Commit 1794995d authored by 廖旭伟's avatar 廖旭伟

证照打印系统

parent 8670be74
Pipeline #2263 failed with stages
-- ----------------------------
-- 行业目录表
-- ----------------------------
DROP TABLE IF EXISTS `mortals_xhx_certificate_industry`;
CREATE TABLE mortals_xhx_certificate_industry(
`id` bigint(20) AUTO_INCREMENT COMMENT '序号,主键,自增长',
`parentId` bigint(20) NOT NULL COMMENT '父级id',
`industryName` varchar(64) NOT NULL COMMENT '行业名称',
`createUserId` bigint(20) NOT NULL COMMENT '创建用户',
`createTime` datetime NOT NULL COMMENT '创建时间',
`updateUserId` bigint(20) COMMENT '更新用户',
`updateTime` datetime COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='行业目录';
-- ----------------------------
-- 证照分类表
-- ----------------------------
DROP TABLE IF EXISTS `mortals_xhx_certificate_classify`;
CREATE TABLE mortals_xhx_certificate_classify(
`id` bigint(20) AUTO_INCREMENT COMMENT '序号,主键,自增长',
`classifyName` varchar(64) NOT NULL COMMENT '分类名称',
`sort` int(4) COMMENT '排序号',
`total` int(8) COMMENT '打印次数',
`showFront` tinyint(2) COMMENT '是否首页展示0:否1是',
`classifyType` tinyint(2) COMMENT '证照类型,1:普通,2:正副本',
`createUserId` bigint(20) NOT NULL COMMENT '创建用户',
`createTime` datetime NOT NULL COMMENT '创建时间',
`updateUserId` bigint(20) COMMENT '更新用户',
`updateTime` datetime COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='证照分类';
-- ----------------------------
-- 证照目录表
-- ----------------------------
DROP TABLE IF EXISTS `mortals_xhx_certificate_catalog`;
CREATE TABLE mortals_xhx_certificate_catalog(
`id` bigint(20) AUTO_INCREMENT COMMENT '序号,主键,自增长',
`catalogName` varchar(64) NOT NULL COMMENT '目录名称',
`catalogCode` varchar(64) NOT NULL COMMENT '目录编号',
`holderType` tinyint(2) NOT NULL COMMENT '持有者类型,1:自然人;2:法人;3:自然人,法人',
`industryId` bigint(20) NOT NULL COMMENT '所属行业',
`classifyId` bigint(20) NOT NULL COMMENT '所属分类',
`transverse` int(8) NOT NULL COMMENT '横向尺寸(单位mm)',
`portrait` int(8) NOT NULL COMMENT '纵向尺寸(单位mm)',
`inspect` tinyint(2) NOT NULL COMMENT '是否需要年检,0:否1:是',
`oriFileName` varchar(64) COMMENT '证照模板正本文件名称',
`originalUrl` varchar(128) COMMENT '证照模板正本文件地址',
`oriFormContent` text COMMENT '证照模板正本表单内容',
`dupFileName` varchar(64) COMMENT '证照模板副本文件名称',
`duplicateUrl` varchar(128) COMMENT '证照模板副本文件地址',
`dupFormContent` text COMMENT '证照模板副本表单内容',
`exampleUrl` varchar(128) COMMENT '证照示例图地址',
`status` tinyint(2) COMMENT '证照状态,0:禁用1:启用',
`createUserId` bigint(20) NOT NULL COMMENT '创建用户',
`createTime` datetime NOT NULL COMMENT '创建时间',
`updateUserId` bigint(20) COMMENT '更新用户',
`updateTime` datetime COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='证照目录';
-- ----------------------------
-- 证照柜设备表
-- ----------------------------
DROP TABLE IF EXISTS `mortals_xhx_device`;
CREATE TABLE mortals_xhx_device(
`id` bigint(20) AUTO_INCREMENT COMMENT '序号,主键,自增长',
`deviceName` varchar(64) NOT NULL COMMENT '设备名称',
`deviceCode` varchar(128) COMMENT '设备编码',
`deviceType` tinyint(2) COMMENT '设备类型1证照柜',
`deviceMac` varchar(64) COMMENT 'Mac地址',
`deviceFirmname` varchar(20) COMMENT '设备厂商',
`ip` varchar(64) COMMENT '设备IP地址',
`port` varchar(64) COMMENT '端口号',
`resolution` varchar(64) COMMENT '设备分辨率',
`leadingOfficial` varchar(64) COMMENT '负责人',
`telephone` varchar(64) COMMENT '负责人电话',
`longitude` varchar(64) COMMENT '设备经度',
`latitude` varchar(64) COMMENT '设备纬度',
`building` tinyint(2) COMMENT '所在楼宇',
`floor` tinyint(2) COMMENT '所在楼层',
`managePWD` varchar(64) COMMENT '管理员密码',
`remark` varchar(128) COMMENT '备注',
`status` tinyint(2) COMMENT '设备状态,0:未激活,1:离线:2:在线',
`enabled` tinyint(2) COMMENT '启停状态,0:停用,1:启用',
`createUserId` bigint(20) NOT NULL COMMENT '创建用户',
`createTime` datetime NOT NULL COMMENT '创建时间',
`updateUserId` bigint(20) COMMENT '更新用户',
`updateTime` datetime COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='证照柜设备';
-- ----------------------------
-- 证照申请表
-- ----------------------------
DROP TABLE IF EXISTS `mortals_xhx_apply_log`;
CREATE TABLE mortals_xhx_apply_log(
`id` bigint(20) AUTO_INCREMENT COMMENT '序号,主键,自增长',
`certificateCode` varchar(128) COMMENT '证件编号',
`certificateName` varchar(128) COMMENT '证件名称',
`issueTime` datetime COMMENT '颁发时间',
`pickerName` varchar(128) COMMENT '取件人姓名',
`pickerIDCardNo` varchar(64) COMMENT '取件人证件号码',
`holderType` tinyint(2) NOT NULL COMMENT '持有者类型,1:自然人,2:法人,3:自然人法人',
`holderIdType` tinyint(2) NOT NULL COMMENT '持有者证件类型,1:身份证,2:组织机构代码等',
`holderName` varchar(64) NOT NULL COMMENT '持有者名称',
`holderIDCardNo` varchar(64) COMMENT '持有者证件号码',
`enterpriseNam` varchar(128) NOT NULL COMMENT '企业名称',
`validityStart` datetime COMMENT '有效期起始',
`validityEnd` datetime COMMENT '有效期截止',
`privateID` varchar(128) COMMENT '专网ID',
`originalUrl` varchar(128) COMMENT '正本附件地址',
`oriFormContent` text NOT NULL COMMENT '证照模板正本表单内容',
`duplicateUrl` varchar(128) COMMENT '副本附件地址',
`dupFormContent` text NOT NULL COMMENT '证照模板副本表单内容',
`createUserId` bigint(20) NOT NULL COMMENT '创建用户',
`createTime` datetime NOT NULL COMMENT '创建时间',
`updateUserId` bigint(20) COMMENT '更新用户',
`updateTime` datetime COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='证照申请';
-- ----------------------------
-- 证照持有表
-- ----------------------------
DROP TABLE IF EXISTS `mortals_xhx_retain_log`;
CREATE TABLE mortals_xhx_retain_log(
`id` bigint(20) AUTO_INCREMENT COMMENT '序号,主键,自增长',
`catalogCode` varchar(64) NOT NULL COMMENT '证照目录编号',
`certificateName` varchar(64) NOT NULL COMMENT '证照名称',
`certificateCode` varchar(64) NOT NULL COMMENT '证照编号',
`enterpriseNam` varchar(128) NOT NULL COMMENT '企业名称',
`holderName` varchar(64) NOT NULL COMMENT '持有者姓名',
`holderIDCardNo` varchar(64) COMMENT '持有者证件号码',
`certificateStatus` tinyint(2) NOT NULL COMMENT '证照状态,1正常2注销',
`originalCount` int(4) NOT NULL COMMENT '正本数',
`duplicateCount` int(4) NOT NULL COMMENT '副本数',
`originalUrl` varchar(128) COMMENT '正本附件地址',
`duplicateUrl` varchar(128) COMMENT '副本附件地址',
`createUserId` bigint(20) NOT NULL COMMENT '创建用户',
`createTime` datetime NOT NULL COMMENT '创建时间',
`updateUserId` bigint(20) COMMENT '更新用户',
`updateTime` datetime COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='证照持有';
-- ----------------------------
-- 证照打印记录表
-- ----------------------------
DROP TABLE IF EXISTS `mortals_xhx_print_log`;
CREATE TABLE mortals_xhx_print_log(
`id` bigint(20) AUTO_INCREMENT COMMENT '序号,主键,自增长',
`catalogCode` varchar(64) NOT NULL COMMENT '证照目录编号',
`certificateName` varchar(64) NOT NULL COMMENT '证照名称',
`certificateCode` varchar(64) NOT NULL COMMENT '证照编号',
`enterpriseNam` varchar(128) NOT NULL COMMENT '企业名称',
`holderName` varchar(64) NOT NULL COMMENT '持有者姓名',
`holderIDCardNo` varchar(64) COMMENT '持有者证件号码',
`pickerName` varchar(128) COMMENT '取件人姓名',
`pickerIDCardNo` varchar(64) COMMENT '取件人证件号码',
`originalCount` int(4) NOT NULL COMMENT '正本数',
`duplicateCount` int(4) NOT NULL COMMENT '副本数',
`printStatus` tinyint(2) NOT NULL COMMENT '打印状态1打印成功2失败',
`printDate` datetime NOT NULL COMMENT '打印时间',
`deviceId` bigint(20) COMMENT '打印设备',
`createUserId` bigint(20) NOT NULL COMMENT '创建用户',
`createTime` datetime NOT NULL COMMENT '创建时间',
`updateUserId` bigint(20) COMMENT '更新用户',
`updateTime` datetime COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='证照打印记录';
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mortals.xhx</groupId>
<artifactId>certificate-system</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>certificate-manager</artifactId>
<packaging>jar</packaging>
<description>证照打印系统</description>
<properties>
</properties>
<profiles>
<profile>
<id>develop</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<profiles.active>develop</profiles.active>
<profiles.server.port>17215</profiles.server.port>
<profiles.queue.type>rabbitmq</profiles.queue.type>
<profiles.kafka.brokers>192.168.0.251:9092</profiles.kafka.brokers>
<profiles.rabbitmq.host>192.168.0.98</profiles.rabbitmq.host>
<profiles.rabbitmq.port>5672</profiles.rabbitmq.port>
<profiles.nacos.server-addr>192.168.0.252:8848</profiles.nacos.server-addr>
<profiles.nacos.group>DEFAULT_GROUP</profiles.nacos.group>
<profiles.nacos.namespace>smart-gov</profiles.nacos.namespace>
<profiles.log.path>/mortals/app/logs</profiles.log.path>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<profiles.active>test</profiles.active>
<profiles.server.port>17001</profiles.server.port>
<profiles.queue.type>rabbitmq</profiles.queue.type>
<profiles.kafka.brokers>192.168.0.251:9092</profiles.kafka.brokers>
<profiles.rabbitmq.host>192.168.0.98</profiles.rabbitmq.host>
<profiles.rabbitmq.port>5672</profiles.rabbitmq.port>
<profiles.nacos.server-addr>192.168.0.252:8848</profiles.nacos.server-addr>
<profiles.nacos.group>DEFAULT_GROUP</profiles.nacos.group>
<profiles.nacos.namespace>smart-gov</profiles.nacos.namespace>
<profiles.log.path>/mortals/app/logs</profiles.log.path>
</properties>
</profile>
<profile>
<id>product</id>
<properties>
<profiles.active>product</profiles.active>
<profiles.server.port>19211</profiles.server.port>
<profiles.queue.type>rabbitmq</profiles.queue.type>
<profiles.kafka.brokers>192.168.0.100:9092</profiles.kafka.brokers>
<profiles.rabbitmq.host>192.168.0.100</profiles.rabbitmq.host>
<profiles.rabbitmq.port>5672</profiles.rabbitmq.port>
<profiles.nacos.server-addr>192.168.0.100:8848</profiles.nacos.server-addr>
<profiles.nacos.group>DEFAULT_GROUP</profiles.nacos.group>
<profiles.nacos.namespace>smart-gov</profiles.nacos.namespace>
<profiles.log.path>/mortals/app/logs</profiles.log.path>
</properties>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>com.mortals.xhx</groupId>
<artifactId>common-lib</artifactId>
<exclusions>
<exclusion>
<artifactId>poi-ooxml-schemas</artifactId>
<groupId>org.apache.poi</groupId>
</exclusion>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
<!--Token生成与解析-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-mock</artifactId>
<version>2.0.8</version>
</dependency>
<dependency>
<groupId>com.aspose.words</groupId>
<artifactId>aspose-words</artifactId>
<version>19.2</version>
<classifier>jdk16</classifier>
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.14</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<skipTests>true</skipTests> <!--默认关掉单元测试 -->
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
<outputDirectory>${project.basedir}/dist/${project.artifactId}/boot</outputDirectory>
<layout>ZIP</layout>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-bin</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<encoding>UTF-8</encoding>
<outputDirectory>${project.basedir}/dist/${project.artifactId}/bin</outputDirectory>
<resources>
<resource>
<directory>src/main/bin/</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
if not exist "%JAVA_HOME%\bin\jps.exe" echo Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better! & EXIT /B 1
setlocal
set "PATH=%JAVA_HOME%\bin;%PATH%"
echo killing server
for /f "tokens=1" %%i in ('jps -m ^| find "@project.artifactId@"') do ( taskkill /F /PID %%i )
echo Done!
#! /bin/sh
PORT="@profiles.server.port@"
BASEDIR=`dirname $0`
BASEDIR=`(cd "$BASEDIR"; pwd)`
PROJECT_NAME="@project.artifactId@"
MAIN_CLASS="$PROJECT_NAME";
if [ ! -n "$PORT" ]; then
echo $"Usage: $0 {port}"
exit $FAIL
fi
pid=`ps ax | grep -i "$MAIN_CLASS" | grep java | grep -v grep | awk '{print $1}'`
if [ -z "$pid" ] ; then
echo "No Server running."
exit -1;
fi
echo "stoping application $PROJECT_NAME......"
kill -9 ${pid}
echo "Send shutdown request to Server $PROJECT_NAME OK"
echo off
if not exist "%JAVA_HOME%\bin\java.exe" echo Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better! & EXIT /B 1
set "JAVA=%JAVA_HOME%\bin\java.exe"
set BASEDIR=%~dp0
set BASEDIR="%BASEDIR:~0,-5%"
set PROJECT_NAME=@project.artifactId@
set APP_NAME=%PROJECT_NAME%-@project.version@.jar
set LOG_PATH="%BASEDIR%@profiles.log.path@/%PROJECT_NAME%"
if not exist "%LOG_PATH%" md "%LOG_PATH%"
set GC_PATH=%LOG_PATH%/gc.log
set HS_ERR_PATH=%LOG_PATH%PORT%-hs_err.log
set HEAP_DUMP_PATH=%LOG_PATH%/heap_dump.hprof
set TEMP_PATH=%LOG_PATH%/temp/
if not exist "%TEMP_PATH%" md "%TEMP_PATH%"
rem jvm启动参数
set JAVA_OPTS=-Xms512M -Xmx512M -Xss256K -XX:+UseAdaptiveSizePolicy -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:GCTimeRatio=39 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+HeapDumpOnOutOfMemoryError
set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCDateStamps -Xloggc:%GC_PATH%
set JAVA_OPTS=%JAVA_OPTS% -XX:ErrorFile=%HS_ERR_PATH%
set JAVA_OPTS=%JAVA_OPTS% -XX:HeapDumpPath=%HEAP_DUMP_PATH%
rem jvm config
set JVM_CONFIG=%JVM_CONFIG% -Dapp.name=%PROJECT_NAME%
set JVM_CONFIG=%JVM_CONFIG% -Dapp.port=%PORT%
set JVM_CONFIG=%JVM_CONFIG% -Djava.io.tmpdir=%TEMP_PATH%
set JVM_CONFIG=%JVM_CONFIG% -Dbasedir=%BASEDIR%
set DEBUG_OPTS=
if ""%1"" == ""debug"" (
set DEBUG_OPTS= -Xloggc:../logs/gc.log -verbose:gc -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=../logs
goto debug
)
set JMX_OPTS=
if ""%1"" == ""jmx"" (
set JMX_OPTS= -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9888 -Dcom.sun.management.jmxremote.ssl=FALSE -Dcom.sun.management.jmxremote.authenticate=FALSE
goto jmx
)
set "LOG_OPTS=--logging.config=%BASEDIR%/conf/logback-spring.xml"
echo "Starting the %APP_NAME%"
"%JAVA%" %JAVA_OPTS% -server %JVM_CONFIG% -jar %BASEDIR%/boot/%APP_NAME%
echo ""%JAVA%" %JAVA_OPTS% -server %JVM_CONFIG% -jar %BASEDIR%/boot/%APP_NAME% "
goto end
:debug
echo "debug"
"%JAVA%" -Xms512m -Xmx512m -server %DEBUG_OPTS% %JVM_CONFIG% -jar ../boot/%APP_NAME%
goto end
:jmx
"%JAVA%" -Xms512m -Xmx512m -server %JMX_OPTS% %JVM_CONFIG% -jar ../boot/%APP_NAME%
goto end
:end
pause
#!/bin/sh
PORT="@profiles.server.port@"
BASEDIR=`dirname $0`/..
BASEDIR=`(cd "$BASEDIR"; pwd)`
PROJECT_NAME="@project.artifactId@";
MAIN_CLASS="$PROJECT_NAME-@project.version@.jar";
LOG_PATH="@profiles.log.path@/$PROJECT_NAME"
GC_PATH=$LOG_PATH/$PORT"-gc.log"
HS_ERR_PATH=$LOG_PATH/$PORT"-hs_err.log"
HEAP_DUMP_PATH=$LOG_PATH/$PORT"-heap_dump.hprof"
TEMP_PATH=$LOG_PATH/temp/
SUCCESS=0
FAIL=9
if [ ! -n "$PORT" ]; then
echo $"Usage: $0 {port}"
exit $FAIL
fi
if [ ! -d $LOG_PATH ];
then
mkdir -p $LOG_PATH;
fi
if [ ! -d $TEMP_PATH ];
then
mkdir -p $TEMP_PATH;
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD=`which java > /dev/null 2>&1`
echo "Error: JAVA_HOME is not defined correctly."
exit $ERR_NO_JAVA
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "We cannot execute $JAVACMD"
exit $ERR_NO_JAVA
fi
if [ -e "$BASEDIR" ]
then
JAVA_OPTS="-Xms512M -Xmx1024M -Xss256K -XX:+UseAdaptiveSizePolicy -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:GCTimeRatio=39 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:$GC_PATH -XX:+HeapDumpOnOutOfMemoryError -XX:ErrorFile=$HS_ERR_PATH -XX:HeapDumpPath=$HEAP_DUMP_PATH"
fi
CLASSPATH=$CLASSPATH_PREFIX:
EXTRA_JVM_ARGUMENTS=""
cd "$BASEDIR/boot";
echo "starting application $PROJECT_NAME......"
exec "$JAVACMD" $JAVA_OPTS \
$EXTRA_JVM_ARGUMENTS \
-Dapp.name="$PROJECT_NAME" \
-Dapp.port="$PORT" \
-Dbasedir="$BASEDIR" \
-Djava.io.tmpdir=$TEMP_PATH \
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=15505 \
-jar $MAIN_CLASS \
> /dev/null &
for i in {1..60}
do
jcpid=`ps -ef | grep -v "grep" | grep "$MAIN_CLASS" | grep "app.port=$PORT" | sed -n '1P' | awk '{print $2}'`
if [ $jcpid ]; then
echo "The $PROJECT_NAME start finished, PID is $jcpid"
exit $SUCCESS
else
echo "starting the application .. $i"
sleep 1
fi
done
echo "$PROJECT_NAME start failure!"
package com.mortals.xhx;
import com.mortals.framework.springcloud.boot.BaseWebApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ImportResource;
@EnableFeignClients
@SpringBootApplication(scanBasePackages = {"com.mortals"})
@ServletComponentScan("com.mortals")
@ImportResource(locations = {"classpath:config/spring-config.xml"})
public class CertificateManagerApplication extends BaseWebApplication {
public static void main(String[] args) {
SpringApplication.run(CertificateManagerApplication.class, args);
}
}
package com.mortals.xhx.base.framework.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Operlog {
String msg() default "";
String params() default "";
}
package com.mortals.xhx.base.framework.aspect;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.mortals.framework.service.ILogService;
import com.mortals.framework.service.impl.FileLogServiceImpl;
import com.mortals.xhx.base.system.oper.service.OperLogService;
/**
* 操作日志记录
*/
@Component
public class OperlogAspect extends FileLogServiceImpl implements ILogService {
private final static Logger logger = LoggerFactory.getLogger(OperlogAspect.class);
@Autowired
private OperLogService operLogService;
@Override
public void doHandlerLog(String platformMark, Long userId, String userName, String loginName, String requestUrl,
String content, String ip, Date logDate) {
super.doHandlerLog(platformMark, userId, userName, loginName, requestUrl, content, ip, logDate);
operLogService.insertOperLog(ip, requestUrl, userId, userName, loginName, content);
}
@Override
public void doHandlerLog(String platformMark, String loginName, String requestUrl, String content, String ip) {
// operLogService.insertOperLog(ip, requestUrl, null, "", loginName,
// content);
this.doHandlerLog(platformMark, null, "", loginName, requestUrl, content, ip, new Date());
}
@Pointcut("execution(public * com.mortals.xhx..*Controller.*(..))")
public void accessLog() {
}
@Before("accessLog()")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// url
logger.info("ip[{}]url[{}]", request.getRemoteAddr(), request.getRequestURL());
// 参数第1和第2个参数为HttpServletRequest request, HttpServletResponse
// response
if (joinPoint.getArgs().length > 2) {
logger.info("args={}", joinPoint.getArgs()[2]);
} else {
logger.info("args={}", joinPoint.getArgs());
}
}
@AfterReturning(returning = "object", pointcut = "accessLog()")
public void doAfterReturning(Object object) {
if (null != object) {
logger.info("response={}", object.toString());
}
}
}
package com.mortals.xhx.base.framework.aspect;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.ContentCachingRequestWrapper;
import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* 打印每个请求的入参、出参等信息
*
* @author: zxfei
* @date: 2022/4/20 9:24
*/
@Aspect
@Component
@Slf4j
@Order(1)
@Profile({"default", "develop", "test"})
public class WebLogAspect {
@Pointcut("execution(public * com.mortals..*Controller.*(..))")
public void webLog() {
}
@Pointcut("execution(public * com.mortals.xhx.base.framework.exception.ExceptionHandle.*(..))")
public void exceptions() {
}
/**
* 只在进入controller时记录请求信息
*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// log.debug("请求路径 {} ,进入方法 {}", request.getRequestURI(), joinPoint.getSignature().getDeclaringTypeName() + ":" + joinPoint.getSignature().getName());
MDC.put("req", getRequestInfo(request).toJSONString());
MDC.put("startTime", String.valueOf(System.currentTimeMillis()));
}
/**
* 打印请求日志
*/
@AfterReturning(pointcut = "webLog()|| exceptions()", returning = "result")
public void afterReturning(Object result) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Map<String, String> map = MDC.getCopyOfContextMap();
if (map != null&&result!=null) {
String startTime = map.getOrDefault("startTime", String.valueOf(System.currentTimeMillis()));
long takeTime = (System.currentTimeMillis() - Long.parseLong(startTime));
log.info(" \n 请求路径:{} \n 耗时:{}ms \n 请求报文:{} \n 响应报文:{}"
, request.getRequestURI(), takeTime, map.getOrDefault("req", ""), result == null ? "" : result.toString());
}
}
/**
* 读取请求信息,如果是表单则转换为json
*/
private JSONObject getRequestInfo(HttpServletRequest req) {
JSONObject requestInfo = new JSONObject();
try {
StringBuffer requestURL = req.getRequestURL();
requestInfo.put("requestURL", requestURL);
String method = req.getMethod();
requestInfo.put("method", method);
if (req.getQueryString() != null) {
requestInfo.put("queryString", URLDecoder.decode(req.getQueryString(), "UTF-8"));
}
String remoteAddr = req.getRemoteAddr();
requestInfo.put("remoteAddr", remoteAddr);
if (req instanceof ContentCachingRequestWrapper) {
ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) req;
String bodyStr = new String(wrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
if (bodyStr.startsWith("{")) {
JSONObject jsonObject = JSON.parseObject(bodyStr);
requestInfo.put("requestBody", jsonObject);
}
}
} catch (Exception e) {
log.error("解析请求失败", e);
requestInfo.put("parseError", e.getMessage());
}
return requestInfo;
}
}
package com.mortals.xhx.base.framework.config;
import com.mortals.framework.springcloud.config.web.BaseWebMvcConfigurer;
import com.mortals.xhx.base.framework.feign.HierarchicalContract;
import feign.Contract;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author: zxfei
* @date: 2021/8/13 0:24
* @description:
**/
@Configuration
public class AccountConfig {
@Bean
public Contract feignContract() {
return new HierarchicalContract();
}
@Bean
public BaseWebMvcConfigurer getBaseWebMvc(){
return new BaseWebMvcConfigurer(false,null);
}
}
package com.mortals.xhx.base.framework.config;
import com.mortals.framework.web.interceptor.BaseInterceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author: zxfei
* @date: 2022/6/6 15:05
* @description:添加跨域响应
**/
@Component
public class CrossInterceptor extends BaseInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
super.afterCompletion(request, response, handler, ex);
}
}
package com.mortals.xhx.base.framework.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
/**
* @author: zxfei
* @date: 2021/10/11 15:20
* @description:
**/
@Configuration
public class FreemarkerApplicationConfig {
@Bean(name = "freeMarkerConfigurer")
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setDefaultEncoding("UTF-8");
configurer.setTemplateLoaderPath("classpath:/template");
return configurer;
}
}
package com.mortals.xhx.base.framework.config;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.PostConstruct;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import com.mortals.framework.util.StringUtils;
@Configuration
public class InterceptorConfig {
/**
* cookie的密钥
*/
@Value("${cookie.key}")
private String securityKey;
/**
* 不需要登录的URL地址,多个用逗号分隔
*/
@Value("${application.auth.unloginUrl}")
private String uncheckLoginUrl;
/**
* 不需要鉴权的URL地址,多个用逗号分隔
*/
@Value("${application.auth.uncheckUrl}")
private String uncheckAuthUrl;
private Set<String> uncheckLoginUrls = new HashSet<>();
private Set<String> uncheckAuthUrls = new HashSet<>();
/**
* 有后缀占位符的不检验地址,如/spi/user/*
*/
private Set<String> uncheckAuthUrlsSuffix = new HashSet<>();
public String getSecurityKey() {
return securityKey;
}
public Set<String> getUncheckLoginUrls() {
return uncheckLoginUrls;
}
public Set<String> getUncheckAuthUrls() {
return uncheckAuthUrls;
}
/**
* 校验地址是否需要权限
*
* @param url
* @return true:需要,false:不需要
*/
public boolean needCheckAuth(String url) {
if (uncheckAuthUrls.contains(url)) {
return false;
}
for (String regexUrl : uncheckAuthUrlsSuffix) {// 支持*结尾
if (url.startsWith(regexUrl)) {
return false;
}
}
return true;
}
@PostConstruct
public void convert() {
uncheckLoginUrls.clear();
uncheckLoginUrls.addAll(StringUtils.converStr2Set(uncheckLoginUrl));
uncheckAuthUrls.clear();
uncheckAuthUrls.addAll(StringUtils.converStr2Set(uncheckAuthUrl));
uncheckAuthUrlsSuffix.clear();
for (String url : uncheckAuthUrls) {
int index = url.indexOf("*");// 支持*结尾
if (index != -1) {
uncheckAuthUrlsSuffix.add(url.substring(0, index));
}
}
}
}
package com.mortals.xhx.base.framework.config;
import java.io.IOException;
import java.net.URLDecoder;
import javax.sql.DataSource;
import com.mortals.framework.springcloud.config.mybatis.AbstractMybatisConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import com.mortals.framework.springcloud.config.SpringBootVFS;
@Configuration
//@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisConfiguration extends AbstractMybatisConfiguration {
private static Log logger = LogFactory.getLog(MybatisConfiguration.class);
// 配置类型别名
@Value("${spring.application.name}")
private String name;
// 配置类型别名
@Value("${mybatis.root-path}")
private String rootPath;
// 配置类型别名
@Value("${mybatis.type-aliases-package}")
private String typeAliasesPackage;
// 配置mapper的扫描,找到所有的mapper.xml映射文件
@Value("${mybatis.mapper-locations}")
private String mapperLocations;
// 加载全局的配置文件
@Value("${mybatis.config-location}")
private String configLocation;
// 提供SqlSeesion
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactoryBean(@Qualifier("dataSource") DataSource dataSource) {
return super.getSqlSessionFactoryBean(dataSource);
}
@Override
public String getTypeAliasesRootPackage() {
return rootPath;
}
@Override
public String getSqlMappers() {
return mapperLocations;
}
@Override
public String getMybatisConfig() {
return configLocation;
}
@Override
public String getTypeAliasesPackage() {
logger.info("typeAliasesPackage:"+typeAliasesPackage);
return typeAliasesPackage;
}
}
\ No newline at end of file
package com.mortals.xhx.base.framework.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.exception.AppException;
/**
* 统一异常处理
*/
@ControllerAdvice
public class ExceptionHandle {
private final static Logger log = LoggerFactory.getLogger(ExceptionHandle.class);
public static final String KEY_RESULT_CODE = "code";
public static final String KEY_RESULT_MSG = "msg";
public static final String KEY_RESULT_DATA = "data";
public static final int VALUE_RESULT_FAILURE = -1;
@ExceptionHandler(value = Exception.class)
@ResponseBody
public String handle(Exception e) {
JSONObject ret = new JSONObject();
ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
if (e instanceof AppException) {
StackTraceElement stack = e.getStackTrace()[0];
log.error("[business error]=========stack message[{}],[{},method:{},line{}][{}]", e.getMessage(),
stack.getClassName(), stack.getMethodName(), stack.getLineNumber(), e.getClass().getName());
AppException ex = (AppException) e;
ret.put(KEY_RESULT_MSG, ex.getMessage());
} else {
log.error("[system error]", e);
ret.put(KEY_RESULT_MSG, "unknown exception!");
}
return ret.toJSONString();
}
}
package com.mortals.xhx.base.framework.feign;
import feign.MethodMetadata;
import feign.Util;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import static org.springframework.core.annotation.AnnotationUtils.synthesizeAnnotation;
/**
* 解决feign不能多继承
* @author: zxfei
* @date: 2021/8/13 0:20
* @description:
**/
public class HierarchicalContract extends SpringMvcContract {
private ResourceLoader resourceLoader;
@Override
public List<MethodMetadata> parseAndValidateMetadata(final Class<?> targetType) {
Util.checkState(targetType.getTypeParameters().length == 0,
"Parameterized types unsupported: %s",
targetType.getSimpleName());
final Map<String, MethodMetadata> result = new LinkedHashMap<>();
for (final Method method : targetType.getMethods()) {
if (method.getDeclaringClass() == Object.class || (method.getModifiers() & Modifier.STATIC) != 0
|| Util.isDefault(method)) {
continue;
}
final MethodMetadata metadata = this.parseAndValidateMetadata(targetType, method);
Util.checkState(!result.containsKey(metadata.configKey()), "Overrides unsupported: %s", metadata.configKey());
result.put(metadata.configKey(), metadata);
}
return new ArrayList<>(result.values());
}
@Override
public MethodMetadata parseAndValidateMetadata(final Class<?> targetType, final Method method) {
final MethodMetadata methodMetadata = super.parseAndValidateMetadata(targetType, method);
final LinkedList<Class<?>> classHierarchy = new LinkedList<>();
classHierarchy.add(targetType);
this.findClass(targetType, method.getDeclaringClass(), classHierarchy);
classHierarchy.stream()
.map(this::processPathValue)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.ifPresent((path) -> methodMetadata.template().insert(0, path));
return methodMetadata;
}
private Optional<String> processPathValue(final Class<?> clz) {
Optional<String> result = Optional.empty();
final RequestMapping classAnnotation = clz.getAnnotation(RequestMapping.class);
if (classAnnotation != null) {
final RequestMapping synthesizeAnnotation = synthesizeAnnotation(classAnnotation, clz);
// Prepend path from class annotation if specified
if (synthesizeAnnotation.value().length > 0) {
String pathValue = Util.emptyToNull(synthesizeAnnotation.value()[0]);
pathValue = this.resolveValue(pathValue);
if (!pathValue.startsWith("/")) {
pathValue = "/" + pathValue;
}
result = Optional.of(pathValue);
}
}
return result;
}
private String resolveValue(final String value) {
if (StringUtils.hasText(value) && this.resourceLoader instanceof ConfigurableApplicationContext) {
return ((ConfigurableApplicationContext) this.resourceLoader).getEnvironment().resolvePlaceholders(value);
}
return value;
}
@Override
protected void processAnnotationOnClass(final MethodMetadata data, final Class<?> clz) {
// skip this step
}
private boolean findClass(final Class<?> currentClass, final Class<?> searchClass,
final LinkedList<Class<?>> classHierarchy) {
if (currentClass == searchClass) {
return true;
}
final Class<?>[] interfaces = currentClass.getInterfaces();
for (final Class<?> currentInterface : interfaces) {
classHierarchy.add(currentInterface);
final boolean findClass = this.findClass(currentInterface, searchClass, classHierarchy);
if (findClass) {
return true;
}
classHierarchy.removeLast();
}
return false;
}
@Override
public void setResourceLoader(final ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
super.setResourceLoader(resourceLoader);
}
}
package com.mortals.xhx.base.framework.filter;
import cn.hutool.core.util.IdUtil;
import com.mortals.framework.service.IAuthTokenService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
*
* 请求过滤链
* @author: zxfei
* @date: 2022/4/20 14:52
*/
@Component
@Slf4j
public class RequestFilter extends OncePerRequestFilter implements Filter {
@Autowired
private IAuthTokenService authTokenService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
//每个请求记录一个traceId,可以根据traceId搜索出本次请求的全部相关日志
MDC.put("traceId", IdUtil.fastSimpleUUID().substring(0,12));
setUsername(request);
request = new ContentCachingRequestWrapper(request);
filterChain.doFilter(request, response);
} catch (Exception e) {
throw e;
} finally {
//清理ThreadLocal
MDC.clear();
}
}
private void setUsername(HttpServletRequest request) {
//通过token解析出username
String token = authTokenService.getToken(request);
//String token = request.getHeader("token");
if (!ObjectUtils.isEmpty(token)) {
MDC.put("token",token);
// MDC.put("token", token);
// try {
// SessionUserInfo info = tokenService.getUserInfo();
// if (info != null) {
// String username = info.getUsername();
// MDC.put("username", username);
// }
// } catch (CommonJsonException e) {
// log.info("无效的token:{}", token);
// }
}
}
}
package com.mortals.xhx.base.framework.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.annotation.UnAuth;
import com.mortals.framework.service.IAuthTokenService;
import com.mortals.framework.service.IUser;
import com.mortals.framework.util.AESUtil;
import com.mortals.framework.utils.ServletUtils;
import com.mortals.framework.web.interceptor.BaseInterceptor;
import com.mortals.xhx.base.framework.config.InterceptorConfig;
import com.mortals.xhx.common.key.Constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* 用户权限验证,基于token
*
* @author: zxfei
* @date: 2022/4/24 11:04
*/
@Component
public class AuthUserInterceptor extends BaseInterceptor {
@Autowired
private InterceptorConfig config;
@Autowired
private IAuthTokenService authTokenService;
@Override
public int getOrder() {
return Integer.MAX_VALUE - 9;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
UnAuth annotation = method.getAnnotation(UnAuth.class);
if (annotation != null) {
//取消校验
return true;
}
} else if (handler instanceof ResourceHttpRequestHandler) {
return true;
}
JSONObject ret = new JSONObject();
try {
String uri = request.getServletPath();
//校验配置的请求路径是否需要检查权限
if (config.needCheckAuth(uri)) {
//需要校验权限
boolean auth = this.checkAuth(request, uri, config.getSecurityKey());
if (!auth) {
//不存在时候 如果是管理员也不做拦截
IUser loginUser = authTokenService.getLoginUser(request);
//loginUser.isManager()
if(ObjectUtils.isEmpty(loginUser)){
ret.put("code", 401);
ret.put("msg", "用户未登录或登录失效,请重新登录");
ServletUtils.renderString(response, JSONObject.toJSONString(ret));
return false;
}else if(loginUser.isAdmin()||loginUser.getUserType()==1||loginUser.getUserType()== Constant.CUSTOMER_USER){
return super.preHandle(request, response, handler);
} else {
ret.put("code", -1);
ret.put("msg", "用户无该操作权限!");
ServletUtils.renderString(response, JSONObject.toJSONString(ret));
return false;
}
}
}
} catch (Exception e) {
logger.error("权限校验拦截请求处理异常-->" + e.getMessage());
writeJsonResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "用户权限校验异常");
return false;
}
return super.preHandle(request, response, handler);
}
private boolean checkAuth(HttpServletRequest request, String requestUrl, String securityKey) throws Exception {
int code = requestUrl.hashCode() & (Integer.MAX_VALUE - 1);
IUser loginUser = authTokenService.getLoginUser(request);
if (ObjectUtils.isEmpty(loginUser)) return false;
String menuUrl = loginUser.getMenuUrl();
if (ObjectUtils.isEmpty(menuUrl)) return false;
menuUrl = AESUtil.decrypt(menuUrl, securityKey);
String codes = "," + menuUrl + ",";
String codeKey = "," + code + ",";
if (codes.indexOf(codeKey) != -1) {
return true;
}
return false;
}
}
package com.mortals.xhx.base.framework.security;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.ap.SysConstains;
import com.mortals.framework.service.IAuthTokenService;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.service.IUser;
import com.mortals.framework.util.DateUtils;
import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.base.system.user.model.UserEntity;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* token验证处理
*
* @author zxfei
*/
@Primary
@Service
@Order(1)
@Slf4j
public class AuthTokenServiceImpl implements IAuthTokenService {
// 令牌自定义标识
@Value("${token.header:Authorization}")
private String header;
// 令牌秘钥
@Value("${token.secret:026db82420614469897fcc2dc1b4ce38}")
private String secret;
// 令牌有效期(默认60分钟)
@Value("${token.expireTime:60}")
private int expireTime;
// 令牌前缀
@Value("${token.prefix:}")
private String tokenPrefix;
// redis db
// @Value("${spring.redis.database:}")
// private Integer db;
//
// @Value("${token.database:0}")
// private Integer portalDb;
protected static final Long SECOND = 1l;
protected static final Long SECOND_MINUTE = 60 * SECOND;
protected static final Long SECOND_HOUR = 60 * SECOND_MINUTE;
protected static final Long SECOND_DAY = 24 * SECOND_HOUR;
protected static final Long SECOND_WEEK = 7 * SECOND_DAY;
private static final Long SECOND_MINUTE_TEN = 1 * SECOND_MINUTE;
@Autowired
private ICacheService cacheService;
/**
* 获取信息
*
* @return 用户信息
*/
@Override
public IUser getLoginUser(HttpServletRequest request) {
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token)) {
try {
Claims claims = parseToken(token);
String uuid = (String) claims.get(SysConstains.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
//cacheService.select(portalDb);
String userStr = cacheService.get(userKey);
//cacheService.select(db);
// Rest<String> rest = userFeign.getToken(userKey);
// String userStr = rest.getData();
if (StringUtils.isNotEmpty(userStr)) {
UserEntity userEntity = JSONObject.parseObject(userStr, UserEntity.class);
userEntity.setToken(token);
return userEntity;
}
} catch (Exception e) {
log.error("解析jwt token异常!", e);
return null;
}
}
return null;
}
/**
* 设置用户信息
*/
@Override
public void setUser(IUser user) {
if (StringUtils.isNotNull(user) && StringUtils.isNotEmpty(user.getToken())) {
refreshToken(user);
}
}
/**
* 删除用户身份信息
*/
@Override
public void delUser(String token) {
if (StringUtils.isNotEmpty(token)) {
String userKey = getTokenKey(token);
cacheService.del(userKey);
}
}
/**
* 创建令牌
*
* @param user 用户信息
* @return 令牌
*/
@Override
public String createToken(IUser user) {
// String token = IdUtil.fastSimpleUUID();
// user.setToken(token);
refreshToken(user);
Map<String, Object> claims = new HashMap<>();
claims.put(SysConstains.LOGIN_USER_KEY, user.getToken());
return createToken(claims);
}
/**
* 验证令牌有效期,相差不足20分钟,自动刷新缓存
*
* @param user
* @return 令牌
*/
@Override
public void verifyToken(IUser user) {
long expireTime = user.getExpireTime();
long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= SECOND_MINUTE_TEN) {
log.info("不足十分钟,刷新过期时间");
refreshToken(user);
}
}
/**
* 刷新令牌有效期
*
* @param user 信息
*/
public void refreshToken(IUser user) {
//user.setLoginTime(System.currentTimeMillis());
user.setExpireTime(user.getLoginTime() == null ? System.currentTimeMillis() : user.getLoginTime() + expireTime * SECOND_MINUTE);
// 根据uuid将user缓存
String userKey = getTokenKey(user.getToken());
//设置有效时间 单位秒
cacheService.set(userKey, user, expireTime * SECOND_MINUTE);
}
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map<String, Object> claims) {
String token = Jwts.builder()
.setExpiration(DateUtils.addCurrDate(7))
.setClaims(claims)
.signWith(SignatureAlgorithm.HS256, Base64.getEncoder()
.encodeToString(secret.getBytes())).compact();
return token;
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
@Override
public Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(Base64.getEncoder().encodeToString(secret.getBytes()))
.parseClaimsJws(token)
.getBody();
}
/**
* 从令牌中获取用户
*
* @param token 令牌
* @return 用户名
*/
@Override
public String getUserNumFromToken(String token) {
Claims claims = parseToken(token);
return claims.getSubject();
}
/**
* 获取请求token
*
* @param request
* @return token
*/
@Override
public String getToken(HttpServletRequest request) {
String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(tokenPrefix)) {
token = token.replace(tokenPrefix, "");
}
return token;
}
private String getTokenKey(String uuid) {
return SysConstains.LOGIN_TOKEN_KEY + uuid;
}
}
package com.mortals.xhx.base.framework.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* 安全服务工具类
*
* @author zxfei
*/
public class SecurityUtils {
/**
* 获取Authentication
*/
public static Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
/**
* 生成BCryptPasswordEncoder密码
*
* @param password 密码
* @return 加密字符串
*/
public static String encryptPassword(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password);
}
/**
* 判断密码是否相同
*
* @param rawPassword 真实密码
* @param encodedPassword 加密后字符
* @return 结果
*/
public static boolean matchesPassword(String rawPassword, String encodedPassword) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(rawPassword, encodedPassword);
}
/**
* 是否为管理员
*
* @param userId 用户ID
* @return 结果
*/
public static boolean isAdmin(Long userId) {
return userId != null && 1L == userId;
}
}
package com.mortals.xhx.base.framework.ws;
import com.mortals.xhx.base.framework.ws.websocket.WebSocketHandler;
import com.mortals.xhx.base.framework.ws.websocket.WebSocketShakeInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket // 开启 Spring WebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(this.webSocketHandler(), "/ws") // 配置处理器
.addInterceptors(new WebSocketShakeInterceptor()) // 配置拦截器
.setAllowedOrigins("*"); // 解决跨域问题
}
@Bean
public WebSocketHandler webSocketHandler() {
return new WebSocketHandler();
}
@Bean
public WebSocketShakeInterceptor webSocketShakeInterceptor() {
return new WebSocketShakeInterceptor();
}
}
package com.mortals.xhx.base.framework.ws.handler;
import com.alibaba.fastjson.JSON;
import com.mortals.xhx.base.framework.ws.message.AuthRequest;
import com.mortals.xhx.base.framework.ws.message.AuthResponse;
import com.mortals.xhx.base.framework.ws.message.UserJoinNoticeRequest;
import com.mortals.xhx.base.framework.ws.util.WebSocketUtil;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.WebSocketSession;
@Component
@CommonsLog
public class AuthMessageHandler implements MessageHandler<AuthRequest> {
@Override
public void execute(WebSocketSession session, AuthRequest message) {
log.info("receive message:"+ JSON.toJSONString(message));
// 如果未传递 accessToken
if (StringUtils.isEmpty(message.getAccessToken())) {
WebSocketUtil.send(session, AuthResponse.TYPE,
new AuthResponse().setCode(1).setMessage("认证 accessToken 未传入"));
return;
}
// 添加到 WebSocketUtil 中
WebSocketUtil.addSession(session, message.getAccessToken()); // 考虑到代码简化,我们先直接使用 accessToken 作为 User
// 判断是否认证成功。这里,假装直接成功
WebSocketUtil.send(session, AuthResponse.TYPE, new AuthResponse().setCode(0));
// 通知所有人,某个人加入了。这个是可选逻辑,仅仅是为了演示
// WebSocketUtil.broadcast(UserJoinNoticeRequest.TYPE,
// new UserJoinNoticeRequest().setNickname(message.getAccessToken())); // 考虑到代码简化,我们先直接使用 accessToken 作为 User
//
}
@Override
public String getType() {
return AuthRequest.TYPE;
}
}
package com.mortals.xhx.base.framework.ws.handler;
import com.mortals.xhx.base.framework.ws.message.HeartBeatRequest;
import com.mortals.xhx.base.framework.ws.message.SendResponse;
import com.mortals.xhx.base.framework.ws.message.SendToOneRequest;
import com.mortals.xhx.base.framework.ws.message.SendToUserRequest;
import com.mortals.xhx.base.framework.ws.util.WebSocketUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
@Component
public class HeartBeatHandler implements MessageHandler<HeartBeatRequest> {
@Override
public void execute(WebSocketSession session, HeartBeatRequest message) {
// 这里,假装直接成功
SendResponse sendResponse = new SendResponse().setMsgId(message.getMsgId()).setCode(0);
WebSocketUtil.send(session, SendResponse.TYPE, sendResponse);
}
@Override
public String getType() {
return HeartBeatRequest.TYPE;
}
}
package com.mortals.xhx.base.framework.ws.handler;
import com.mortals.xhx.base.framework.ws.message.Message;
import org.springframework.web.socket.WebSocketSession;
/**
* 消息处理器接口
*/
public interface MessageHandler<T extends Message> {
/**
* 执行处理消息
*
* @param session 会话
* @param message 消息
*/
void execute(WebSocketSession session, T message);
/**
* @return 消息类型,即每个 Message 实现类上的 TYPE 静态字段
*/
String getType();
}
package com.mortals.xhx.base.framework.ws.handler;
import com.mortals.xhx.base.framework.ws.message.SendResponse;
import com.mortals.xhx.base.framework.ws.message.SendToAllRequest;
import com.mortals.xhx.base.framework.ws.message.SendToUserRequest;
import com.mortals.xhx.base.framework.ws.util.WebSocketUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
@Component
public class SendToAllHandler implements MessageHandler<SendToAllRequest> {
@Override
public void execute(WebSocketSession session, SendToAllRequest message) {
// 这里,假装直接成功
SendResponse sendResponse = new SendResponse().setMsgId(message.getMsgId()).setCode(0);
WebSocketUtil.send(session, SendResponse.TYPE, sendResponse);
// 创建转发的消息
SendToUserRequest sendToUserRequest = new SendToUserRequest().setMsgId(message.getMsgId())
.setContent(message.getContent());
// 广播发送
WebSocketUtil.broadcast(SendToUserRequest.TYPE, sendToUserRequest);
}
@Override
public String getType() {
return SendToAllRequest.TYPE;
}
}
package com.mortals.xhx.base.framework.ws.handler;
import com.mortals.xhx.base.framework.ws.message.SendResponse;
import com.mortals.xhx.base.framework.ws.message.SendToOneRequest;
import com.mortals.xhx.base.framework.ws.message.SendToUserRequest;
import com.mortals.xhx.base.framework.ws.util.WebSocketUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
@Component
public class SendToOneHandler implements MessageHandler<SendToOneRequest> {
@Override
public void execute(WebSocketSession session, SendToOneRequest message) {
// 这里,假装直接成功
SendResponse sendResponse = new SendResponse().setMsgId(message.getMsgId()).setCode(0);
WebSocketUtil.send(session, SendResponse.TYPE, sendResponse);
// 创建转发的消息
SendToUserRequest sendToUserRequest = new SendToUserRequest().setMsgId(message.getMsgId())
.setContent(message.getContent());
// 广播发送
WebSocketUtil.send(message.getToUser(), SendToUserRequest.TYPE, sendToUserRequest);
}
@Override
public String getType() {
return SendToOneRequest.TYPE;
}
}
package com.mortals.xhx.base.framework.ws.message;
/**
* 用户认证请求
*/
public class AuthRequest implements Message {
public static final String TYPE = "AUTH_REQUEST";
/**
* 认证 Token
*/
private String accessToken;
public String getAccessToken() {
return accessToken;
}
public AuthRequest setAccessToken(String accessToken) {
this.accessToken = accessToken;
return this;
}
}
package com.mortals.xhx.base.framework.ws.message;
/**
* 用户认证响应
*/
public class AuthResponse implements Message {
public static final String TYPE = "AUTH_RESPONSE";
/**
* 响应状态码
*/
private Integer code;
/**
* 响应提示
*/
private String message;
public Integer getCode() {
return code;
}
public AuthResponse setCode(Integer code) {
this.code = code;
return this;
}
public String getMessage() {
return message;
}
public AuthResponse setMessage(String message) {
this.message = message;
return this;
}
}
package com.mortals.xhx.base.framework.ws.message;
import com.alibaba.fastjson.JSON;
/**
* 心跳 Message
*/
public class HeartBeatRequest implements Message {
public static final String TYPE = "HEART_BEAT_REQUEST";
/**
* 消息编号
*/
private String msgId;
/**
* 内容
*/
private String content;
public String getMsgId() {
return msgId;
}
public HeartBeatRequest setMsgId(String msgId) {
this.msgId = msgId;
return this;
}
public String getContent() {
return content;
}
public HeartBeatRequest setContent(String content) {
this.content = content;
return this;
}
public static void main(String[] args) {
HeartBeatRequest heartBeatRequest = new HeartBeatRequest();
heartBeatRequest.setMsgId("123");
System.out.println(JSON.toJSONString(heartBeatRequest));
}
}
package com.mortals.xhx.base.framework.ws.message;
/**
* 基础消息体
*/
public interface Message {
}
package com.mortals.xhx.base.framework.ws.message;
/**
* 发送消息响应结果的 Message
*/
public class SendResponse implements Message {
public static final String TYPE = "SEND_RESPONSE";
/**
* 消息编号
*/
private String msgId;
/**
* 响应状态码
*/
private Integer code;
/**
* 响应提示
*/
private String message;
public String getMsgId() {
return msgId;
}
public SendResponse setMsgId(String msgId) {
this.msgId = msgId;
return this;
}
public Integer getCode() {
return code;
}
public SendResponse setCode(Integer code) {
this.code = code;
return this;
}
public String getMessage() {
return message;
}
public SendResponse setMessage(String message) {
this.message = message;
return this;
}
}
package com.mortals.xhx.base.framework.ws.message;
/**
* 发送给所有人的群聊消息的 Message
*/
public class SendToAllRequest implements Message {
public static final String TYPE = "SEND_TO_ALL_REQUEST";
/**
* 消息编号
*/
private String msgId;
/**
* 内容
*/
private String content;
public String getContent() {
return content;
}
public SendToAllRequest setContent(String content) {
this.content = content;
return this;
}
public String getMsgId() {
return msgId;
}
public SendToAllRequest setMsgId(String msgId) {
this.msgId = msgId;
return this;
}
}
package com.mortals.xhx.base.framework.ws.message;
/**
* 发送给指定人的私聊消息的 Message
*/
public class SendToOneRequest implements Message {
public static final String TYPE = "SEND_TO_ONE_REQUEST";
/**
* 发送给的用户
*/
private String toUser;
/**
* 消息编号
*/
private String msgId;
/**
* 内容
*/
private String content;
public String getToUser() {
return toUser;
}
public SendToOneRequest setToUser(String toUser) {
this.toUser = toUser;
return this;
}
public String getMsgId() {
return msgId;
}
public SendToOneRequest setMsgId(String msgId) {
this.msgId = msgId;
return this;
}
public String getContent() {
return content;
}
public SendToOneRequest setContent(String content) {
this.content = content;
return this;
}
}
package com.mortals.xhx.base.framework.ws.message;
/**
* 发送消息给一个用户的 Message
*/
public class SendToUserRequest implements Message {
public static final String TYPE = "SEND_TO_USER_REQUEST";
/**
* 消息编号
*/
private String msgId;
/**
* 内容
*/
private String content;
public String getMsgId() {
return msgId;
}
public SendToUserRequest setMsgId(String msgId) {
this.msgId = msgId;
return this;
}
public String getContent() {
return content;
}
public SendToUserRequest setContent(String content) {
this.content = content;
return this;
}
}
package com.mortals.xhx.base.framework.ws.message;
/**
* 用户加入群聊的通知 Message
*/
public class UserJoinNoticeRequest implements Message {
public static final String TYPE = "USER_JOIN_NOTICE_REQUEST";
/**
* 昵称
*/
private String nickname;
public String getNickname() {
return nickname;
}
public UserJoinNoticeRequest setNickname(String nickname) {
this.nickname = nickname;
return this;
}
}
package com.mortals.xhx.base.framework.ws.util;
import com.alibaba.fastjson.JSONObject;
import com.mortals.xhx.base.framework.ws.message.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* WebSocket 工具类,提供客户端连接的管理等功能
*/
public class WebSocketUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketUtil.class);
// ========== 会话相关 ==========
/**
* Session 与用户的映射
*/
private static final Map<WebSocketSession, String> SESSION_USER_MAP = new ConcurrentHashMap<>();
/**
* 用户与 Session 的映射
*/
private static final Map<String, WebSocketSession> USER_SESSION_MAP = new ConcurrentHashMap<>();
/**
* 添加 Session 。在这个方法中,会添加用户和 Session 之间的映射
*
* @param session Session
* @param user 用户
*/
public static void addSession(WebSocketSession session, String user) {
// 更新 USER_SESSION_MAP
USER_SESSION_MAP.put(user, session);
// 更新 SESSION_USER_MAP
SESSION_USER_MAP.put(session, user);
}
/**
* 移除 Session 。
*
* @param session Session
*/
public static void removeSession(WebSocketSession session) {
// 从 SESSION_USER_MAP 中移除
String user = SESSION_USER_MAP.remove(session);
// 从 USER_SESSION_MAP 中移除
if (user != null && user.length() > 0) {
USER_SESSION_MAP.remove(user);
}
}
// ========== 消息相关 ==========
/**
* 广播发送消息给所有在线用户
*
* @param type 消息类型
* @param message 消息体
* @param <T> 消息类型
*/
public static <T extends Message> void broadcast(String type, T message) {
// 创建消息
TextMessage textMessage = buildTextMessage(type, message);
// 遍历 SESSION_USER_MAP ,进行逐个发送
for (WebSocketSession session : SESSION_USER_MAP.keySet()) {
sendTextMessage(session, textMessage);
}
}
/**
* 发送消息给单个用户的 Session
*
* @param session Session
* @param type 消息类型
* @param message 消息体
* @param <T> 消息类型
*/
public static <T extends Message> void send(WebSocketSession session, String type, T message) {
// 创建消息
TextMessage textMessage = buildTextMessage(type, message);
// 遍历给单个 Session ,进行逐个发送
sendTextMessage(session, textMessage);
}
/**
* 发送消息给指定用户
*
* @param user 指定用户
* @param type 消息类型
* @param message 消息体
* @param <T> 消息类型
* @return 发送是否成功你那个
*/
public static <T extends Message> boolean send(String user, String type, T message) {
// 获得用户对应的 Session
WebSocketSession session = USER_SESSION_MAP.get(user);
if (session == null) {
LOGGER.error("[send][user({}) 不存在对应的 session]", user);
return false;
}
// 发送消息
send(session, type, message);
return true;
}
/**
* 构建完整的消息
*
* @param type 消息类型
* @param message 消息体
* @param <T> 消息类型
* @return 消息
*/
private static <T extends Message> TextMessage buildTextMessage(String type, T message) {
JSONObject messageObject = new JSONObject();
messageObject.put("type", type);
messageObject.put("body", message);
return new TextMessage(messageObject.toString());
}
/**
* 真正发送消息
*
* @param session Session
* @param textMessage 消息
*/
private static void sendTextMessage(WebSocketSession session, TextMessage textMessage) {
if (session == null) {
LOGGER.error("[sendTextMessage][session 为 null]");
return;
}
try {
session.sendMessage(textMessage);
} catch (IOException e) {
LOGGER.error("[sendTextMessage][session({}) 发送消息{}) 发生异常",
session, textMessage, e);
}
}
}
package com.mortals.xhx.base.framework.ws.websocket;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import java.util.Map;
/**
* 自定义 HttpSessionHandshakeInterceptor 拦截器
*
* 因为 WebSocketSession 无法获得 ws 地址上的请求参数,所以只好通过该拦截器,获得 accessToken 请求参数,设置到 attributes 中
*/
@CommonsLog
public class WebSocketShakeInterceptor extends HttpSessionHandshakeInterceptor {
@Override // 拦截 Handshake 事件
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
// 获得 accessToken
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request;
attributes.put("accessToken", serverRequest.getServletRequest().getParameter("accessToken"));
}
// 调用父方法,继续执行逻辑
return super.beforeHandshake(request, response, wsHandler, attributes);
}
public static void main(String[] args) {
WebSocketShakeInterceptor webSocketShakeInterceptor = new WebSocketShakeInterceptor();
}
}
package com.mortals.xhx.base.login.interceptor;
import com.mortals.xhx.base.framework.config.InterceptorConfig;
import com.mortals.framework.ap.CookieService;
import com.mortals.framework.ap.SysConstains;
import com.mortals.framework.model.CookieInfo;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.util.AESUtil;
import com.mortals.framework.util.HttpUtil;
import com.mortals.framework.util.StringUtils;
import com.mortals.framework.web.interceptor.BaseInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//@Order(1)
//@Component
public class AuthJsonInterceptor extends BaseInterceptor {
@Autowired
private InterceptorConfig config;
@Autowired
private ICacheService cacheService;
@Override
public int getOrder() {
return Integer.MAX_VALUE - 9;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
try {
String uri = request.getServletPath();
if (config.needCheckAuth(uri)) {
boolean auth = this.checkAuth(request, uri, config.getSecurityKey());
if (!auth) {
CookieInfo cookie = CookieService.getLoginCookie(request, config.getSecurityKey());
if (cookie == null || cookie.getUser() == null) {
writeJsonResponse(response, HttpServletResponse.SC_FORBIDDEN, "用户未登录或登录失效,请重新登录");
return false;
} else if (cookie.getUser().isAdmin()) {
return super.preHandle(request, response, handler);
} else {
writeJsonResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "用户无该操作权限");
return false;
}
}
}
} catch (Exception e) {
logger.error("权限校验拦截请求处理异常-->" + e.getMessage());
writeJsonResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "用户权限校验异常");
return false;
}
return super.preHandle(request, response, handler);
}
private boolean checkAuth(HttpServletRequest request, String requestUrl, String securityKey) throws Exception {
int code = requestUrl.hashCode() & (Integer.MAX_VALUE - 1);
String cacheKey = HttpUtil.getCookieValue(request, SysConstains.COOKIE_MENU);
if (StringUtils.isEmpty(cacheKey)) {
return false;
}
String menuUrl = cacheService.get(cacheKey);
if (StringUtils.isEmpty(menuUrl)) {
return false;
}
menuUrl = AESUtil.decrypt(menuUrl, securityKey);
String codes = "," + menuUrl + ",";
String codeKey = "," + code + ",";
if (codes.indexOf(codeKey) != -1) {
return true;
}
return false;
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment