diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7228855728066974381af8f5fcf084b55bc4625c
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e79da7eced123ad640ac28b12dd7a80ede958336
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4527ab398eaad8badc66bb8b88e29ab64b206d18
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/interface-common.iml b/.idea/interface-common.iml
new file mode 100644
index 0000000000000000000000000000000000000000..78b2cc53b203f0b97534bb1184cdc7b474339fb4
--- /dev/null
+++ b/.idea/interface-common.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3ccb27b15ba9e9d42e35dca35e2d1b9de04d2fad
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/smartfox_info.xml b/.idea/smartfox_info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1c2584f990e305e762d6d822c77dbd94ea31c7e4
--- /dev/null
+++ b/.idea/smartfox_info.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e96534fb27b68192f27f985d3879e173ec77adb8
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..94a25f7f4cb416c083d265558da75d457237d671
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.en.md b/README.en.md
index 1197f00c7b7aa2ef773146c741140df1ab1c4de2..7ae86562fc924e8245a3f7bf07ef845a365230e0 100644
--- a/README.en.md
+++ b/README.en.md
@@ -1,10 +1,10 @@
# interface-common
#### Description
-通过springboot整合一些工作中常用的技术,提供开源学习
+搭建springBoot通用后台接口服务interface-common(针对于前后端分离项目)
#### Software Architecture
-Software architecture description
+
#### Installation
diff --git a/interface-common.iml b/interface-common.iml
new file mode 100644
index 0000000000000000000000000000000000000000..78b2cc53b203f0b97534bb1184cdc7b474339fb4
--- /dev/null
+++ b/interface-common.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d41c9c3a1b7229e901ef6d687979035b0778e87f
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,358 @@
+
+
+ 4.0.0
+
+ com.kyrie
+ interface-common
+ 1.0-SNAPSHOT
+
+ jar
+
+
+ interface-common
+ interface-common通用接口平台
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+
+ 2.1.0.RELEASE
+
+
+
+
+
+ UTF-8
+ 1.8
+ 1.3.6
+ 1.0.18
+ 3.1.0
+ 3.1.0
+ 2.22.1
+ 3.1.0
+ 1.1.1
+ 1.9
+ 3.4
+ 1.3.2
+ 3.2.0
+ 0.9.1
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ mysql
+ mysql-connector-java
+
+
+ com.alibaba
+ druid
+ ${druid.version}
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ ${mybatis.version}
+
+
+
+ commons-codec
+ commons-codec
+ ${commons-codec.version}
+
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.8
+
+
+
+
+ com.google.code.gson
+ gson
+ 2.8.5
+
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.2
+
+
+
+
+ org.yaml
+ snakeyaml
+
+
+
+
+ log4j
+ log4j
+ 1.2.17
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.16.16
+ provided
+
+
+
+
+ org.apache.shiro
+ shiro-spring
+ ${shiro-spring.version}
+
+
+
+
+ com.auth0
+ java-jwt
+ ${java-jwt.version}
+
+
+
+ io.jsonwebtoken
+ jjwt
+ ${jjwt.version}
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+ 1.5.7.RELEASE
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+
+
+ org.springframework.kafka
+ spring-kafka
+
+
+
+
+
+
+ interface-common
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
+ src/main/resources
+ true
+
+ application.yml
+ application-${profileActive}.yml
+ mapper/**/*.xml
+ static/**
+ templates/**
+ *.xml
+ *.properties
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.1.0
+
+
+
+
+ com.kyrie.Application
+ ../lib
+ true
+
+
+
+
+ com/kyrie/**
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ ZIP
+
+
+
+ non-exists
+ non-exists
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ ${maven.dependency.version}
+
+
+ prepare-package
+
+ copy-dependencies
+
+
+ target/lib
+ false
+ false
+ true
+ compile
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ ${maven.resources.version}
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${java.version}
+ ${java.version}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven.surefire.version}
+
+ true
+
+
+
+
+
+ maven-assembly-plugin
+ ${maven.assembly.version}
+
+
+ false
+
+ src/main/assembly/assembly.xml
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+
+
+
+
+
+
+ local
+
+ local
+
+
+ true
+
+
+
+ dev
+
+ dev
+
+
+ false
+
+
+
+ uat
+
+ uat
+
+
+ false
+
+
+
+ prod
+
+ prod
+
+
+ false
+
+
+
+
\ No newline at end of file
diff --git a/sql/interface-common.sql b/sql/interface-common.sql
new file mode 100644
index 0000000000000000000000000000000000000000..3017d345caf231cc367ac00d2f30be655c7c8786
--- /dev/null
+++ b/sql/interface-common.sql
@@ -0,0 +1,127 @@
+create database interface_common;
+use interface_common;
+-- 取消外键约束
+SET FOREIGN_KEY_CHECKS=0;
+
+-- Create table 用户信息表
+DROP TABLE IF EXISTS `t_user_info`;
+CREATE TABLE `t_user_info`
+(
+ `seq_id` VARCHAR(64) NOT NULL PRIMARY KEY COMMENT '主键',
+ `user_no` VARCHAR(100) COMMENT '用户登录工号',
+ `user_name` VARCHAR(100) COMMENT '用户姓名',
+ `password` VARCHAR(64) COMMENT '用户密码',
+ `salt` VARCHAR(25) COMMENT '盐值 ',
+ `department_id` VARCHAR(100) COMMENT '部门编号',
+ `role_id` VARCHAR(64) COMMENT '角色编码',
+ `is_locked` VARCHAR(1) COMMENT '用户账号状态:1-正常、0-锁定',
+ `create_date` datetime COMMENT '创建时间',
+ `create_person` varchar(64) COMMENT '创建人',
+ `if_display` varchar(1) comment '用户账号是否有效:0-无效、1-有效'
+) ENGINE=INNODB DEFAULT CHARSET=UTF8 COMMENT='用户信息表';
+-- create index
+CREATE INDEX userInfo_userNo ON t_user_info(user_no);
+CREATE INDEX userInfo_userName ON t_user_info(user_name);
+CREATE INDEX userInfo_roleId ON t_user_info(role_id);
+CREATE INDEX userInfo_display ON t_user_info(if_display);
+CREATE INDEX userInfo_locked ON t_user_info(is_locked);
+CREATE INDEX userInfo_deptId ON t_user_info(department_id);
+
+INSERT INTO `interface_common`.`t_user_info` (`seq_id`, `user_no`, `user_name`, `password`, `salt`, `department_id`, `role_id`, `is_locked`, `create_date`, `create_person`, `if_display`)
+VALUES ('2020040723459081', '200355', '小炑', 'Abcd1234', '0', '999', '1', '1', '2020-04-07 23:59:30', 'admin', '1');
+
+
+select * from `t_user_role`;
+
+
+-- Create table 用户角色表
+DROP TABLE IF EXISTS `t_user_role`;
+CREATE TABLE `t_user_role`
+(
+ `seq_id` VARCHAR(64) NOT NULL PRIMARY KEY COMMENT '主键',
+ `role_id` VARCHAR(100) COMMENT '角色编码',
+ `role_name` VARCHAR(100) COMMENT '角色名称',
+ `role_sign` VARCHAR(100) COMMENT '权限代码',
+ `create_date` datetime COMMENT '创建时间',
+ `create_person` varchar(64) COMMENT '创建人',
+ `if_useable` varchar(1) comment '角色是否有效:0-无效、1-有效'
+) ENGINE=INNODB DEFAULT CHARSET=UTF8 COMMENT='用户角色表';
+-- create index
+CREATE INDEX userRole_roleId ON t_user_role(role_id);
+CREATE INDEX userRole_roleSign ON t_user_role(role_sign);
+INSERT INTO `interface_common`.`t_user_role` (`seq_id`, `role_id`, `role_name`, `role_sign`, `create_date`, `create_person`, `if_useable`) VALUES ('2020040723489801', '1', '系统管理员', 'systemAdmin', '2020-04-07 23:49:40', 'admin', '1');
+
+-- Create table 登录日志表
+DROP TABLE IF EXISTS `login_log`;
+CREATE TABLE `login_log` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `logname` varchar(255) DEFAULT NULL,
+ `userid` int(11) DEFAULT NULL,
+ `createtime` datetime DEFAULT NULL,
+ `state` varchar(255) DEFAULT NULL,
+ `message` varchar(255) DEFAULT NULL,
+ `ip` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=206 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
+
+
+-- Create table 数据字典表
+DROP TABLE IF EXISTS `t_operation_comm_type_val`;
+CREATE TABLE `t_operation_comm_type_val`
+(
+ `seq_id` varchar(64) not null primary key COMMENT '主键',
+ `type_id` varchar(50) COMMENT '类型标识',
+ `type_name` varchar(50) COMMENT '类型名称',
+ `val_id` varchar(60) COMMENT '值编号',
+ `val_name` varchar(4000) COMMENT '值名称',
+ `ext_val` varchar(4000) COMMENT '扩展值',
+ `status` varchar(1) COMMENT '状态:0-无效、1-有效',
+ `order_by` int(4) COMMENT '排序',
+ `remake` varchar(4000) COMMENT '备注',
+ `create_date` datetime COMMENT '创建时间',
+ `create_person` varchar(64) COMMENT '创建人'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='数据字典表';
+-- create index
+CREATE INDEX operationcomm_typeId ON t_operation_comm_type_val(type_id);
+CREATE INDEX operationcomm_valId ON t_operation_comm_type_val(val_id);
+
+
+INSERT INTO `interface_common`.`t_operation_comm_type_val`
+(`seq_id`, `type_id`, `val_id`, `val_name`, `status`, `order_by`, `remake`, `create_date`, `create_person`)
+VALUES ('20200408121728761', 'shiroUrl', 'anon', '/unauthorized;/unauthorized/**;/login', '1', '0', '无会话访问url', '2020-04-08 12:20:20', 'admin');
+
+DROP TABLE IF EXISTS `t_trans_log`;
+CREATE TABLE `t_trans_log` (
+ `logId` varchar(50) NOT NULL COMMENT '日志标识',
+ `transCode` varchar(200) DEFAULT NULL COMMENT '接口地址',
+ `createDate` varchar(50) DEFAULT NULL COMMENT '创建时间',
+ `requestBody` longtext COMMENT '请求体',
+ `responseBody` longtext COMMENT '响应体',
+ `transOperator` varchar(50) DEFAULT NULL COMMENT '接口执行人',
+ `transLogDesc` varchar(100) DEFAULT NULL COMMENT '接口描述',
+ `transTime` varchar(50) DEFAULT NULL COMMENT '接口耗时',
+ PRIMARY KEY (`logId`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='接口交易日志表';
+-- create index
+CREATE INDEX transLog_operator ON t_trans_log(transOperator);
+-- DROP INDEX transLog_operator on t_trans_log;
+-- select * from t_trans_log t
+-- where t.transOperator = '200355'
+-- and t.logId = '6aafb760-e13f-4cea-9f1f-5cd49cff81141587058024331';
+
+-- create procedure
+delimiter $$
+CREATE procedure SP_EXE_SQL(
+sqlstr varchar(1600))
+begin
+ SET @sql=sqlstr;
+ PREPARE s1 FROM @sql;
+ EXECUTE s1;
+ commit;
+ DEALLOCATE PREPARE s1;
+END$$
+delimiter ;
+-- 6aafb760-e13f-4cea-9f1f-5cd49cff81141587058024331
+-- update t_trans_log set transTime = '0' where logId = '6aafb760-e13f-4cea-9f1f-5cd49cff81141587058024331'
+call SP_EXE_SQL('update t_trans_log set transTime = ''123'' where logId = ''6aafb760-e13f-4cea-9f1f-5cd49cff81141587058024331''');
+-- drop procedure SP_EXE_SQL;
diff --git a/src/bin/restart.sh b/src/bin/restart.sh
new file mode 100755
index 0000000000000000000000000000000000000000..13aea275b95d332bb3f0c3594b65b0b82403ab9c
--- /dev/null
+++ b/src/bin/restart.sh
@@ -0,0 +1,21 @@
+#! /bin/shell
+
+#======================================================================
+# 项目重启shell脚本
+# 先调用shutdown.sh停服
+# 然后调用startup.sh启动服务
+#
+# author: kyrie
+# date: 2020-04-02
+#======================================================================
+
+# 项目名称
+APPLICATION="interface-common"
+
+# 停服
+echo stop ${APPLICATION} Application...
+sh shutdown.sh
+
+# 启动服务
+echo start ${APPLICATION} Application...
+sh startup.sh
\ No newline at end of file
diff --git a/src/bin/shutdown.sh b/src/bin/shutdown.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2d5a3687e9cc530789ae914c6b485a16cb058da2
--- /dev/null
+++ b/src/bin/shutdown.sh
@@ -0,0 +1,26 @@
+#! /bin/shell
+
+#======================================================================
+# 项目停服shell脚本
+# 通过项目名称查找到PID
+# 然后kill -9 pid
+#
+# author: kyrie
+# date: 2020-04-02
+#======================================================================
+
+# 项目名称
+APPLICATION="interface-common"
+
+# 项目启动jar包名称
+APPLICATION_JAR="${APPLICATION}.jar"
+
+PID=$(ps -ef | grep "${APPLICATION_JAR}" | grep -v grep | awk '{ print $2 }')
+if [[ -z "$PID" ]]
+then
+ echo ${APPLICATION} is already stopped
+else
+ echo kill ${PID}
+ kill -9 ${PID}
+ echo ${APPLICATION} stopped successfully
+fi
\ No newline at end of file
diff --git a/src/bin/startup.sh b/src/bin/startup.sh
new file mode 100644
index 0000000000000000000000000000000000000000..c17657a5db333cc89caa167a23d73550b4154eb8
--- /dev/null
+++ b/src/bin/startup.sh
@@ -0,0 +1,125 @@
+#! /bin/shell
+
+#======================================================================
+# 项目启动shell脚本
+# boot目录: spring boot jar包
+# config目录: 配置文件目录
+# logs目录: 项目运行日志目录
+# logs/interface-common_startup.log: 记录启动日志
+# logs/back目录: 项目运行日志备份目录
+# nohup后台运行
+#
+# author: wuxiang
+# date: 2020-04-05
+#======================================================================
+
+# 项目名称
+APPLICATION="interface-common"
+
+# 项目启动jar包名称
+APPLICATION_JAR="${APPLICATION}.jar"
+
+# bin目录绝对路径
+BIN_PATH=$(cd `dirname $0`; pwd)
+# 进入bin目录
+cd `dirname $0`
+# 返回到上一级项目根目录路径
+cd ..
+# 打印项目根目录绝对路径
+# `pwd` 执行系统命令并获得结果
+BASE_PATH=`pwd`
+
+# 外部配置文件绝对目录,如果是目录需要/结尾,也可以直接指定文件
+# 如果指定的是目录,spring则会读取目录中的所有配置文件
+CONFIG_DIR=${BASE_PATH}"/config/"
+
+# 项目日志输出绝对路径
+LOG_DIR=${BASE_PATH}"/logs"
+LOG_FILE="${APPLICATION}.log"
+LOG_PATH="${LOG_DIR}/${LOG_FILE}"
+# 日志备份目录
+LOG_BACK_DIR="${LOG_DIR}/back/"
+
+# 项目启动日志输出绝对路径
+LOG_STARTUP_PATH="${LOG_DIR}/${APPLICATION}_startup.log"
+
+# 当前时间
+NOW=`date +'%Y-%m-%m-%H-%M-%S'`
+NOW_PRETTY=`'date +%Y-%m-%m %H:%M:%S'`
+
+# 启动日志
+STARTUP_LOG="================================================ ${NOW_PRETTY} ================================================\n"
+
+# 如果logs文件夹不存在,则创建文件夹
+if [[ ! -d "${LOG_DIR}" ]]; then
+ mkdir "${LOG_DIR}"
+fi
+
+# 如果logs/back文件夹不存在,则创建文件夹
+if [[ ! -d "${LOG_BACK_DIR}" ]]; then
+ mkdir "${LOG_BACK_DIR}"
+fi
+
+# 如果项目运行日志存在,则重命名备份
+if [[ -f "${LOG_PATH}" ]]; then
+ mv ${LOG_PATH} "${LOG_BACK_DIR}/${APPLICATION}_back_${NOW}.log"
+fi
+
+# 创建新的项目运行日志
+echo "" > ${LOG_PATH}
+
+# 如果项目启动日志不存在,则创建,否则追加
+echo "${STARTUP_LOG}" >> ${LOG_STARTUP_PATH}
+
+#==========================================================================================
+# JVM Configuration
+# -Xmx256m:设置JVM最大可用内存为256m,根据项目实际情况而定,建议最小和最大设置成一样。
+# -Xms256m:设置JVM初始内存。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存
+# -Xmn512m:设置年轻代大小为512m。整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。
+# 持久代一般固定大小为64m,所以增大年轻代,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8
+# -XX:MetaspaceSize=64m:存储class的内存大小,该值越大触发Metaspace GC的时机就越晚
+# -XX:MaxMetaspaceSize=320m:限制Metaspace增长的上限,防止因为某些情况导致Metaspace无限的使用本地内存,影响到其他程序
+# -XX:-OmitStackTraceInFastThrow:解决重复异常不打印堆栈信息问题
+#==========================================================================================
+JAVA_OPT="-server -Xms256m -Xmx256m -Xmn512m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=256m"
+JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
+
+#=======================================================
+# 将命令启动相关日志追加到日志文件
+#=======================================================
+
+# 输出项目名称
+STARTUP_LOG="${STARTUP_LOG}application name: ${APPLICATION}\n"
+# 输出jar包名称
+STARTUP_LOG="${STARTUP_LOG}application jar name: ${APPLICATION_JAR}\n"
+# 输出项目bin路径
+STARTUP_LOG="${STARTUP_LOG}application bin path: ${BIN_PATH}\n"
+# 输出项目根目录
+STARTUP_LOG="${STARTUP_LOG}application root path: ${BASE_PATH}\n"
+# 打印日志路径
+STARTUP_LOG="${STARTUP_LOG}application log path: ${LOG_PATH}\n"
+# 打印JVM配置
+STARTUP_LOG="${STARTUP_LOG}application JAVA_OPT : ${JAVA_OPT}\n"
+
+
+# 打印启动命令
+STARTUP_LOG="${STARTUP_LOG}application background startup command: nohup java ${JAVA_OPT} -jar ${BASE_PATH}/boot/${APPLICATION_JAR} --spring.config.location=${CONFIG_DIR} > ${LOG_PATH} 2>&1 &\n"
+
+
+#======================================================================
+# 执行启动命令:后台启动项目,并将日志输出到项目根目录下的logs文件夹下
+#======================================================================
+nohup java ${JAVA_OPT} -jar ${BASE_PATH}/boot/${APPLICATION_JAR} --spring.config.location=${CONFIG_DIR} > ${LOG_PATH} 2>&1 &
+
+
+# 进程ID
+PID=$(ps -ef | grep "${APPLICATION_JAR}" | grep -v grep | awk '{ print $2 }')
+STARTUP_LOG="${STARTUP_LOG}application pid: ${PID}\n"
+
+# 启动日志追加到启动日志文件中
+echo -e ${STARTUP_LOG} >> ${LOG_STARTUP_PATH}
+# 打印启动日志
+echo -e ${STARTUP_LOG}
+
+# 打印项目日志
+tail -f ${LOG_PATH}
diff --git a/src/main/assembly/assembly.xml b/src/main/assembly/assembly.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0dfe66d84ab6bff0b6637abc71fc902c54862ff4
--- /dev/null
+++ b/src/main/assembly/assembly.xml
@@ -0,0 +1,77 @@
+
+
+
+
+ ${profileActive}-${project.version}
+
+
+
+ tar.gz
+
+
+
+ true
+
+
+
+
+
+
+ ${basedir}/src/bin
+ bin
+ 0755
+
+ **.sh
+
+
+
+
+
+
+ ${basedir}/target/classes
+ config
+ 0644
+
+ application.yml
+ application-${profileActive}.yml
+ mapper/**/*.xml
+ static/**
+ templates/**
+ *.xml
+ *.properties
+ *.jks
+
+
+
+
+
+ ${basedir}/target/lib
+ lib
+ 0755
+
+
+
+
+ ${basedir}/target
+ boot
+ 0755
+
+ ${project.build.finalName}.jar
+
+
+
+
+
+ ${basedir}
+
+ NOTICE
+ LICENSE
+ *.md
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/kyrie/Application.java b/src/main/java/com/kyrie/Application.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8002376e5c5c0b99cb58bfa4f476a58ec5f1358
--- /dev/null
+++ b/src/main/java/com/kyrie/Application.java
@@ -0,0 +1,29 @@
+package com.kyrie;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.servlet.ServletComponentScan;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.env.ConfigurableEnvironment;
+
+/**
+ * @author wuxiang
+ */
+@SpringBootApplication
+@ServletComponentScan
+public class Application {
+ static Logger logger = LoggerFactory.getLogger(Application.class);
+
+ public static void main(String[] args) {
+ ConfigurableApplicationContext context = SpringApplication.run(Application.class,args);
+
+ ConfigurableEnvironment environment = context.getEnvironment();
+ // 当前项目环境
+ logger.info("项目当前运行环境: {}",environment.getProperty("spring.profiles.active"));
+ String port = environment.getProperty("server.port");
+ String contextPath = environment.getProperty("server.servlet.context-path");
+ logger.info("##########项目启动完成,运行地址为: {} ##########","http://localhost:"+port+contextPath);
+ }
+}
diff --git a/src/main/java/com/kyrie/annotation/EnumValidator.java b/src/main/java/com/kyrie/annotation/EnumValidator.java
new file mode 100644
index 0000000000000000000000000000000000000000..6da395d8b61201886855c5d88fa966e679d13e1d
--- /dev/null
+++ b/src/main/java/com/kyrie/annotation/EnumValidator.java
@@ -0,0 +1,28 @@
+package com.kyrie.annotation;
+
+import com.kyrie.aop.EnumValidatorClass;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+/***
+ * 描述: 自定义枚举参数校验注解
+ *
+ * @author wuxiang
+ * @date 2020-04-21 17:12
+ */
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD,ElementType.METHOD})
+@Constraint(validatedBy = EnumValidatorClass.class)
+public @interface EnumValidator {
+ Class> value();
+
+ String message() default "参数[operateType]不在指定的枚举中";
+
+ Class>[] groups() default { };
+
+ Class extends Payload>[] payload() default { };
+}
diff --git a/src/main/java/com/kyrie/annotation/TransLog.java b/src/main/java/com/kyrie/annotation/TransLog.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d71570afaee6fe22337be528a3127d56226c6fd
--- /dev/null
+++ b/src/main/java/com/kyrie/annotation/TransLog.java
@@ -0,0 +1,22 @@
+package com.kyrie.annotation;
+
+import java.lang.annotation.*;
+
+/***
+ * 描述: 交易日志切面注解
+ *
+ * @author wuxiang
+ * @date 2020-04-16 15:14
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface TransLog {
+
+ // 描述
+ String description() default "";
+
+ // 接口交易码
+ String transCode();
+
+}
diff --git a/src/main/java/com/kyrie/aop/EnumValidatorClass.java b/src/main/java/com/kyrie/aop/EnumValidatorClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..4985d523e1c152c6c4c73c6fbe8156bc4c7a4b97
--- /dev/null
+++ b/src/main/java/com/kyrie/aop/EnumValidatorClass.java
@@ -0,0 +1,55 @@
+package com.kyrie.aop;
+
+import com.kyrie.annotation.EnumValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/***
+ * 描述: 自定义枚举参数校验注解处理类
+ *
+ * @author wuxiang
+ * @date 2020-04-21 17:37
+ */
+public class EnumValidatorClass implements ConstraintValidator, Annotation {
+ private Logger log = LoggerFactory.getLogger(this.getClass());
+ private List values = new ArrayList<>();
+
+ @Override
+ public void initialize(EnumValidator enumValidator) {
+ Class> clz = enumValidator.value();
+ Object[] ojects = clz.getEnumConstants();
+ try {
+ Method method = clz.getMethod("getValue");
+ if (Objects.isNull(method)) {
+ throw new Exception(String.format("枚举对象{}缺少字段名为value的字段",
+ clz.getName()));
+ }
+ Object value = null;
+ for (Object obj : ojects) {
+ value = method.invoke(obj);
+ values.add(value);
+ }
+ } catch (Exception e) {
+ log.error("[处理枚举校验异常]", e);
+ }
+ }
+
+
+ @Override
+ public Class extends Annotation> annotationType() {
+ return null;
+ }
+
+ @Override
+ public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
+ return Objects.isNull(value) || values.contains(value) ? true : false;
+ }
+}
diff --git a/src/main/java/com/kyrie/aop/TransLogAop.java b/src/main/java/com/kyrie/aop/TransLogAop.java
new file mode 100644
index 0000000000000000000000000000000000000000..d450167ff6f3d734ab00e6e838c40d4f0e551018
--- /dev/null
+++ b/src/main/java/com/kyrie/aop/TransLogAop.java
@@ -0,0 +1,101 @@
+package com.kyrie.aop;
+
+import com.alibaba.fastjson.JSON;
+import com.kyrie.annotation.TransLog;
+import com.kyrie.dto.UserLoginDto;
+import com.kyrie.system.mybatis.service.IDefaultService;
+import com.kyrie.utils.ConvertUtils;
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.utils.IActionContext;
+import com.kyrie.vo.TransLogVO;
+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.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.UUID;
+
+/***
+ * 描述: 交易日志切面
+ *
+ * @author wuxiang
+ * @date 2020-04-16 15:15
+ */
+@Aspect
+@Component
+public class TransLogAop {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ // 线程对象
+ private ThreadLocal threadLocal = new ThreadLocal<>();
+
+ @Resource(name = "defaultService")
+ private IDefaultService service;
+
+ @Value("${kyrie.loginUrl}")
+ private String loginUrl;
+
+ // 设置切点
+ @Pointcut("@annotation(com.kyrie.annotation.TransLog)")
+ public void transLogCut(){
+
+ }
+
+ @Before("transLogCut()")
+ public void before(JoinPoint point) {
+ long startTime = System.currentTimeMillis();
+ threadLocal.set(startTime);
+ }
+
+ @AfterReturning(value = "transLogCut()",returning = "rtv")
+ public void after(JoinPoint point,Object rtv) {
+ TransLogVO transLog = new TransLogVO();
+ // 接口耗时
+ long endTime = System.currentTimeMillis();
+ String transTime = String.valueOf(endTime - threadLocal.get());
+ // 释放线程
+ threadLocal.remove();
+ transLog.setTransTime(transTime);
+
+ //获取连接点的方法签名对象,在该对象中可以获取到目标方法名,所属类的Class等信息
+ MethodSignature signature = (MethodSignature) point.getSignature();
+ // 获取注解所属方法相关信息:接口地址、接口描述
+ String transCode = signature.getMethod().getAnnotation(TransLog.class).transCode();
+ String transDesc = signature.getMethod().getAnnotation(TransLog.class).description();
+ transLog.setTransCode(transCode);
+ transLog.setTransLogDesc(transDesc);
+
+ // 获取请求对象
+ Object[] objects = point.getArgs();
+ String requestBody = JSON.toJSONString(objects[0]);
+ transLog.setRequestBody(requestBody);
+
+ // 用户信息,判断当前请求是否为登录请求
+ String userNo;
+ if (loginUrl.equals(transCode)) {
+ UserLoginDto userLogin = ConvertUtils.stringToBean(requestBody,UserLoginDto.class);
+ userNo = userLogin.getUserNo();
+ } else {
+ userNo = IActionContext.getUserNo();
+ }
+ transLog.setTransOperator(userNo);
+
+ // 获取响应对象
+ String responseBody = JSON.toJSONString(rtv);
+ transLog.setResponseBody(responseBody);
+
+ // 生成logId
+ String logId = UUID.randomUUID().toString() + System.currentTimeMillis();
+ transLog.setLogId(logId);
+ // 记录切面日志
+ service.insert(GlobalConstants.NAME_SPACE + "insertTransLog",transLog);
+ }
+
+}
diff --git a/src/main/java/com/kyrie/config/demo.xml b/src/main/java/com/kyrie/config/demo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..48d0990d5f5176d6abc54e379fd8b669af3533d4
--- /dev/null
+++ b/src/main/java/com/kyrie/config/demo.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ SELECT
+ date_format(t.createtime,'%Y-%m-%d %H:%i:%s') createTime,
+ t.logname logType,
+ t.ip ip,
+ t.id id,
+ t.state state,
+ t.message message,
+ t.userid userId
+ FROM login_log t
+ where t.userid = #{userId}
+ and t.logname = #{logType}
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/kyrie/config/loginAuthentication.xml b/src/main/java/com/kyrie/config/loginAuthentication.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a9e712b55bfa3850baf6cb1e2c111c45a99163ae
--- /dev/null
+++ b/src/main/java/com/kyrie/config/loginAuthentication.xml
@@ -0,0 +1,38 @@
+
+
+
+
+ select
+ t1.user_no userNo,
+ t1.user_name userName,
+ t1.password password,
+ t1.salt salt,
+ t1.department_id deparmentId,
+ t1.is_locked isLocked,
+ date_format(t1.create_date,'%Y-%m-%d %H-%i-%s') createDate,
+ t1.create_person createPerson,
+ t2.role_sign roleSign,
+ t2.role_name roleName
+ from t_user_info t1,t_user_role t2
+ where t1.role_id = t2.role_id
+ and t1.user_no = #{userNo}
+ and t1.if_display = '1'
+ and t2.if_useable = '1'
+
+
+
+ select
+ t1.user_no userNo,
+ t1.user_name userName,
+ t1.department_id deparmentId,
+ t2.role_sign roleSign,
+ t2.role_name roleName
+ from t_user_info t1,t_user_role t2
+ where t1.role_id = t2.role_id
+ and t1.user_no = #{userNo}
+ and t1.if_display = '1'
+ and t2.if_useable = '1'
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/kyrie/config/operationCommTypeVal.xml b/src/main/java/com/kyrie/config/operationCommTypeVal.xml
new file mode 100644
index 0000000000000000000000000000000000000000..13fcd6eff3e29c0297db8ffe1adcb73b3202af61
--- /dev/null
+++ b/src/main/java/com/kyrie/config/operationCommTypeVal.xml
@@ -0,0 +1,191 @@
+
+
+
+
+ select
+ t.seq_id seqId,
+ t.type_id typeId,
+ t.type_name typeName,
+ t.val_id valId,
+ t.val_name valName,
+ t.ext_val extVal,
+ t.status status,
+ t.order_by orderBy,
+ t.remake remake,
+ date_format(t.create_date,'%Y-%m-%d %H:%i:%s') createDate,
+ t.create_person createPerson
+ from t_operation_comm_type_val t
+ where t.type_id = #{typeId}
+
+ and t.val_id = #{valId}
+
+
+ and t.val_name = #{valName}
+
+
+
+
+ select
+ t.val_name valName
+ from t_operation_comm_type_val t
+ where 1=1
+
+ and t.type_id = #{typeId}
+
+
+ and t.val_id = #{valId}
+
+
+
+
+ update t_operation_comm_type_val t
+ set
+
+ val_id = #{valId}
+
+
+ ,val_name = #{valName}
+
+
+ ,ext_val = #{extVal}
+
+
+ ,status = #{status}
+
+
+ ,order_by = #{orderBy}
+
+
+ ,remake = #{remake}
+
+ ,create_date = now()
+ ,create_person = #{userNo}
+ where 1=1
+
+ and type_id = #{typeId}
+
+
+ and val_id = #{valId}
+
+
+
+
+ insert into t_operation_comm_type_val(
+
+ seq_id
+
+
+ ,type_id
+
+
+ ,type_name
+
+
+ ,val_id
+
+
+ ,val_name
+
+
+ ,ext_val
+
+
+ ,status
+
+
+ ,order_by
+
+
+ ,remake
+
+ ,create_date,create_person
+ ) values (
+
+ #{seqId}
+
+
+ ,#{typeId}
+
+
+ ,#{typeName}
+
+
+ ,#{valId}
+
+
+ ,#{valName}
+
+
+ ,#{extVal}
+
+
+ ,#{status}
+
+
+ ,#{orderBy}
+
+
+ ,#{remake}
+
+ ,now(),#{userNo}
+ )
+
+
+
+ delete from t_operation_comm_type_val
+ where type_id = #{typeId}
+ and val_id = #{valId}
+
+
+
+ insert into t_trans_log(
+
+ logId
+
+
+ ,transCode
+
+
+ ,requestBody
+
+
+ ,responseBody
+
+
+ ,transOperator
+
+
+ ,transLogDesc
+
+
+ ,transTime
+
+ ,createDate
+ ) values(
+
+ #{logId}
+
+
+ ,#{transCode}
+
+
+ ,#{requestBody}
+
+
+ ,#{responseBody}
+
+
+ ,#{transOperator}
+
+
+ ,#{transLogDesc}
+
+
+ ,#{transTime}
+
+ ,now()
+ )
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/kyrie/controller/DemoController.java b/src/main/java/com/kyrie/controller/DemoController.java
new file mode 100644
index 0000000000000000000000000000000000000000..284b238a5961900b3e9ab202cd8cba4f43856caf
--- /dev/null
+++ b/src/main/java/com/kyrie/controller/DemoController.java
@@ -0,0 +1,64 @@
+package com.kyrie.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.google.gson.Gson;
+import com.kyrie.annotation.TransLog;
+import com.kyrie.dto.LoginLogDto;
+import com.kyrie.system.druid.DatasourceSelectHelper;
+import com.kyrie.system.mybatis.execption.ServiceException;
+import com.kyrie.system.mybatis.service.IDefaultService;
+import com.kyrie.utils.ConvertUtils;
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.vo.LoginLogVO;
+import com.kyrie.vo.ResponseBean;
+import org.apache.shiro.authz.annotation.Logical;
+import org.apache.shiro.authz.annotation.RequiresRoles;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 描述:demo controller
+ * @author wuxiang
+ * @date 2020-04-19 19:38:00
+ */
+@Validated
+@RestController
+public class DemoController {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Resource(name = "defaultService")
+ private IDefaultService service;
+
+ @TransLog(transCode = "/test",description = "@测试接口")
+ @RequestMapping(value = "/test",method = RequestMethod.POST)
+ @RequiresRoles(logical = Logical.OR, value = {"user","systemAdmin"})
+ public ResponseBean> getLog(@Valid @RequestBody LoginLogDto loginLogDto) throws ServiceException {
+
+ logger.info("@demo示例开始执行:{}", JSON.toJSONString(loginLogDto));
+
+ // 默认初始化的数据源
+ List loginLogVOInit = service.selectList(GlobalConstants.NAME_SPACE + "getLoginLog", loginLogDto);
+ logger.info("初始化加载的数据源查询结果为:{}",JSON.toJSONString(loginLogVOInit));
+
+ // 设置业务库
+ DatasourceSelectHelper.setKey(DatasourceSelectHelper.BUSINESS_DB);
+ List loginLogVOTwo = service.selectList(GlobalConstants.NAME_SPACE + "getLoginLog", loginLogDto);
+ logger.info("切换数据源local-2查询结果为:{}",JSON.toJSONString(loginLogVOTwo));
+
+
+ // 设置配置库
+ DatasourceSelectHelper.setKey(DatasourceSelectHelper.CONFIG_DB);
+ List loginLogVOOne = service.selectList(GlobalConstants.NAME_SPACE + "getLoginLog", loginLogDto);
+ logger.info("切换数据源local-1查询结果为:{}",JSON.toJSONString(loginLogVOOne));
+
+ return ResponseBean.success(loginLogVOOne, GlobalConstants.SUCCESS_CODE,"@登录日志查询接口请求成功");
+ }
+}
diff --git a/src/main/java/com/kyrie/controller/ErrorController.java b/src/main/java/com/kyrie/controller/ErrorController.java
new file mode 100644
index 0000000000000000000000000000000000000000..455ebcf0b7f9aea4a13fd5a875845f1d8560f257
--- /dev/null
+++ b/src/main/java/com/kyrie/controller/ErrorController.java
@@ -0,0 +1,26 @@
+package com.kyrie.controller;
+
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.vo.ResponseBean;
+import com.kyrie.vo.UserInfoVO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.*;
+
+/***
+ * 描述: 处理异常的重定向controller
+ *
+ * @author wuxiang
+ * @date 2020-04-07 23:50
+ */
+@RestController
+public class ErrorController {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @RequestMapping(value = "/500",method = RequestMethod.GET)
+ public ResponseBean error500 (String errorMsg) {
+ logger.info("拦截到/500 的错误请求信息为:{}",errorMsg);
+ return ResponseBean.success(null,GlobalConstants.FAIL_CODE,errorMsg);
+
+ }
+}
diff --git a/src/main/java/com/kyrie/controller/KafkaProducerController.java b/src/main/java/com/kyrie/controller/KafkaProducerController.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b5914b11d40e40a698345db0ac3d05497187c68
--- /dev/null
+++ b/src/main/java/com/kyrie/controller/KafkaProducerController.java
@@ -0,0 +1,53 @@
+package com.kyrie.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.kyrie.annotation.TransLog;
+import com.kyrie.dto.KafkaProducerDto;
+import com.kyrie.system.mybatis.execption.ServiceException;
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.vo.ResponseBean;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.apache.shiro.authz.annotation.Logical;
+import org.apache.shiro.authz.annotation.RequiresRoles;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import javax.validation.Valid;
+
+/**
+ * 描述:kafka生产者controller
+ * @author wuxiang
+ * @date 2020-04-19 19:38:00
+ */
+@Validated
+@RestController
+public class KafkaProducerController {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Autowired
+ private KafkaTemplate kafkaTemplate;
+
+ @TransLog(transCode = "/produceMsg",description = "@kafka消息发布接口")
+ @RequestMapping(value = "/produceMsg",method = RequestMethod.POST)
+ @RequiresRoles(logical = Logical.OR, value = {"user","systemAdmin"})
+ public ResponseBean getLog(@Valid @RequestBody KafkaProducerDto kafkaProducerDto) throws ServiceException {
+ kafkaTemplate.send("topic-kafka-demo", JSON.toJSONString(kafkaProducerDto.getPushContent()));
+
+ return ResponseBean.success(null, GlobalConstants.SUCCESS_CODE,"@kafka消息发布接口");
+ }
+
+ @KafkaListener(topics = { "topic-kafka-demo" })
+ public void receive(ConsumerRecord, ?> record) {
+
+ logger.info("消费得到的消息---key: " + record.key());
+ logger.info("消费得到的消息---value: " + record.value().toString());
+
+ }
+}
diff --git a/src/main/java/com/kyrie/controller/SqlController.java b/src/main/java/com/kyrie/controller/SqlController.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c904af2904a79968682ddd1e0def2b2ff1132aa
--- /dev/null
+++ b/src/main/java/com/kyrie/controller/SqlController.java
@@ -0,0 +1,62 @@
+package com.kyrie.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.kyrie.annotation.TransLog;
+import com.kyrie.dto.SqlExecuteDto;
+import com.kyrie.system.druid.DatasourceSelectHelper;
+import com.kyrie.system.mybatis.service.IDefaultService;
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.vo.ResponseBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.SqlParameter;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/***
+ * 描述: 动态sql执行
+ *
+ * @author wuxiang
+ * @date 2020-04-17 15:55
+ */
+@Validated
+@RestController
+public class SqlController {
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Resource(name = "defaultService")
+ private IDefaultService service;
+
+ @TransLog(transCode = "/sql/execute",description = "@动态sql执行接口")
+ @RequestMapping(value = "/sql/execute",method = RequestMethod.POST)
+ public ResponseBean execute(@Valid @RequestBody SqlExecuteDto sqlExecuteDto) {
+ String sql = sqlExecuteDto.getSql();
+ // 格式标准,去除换行符
+ sql = sql.replaceAll("#br#","");
+ String db = sqlExecuteDto.getDb();
+ // 切库
+ DatasourceSelectHelper.setKey(db);
+
+ // 组装动态sql参数
+ Map map = new HashMap<>();
+ map.put("sqlstr",sql);
+ List sqlParameters = new ArrayList<>();
+ sqlParameters.add(new SqlParameter("sqlstr", Types.VARCHAR));
+ Map returnMap = service.call("SP_EXE_SQL",false,map,sqlParameters);
+ logger.info("动态sql执行结果为:{}",returnMap);
+
+ return ResponseBean.success(JSON.toJSONString(returnMap), GlobalConstants.SUCCESS_CODE,"@动态sql执行成功");
+ }
+}
diff --git a/src/main/java/com/kyrie/controller/TOperationController.java b/src/main/java/com/kyrie/controller/TOperationController.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a2929fc0b081c824347fad7d0479afd297cbcb3
--- /dev/null
+++ b/src/main/java/com/kyrie/controller/TOperationController.java
@@ -0,0 +1,77 @@
+package com.kyrie.controller;
+
+import com.alibaba.druid.util.StringUtils;
+import com.kyrie.dto.GetDictionariesDto;
+import com.kyrie.dto.OperateDictionariesDto;
+import com.kyrie.system.mybatis.execption.ServiceException;
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.utils.OperationCommUtil;
+import com.kyrie.vo.ResponseBean;
+import com.kyrie.vo.TOperationCommTypeVal;
+import org.apache.shiro.authz.annotation.Logical;
+import org.apache.shiro.authz.annotation.RequiresRoles;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+/***
+ * 描述: 数据字典
+ *
+ * @author wuxiang
+ * @date 2020-04-07 23:50
+ */
+@Validated
+@RestController
+@RequestMapping("/commVal")
+public class TOperationController {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Resource(name = "operationCommUtil")
+ private OperationCommUtil operationCommUtil;
+
+ /**
+ * 获取数据字典列表
+ */
+ @RequestMapping(value = "/getDictionaries", method = RequestMethod.POST)
+ @RequiresRoles(logical = Logical.OR, value = {"systemAdmin"})
+ public ResponseBean> getDictionaries(@Valid @RequestBody GetDictionariesDto getDictionariesDto) throws ServiceException {
+ String typeId = getDictionariesDto.getTypeId();
+ String valId = getDictionariesDto.getValId();
+ List list = operationCommUtil.getDictList(typeId,valId);
+ return ResponseBean.success(list, GlobalConstants.SUCCESS_CODE, "@数据字典查询成功");
+ }
+
+ /**
+ * 修改+新增+删除数据字典
+ */
+ @RequestMapping(value = "/operateDictionaries", method = RequestMethod.POST)
+ @RequiresRoles(logical = Logical.OR, value = {"systemAdmin"})
+ public ResponseBean> operateDictionaries(@Valid @RequestBody OperateDictionariesDto operateDictionariesDto) throws ServiceException {
+ String operateType = operateDictionariesDto.getOperateType();
+ switch (operateType) {
+ case "add":
+ // 新增字典
+ operationCommUtil.addDictonaries(operateDictionariesDto);
+ return ResponseBean.success(null, GlobalConstants.SUCCESS_CODE, "@数据字典添加成功!");
+ case "delete":
+ // 删除字典
+ operationCommUtil.delDictonaries(operateDictionariesDto);
+ return ResponseBean.success(null, GlobalConstants.SUCCESS_CODE, "@数据字典删除成功!");
+ case "update":
+ // 更新字典
+ operationCommUtil.updDictonaries(operateDictionariesDto);
+ return ResponseBean.success(null, GlobalConstants.SUCCESS_CODE, "@数据字典更新成功!");
+ default:
+ // 未匹配到操作类型
+ return ResponseBean.fail(null, GlobalConstants.FAIL_CODE, "@数据字典操作失败,失败原因:字典操作类型:" + operateType + "非法!");
+ }
+ }
+}
diff --git a/src/main/java/com/kyrie/controller/loginController.java b/src/main/java/com/kyrie/controller/loginController.java
new file mode 100644
index 0000000000000000000000000000000000000000..151ffd07c64eee93be500a69757744712f2b5785
--- /dev/null
+++ b/src/main/java/com/kyrie/controller/loginController.java
@@ -0,0 +1,73 @@
+package com.kyrie.controller;
+
+import com.kyrie.annotation.TransLog;
+import com.kyrie.dto.UserLoginDto;
+import com.kyrie.security.jwt.JWTUtil;
+import com.kyrie.system.druid.DatasourceSelectHelper;
+import com.kyrie.system.mybatis.execption.ServiceException;
+import com.kyrie.system.mybatis.service.IDefaultService;
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.vo.LoginReturnBean;
+import com.kyrie.vo.ResponseBean;
+import com.kyrie.vo.UserInfoVO;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+
+/***
+ * 描述: 登录
+ *
+ * @author wuxiang
+ * @date 2020-04-07 23:50
+ */
+@Validated
+@RestController
+public class loginController {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Resource(name = "defaultService")
+ private IDefaultService service;
+
+
+ /**
+ * 用户登录认真接口
+ * @param user 用户登录信息
+ * @return ResponseBean
+ * @throws ServiceException
+ */
+ @TransLog(transCode = "/login",description = "@用户登录接口")
+ @RequestMapping(value = "/login",method = RequestMethod.POST)
+ public ResponseBean login(@Valid @RequestBody UserLoginDto user) throws ServiceException {
+
+ // 切换配置库
+ DatasourceSelectHelper.setKey(DatasourceSelectHelper.CONFIG_DB);
+ UserInfoVO userDb = service.selectOne(GlobalConstants.NAME_SPACE + "getUserInfo",user);
+ String password = userDb.getPassword();
+ String isLocked = userDb.getIsLocked();
+
+ String token = "";
+ // TODO 当前为测试demo,后续需优化数据库密码及登录校验规则,避免明文校验
+ if (StringUtils.isEmpty(password)) {
+ return ResponseBean.fail(null,GlobalConstants.FAIL_CODE,"用户名或密码不正确!");
+ } else if (!password.equals(user.getPassword())) {
+ return ResponseBean.fail(null,GlobalConstants.FAIL_CODE,"用户名或密码不正确!");
+ } else if ("0".equals(isLocked)) {
+ return ResponseBean.fail(null,GlobalConstants.FAIL_CODE,"账号已被锁定,请联系管理员进行解锁!");
+ } else {
+ token = JWTUtil.createToken(userDb);
+ }
+ // 登录成功返回bean
+ LoginReturnBean loginReturnBean = service.selectOne(GlobalConstants.NAME_SPACE + "loginReturn",user);
+ loginReturnBean.setToken(token);
+ return ResponseBean.success(loginReturnBean,GlobalConstants.SUCCESS_CODE,"@用户登录认证成功");
+
+ }
+}
diff --git a/src/main/java/com/kyrie/dto/GetDictionariesDto.java b/src/main/java/com/kyrie/dto/GetDictionariesDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a1318e5002a8997f5e20f0bc707bc61959e38e2
--- /dev/null
+++ b/src/main/java/com/kyrie/dto/GetDictionariesDto.java
@@ -0,0 +1,24 @@
+package com.kyrie.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/***
+ * 描述: 获取数据字典信息dto
+ *
+ * @author wuxiang
+ * @date 2020-04-14 11:35
+ */
+@Data
+public class GetDictionariesDto implements Serializable {
+
+ private static final long serialVersionUID = 1541103894719787272L;
+
+ @NotBlank(message = "数据字典一级类型不能为空")
+ private String typeId;
+
+ private String valId;
+
+}
diff --git a/src/main/java/com/kyrie/dto/KafkaProducerDto.java b/src/main/java/com/kyrie/dto/KafkaProducerDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9a4e3fc2c4153d96ca4bb47733ad1b8b1067d03
--- /dev/null
+++ b/src/main/java/com/kyrie/dto/KafkaProducerDto.java
@@ -0,0 +1,26 @@
+package com.kyrie.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/***
+ * 描述: kafka消息发布dto
+ *
+ * @author wuxiang
+ * @date 2020-04-23 17:21
+ */
+@Data
+public class KafkaProducerDto implements Serializable {
+
+ private static final long serialVersionUID = 8663656109959279829L;
+ @NotBlank(message = "topic不能为空!")
+ private String topic;
+
+ private Boolean autoFlush;
+
+ private Object pushContent;
+
+
+}
diff --git a/src/main/java/com/kyrie/dto/LoginLogDto.java b/src/main/java/com/kyrie/dto/LoginLogDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9fde64cd9ceb5777557440bc4f4a792dbecfe0f
--- /dev/null
+++ b/src/main/java/com/kyrie/dto/LoginLogDto.java
@@ -0,0 +1,23 @@
+package com.kyrie.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/***
+ * @author wuxiang
+ */
+@Data
+public class LoginLogDto implements Serializable {
+
+ private static final long serialVersionUID = -4774034279756173029L;
+
+ @NotNull(message = "用户编号[userId]不能为空!")
+ private Integer userId;
+
+ @NotBlank(message = "日志类型[logType]不能为空!")
+ private String logType;
+
+}
diff --git a/src/main/java/com/kyrie/dto/OperateDictionariesDto.java b/src/main/java/com/kyrie/dto/OperateDictionariesDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..49968d639db773265e356602d5892fa21dbed5ff
--- /dev/null
+++ b/src/main/java/com/kyrie/dto/OperateDictionariesDto.java
@@ -0,0 +1,49 @@
+package com.kyrie.dto;
+
+import com.kyrie.annotation.EnumValidator;
+import com.kyrie.vo.DictOperateEnum;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/***
+ * 描述: 数据字典操作实体:新增、删除、更新
+ *
+ * @author wuxiang
+ * @date 2020-04-14 11:35
+ */
+@Data
+public class OperateDictionariesDto implements Serializable {
+
+ private static final long serialVersionUID = -8893194005228442084L;
+
+ @NotBlank(message = "数据字典操作类型[operateType]不能为空,add-新增、delete-删除、update-更新")
+ @EnumValidator(value = DictOperateEnum.class,message = "数据字典操作类型[operateType]传入非法")
+ private String operateType;
+
+ private String userNo;
+
+ @NotBlank(message = "数据字典一级类型[typeId]不能为空")
+ private String typeId;
+
+ private String typeName;
+
+ @NotBlank(message = "数据字典二级类型[valId]不能为空")
+ private String valId;
+
+ private String seqId;
+
+ private String valName;
+
+ private String extVal;
+
+ private String status;
+
+ private Integer orderBy;
+
+ private String remake;
+
+ private String createPerson;
+
+}
diff --git a/src/main/java/com/kyrie/dto/SqlExecuteDto.java b/src/main/java/com/kyrie/dto/SqlExecuteDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a65ec965849d1c37f86e5124ab53711cb2401fe
--- /dev/null
+++ b/src/main/java/com/kyrie/dto/SqlExecuteDto.java
@@ -0,0 +1,29 @@
+package com.kyrie.dto;
+
+import com.kyrie.annotation.EnumValidator;
+import com.kyrie.vo.DataSourceEnum;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/***
+ * 描述: 动态执行sql接口dto类
+ *
+ * @author wuxiang
+ * @date 2020-04-17 16:00
+ */
+@Data
+public class SqlExecuteDto implements Serializable {
+ private static final long serialVersionUID = 2889914619629533018L;
+
+ @NotBlank(message = "SQL不能为空")
+ private String sql;
+
+ @NotBlank(message = "数据库不能为空")
+ @EnumValidator(value = DataSourceEnum.class,message = "当前选择的数据库类型[db]非法")
+ private String db;
+
+ @NotBlank(message = "执行类型不能为空")
+ private String asyn;
+}
diff --git a/src/main/java/com/kyrie/dto/UserLoginDto.java b/src/main/java/com/kyrie/dto/UserLoginDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..6128714597679548665c6d41c43e9b8ad7ce6401
--- /dev/null
+++ b/src/main/java/com/kyrie/dto/UserLoginDto.java
@@ -0,0 +1,23 @@
+package com.kyrie.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/***
+ * 描述: 用户登录dto
+ *
+ * @author wuxiang
+ * @date 2020-04-07 23:56
+ */
+@Data
+public class UserLoginDto implements Serializable {
+ private static final long serialVersionUID = 459608697154479803L;
+
+ @NotBlank(message = "用户名不能为空!")
+ private String userNo;
+
+ @NotBlank(message = "登录密码不能为空!")
+ private String password;
+}
diff --git a/src/main/java/com/kyrie/exception/GlobalExceptionHandlerController.java b/src/main/java/com/kyrie/exception/GlobalExceptionHandlerController.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4fe334da3927c799f828979b69573356b5aa44a
--- /dev/null
+++ b/src/main/java/com/kyrie/exception/GlobalExceptionHandlerController.java
@@ -0,0 +1,61 @@
+package com.kyrie.exception;
+
+import com.kyrie.system.mybatis.execption.ServiceException;
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.vo.ResponseBean;
+import org.apache.shiro.authc.AuthenticationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/***
+ * 自定义全局controller异常拦截器
+ * @author wuxiang
+ */
+@RestControllerAdvice
+public class GlobalExceptionHandlerController {
+ Logger logger = LoggerFactory.getLogger(GlobalExceptionHandlerController.class);
+
+ /***
+ * 拦截参数校验失败异常
+ * @param e MethodArgumentNotValidException
+ * @return ResponseBean
+ */
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ @ResponseBody
+ public ResponseBean methodArgumentNotValidException(MethodArgumentNotValidException e) {
+ BindingResult bindingResult = e.getBindingResult();
+ logger.info("【参数校验失败: {}】",bindingResult.getFieldError().getDefaultMessage());
+ return ResponseBean.notValid("", GlobalConstants.FAIL_CODE, bindingResult.getFieldError().getDefaultMessage());
+ }
+
+
+ /***
+ * 数据库操作异常
+ * @param e ServiceException
+ * @return ResponseBean
+ */
+ @ExceptionHandler(ServiceException.class)
+ @ResponseBody
+ public ResponseBean ServiceException(ServiceException e) {
+ logger.error("【数据库操作异常】-- catch ServiceException: ",e);
+ return ResponseBean.exception("", GlobalConstants.FAIL_CODE, e.getMessage());
+ }
+
+ /***
+ * token认证失败异常
+ * @param e AuthenticationException
+ * @return ResponseBean
+ */
+ @ExceptionHandler(AuthenticationException.class)
+ @ResponseBody
+ public ResponseBean AuthenticationException(AuthenticationException e) {
+ logger.error("【token认证失败】-- catch AuthenticationException: ",e);
+ return ResponseBean.exception("", GlobalConstants.FAIL_CODE, e.getMessage());
+ }
+
+}
diff --git a/src/main/java/com/kyrie/kafka/KafKaConfiguration.java b/src/main/java/com/kyrie/kafka/KafKaConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..eb2a768267f8108b5ea0019478f6d9e64e3b7f51
--- /dev/null
+++ b/src/main/java/com/kyrie/kafka/KafKaConfiguration.java
@@ -0,0 +1,45 @@
+package com.kyrie.kafka;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/***
+ * 描述: kafka配置读取类
+ *
+ * @author wuxiang
+ * @date 2020-04-24 13:26
+ */
+@ConfigurationProperties(prefix = "interface.kafka")
+@Component
+public class KafKaConfiguration {
+
+ private String bootstrapServers;
+
+ private KafkaProductConf producer;
+
+ private KafkaConsumerConf consumer;
+
+ public String getBootstrapServers() {
+ return bootstrapServers;
+ }
+
+ public void setBootstrapServers(String bootstrapServers) {
+ this.bootstrapServers = bootstrapServers;
+ }
+
+ public KafkaProductConf getProducer() {
+ return producer;
+ }
+
+ public void setProducer(KafkaProductConf producer) {
+ this.producer = producer;
+ }
+
+ public KafkaConsumerConf getConsumer() {
+ return consumer;
+ }
+
+ public void setConsumer(KafkaConsumerConf consumer) {
+ this.consumer = consumer;
+ }
+}
diff --git a/src/main/java/com/kyrie/kafka/KafkaConfig.java b/src/main/java/com/kyrie/kafka/KafkaConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..969fbb5c0def4394688362eff7392c10431ab90c
--- /dev/null
+++ b/src/main/java/com/kyrie/kafka/KafkaConfig.java
@@ -0,0 +1,128 @@
+package com.kyrie.kafka;
+
+import org.apache.kafka.clients.consumer.ConsumerConfig;
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
+import org.springframework.kafka.config.KafkaListenerContainerFactory;
+import org.springframework.kafka.core.*;
+import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/***
+ * 描述: kafka配置类
+ *
+ * @author wuxiang
+ * @date 2020-04-24 13:43
+ */
+@Configuration
+public class KafkaConfig {
+
+ @Autowired
+ private KafKaConfiguration kafKaConfiguration;
+
+ /**
+ * 生产者配置
+ */
+ public Map producerConfigs() {
+
+ Map props = new HashMap<>();
+ // 集群的服务器地址
+ props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafKaConfiguration.getBootstrapServers());
+ // 消息缓存
+ props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, kafKaConfiguration.getProducer().getBufferMemory());
+ // 生产者空间不足时,send()被阻塞的时间,默认60s
+ props.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, kafKaConfiguration.getProducer().getMaxBlock());
+ // 生产者重试次数
+ props.put(ProducerConfig.RETRIES_CONFIG, kafKaConfiguration.getProducer().getRetries());
+ // 指定ProducerBatch(消息累加器中BufferPool中的)可复用大小
+ props.put(ProducerConfig.BATCH_SIZE_CONFIG, kafKaConfiguration.getProducer().getBatchSize());
+ // 生产者会在ProducerBatch被填满或者等待超过LINGER_MS_CONFIG时发送
+ props.put(ProducerConfig.LINGER_MS_CONFIG, kafKaConfiguration.getProducer().getLinger());
+ // key 和 value 的序列化
+ props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
+ props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
+ "org.apache.kafka.common.serialization.StringSerializer");
+ // 客户端id
+ props.put(ProducerConfig.CLIENT_ID_CONFIG, kafKaConfiguration.getProducer().getClientId());
+
+ return props;
+ }
+
+ /**
+ * 生产者工厂
+ */
+ @Bean
+ public ProducerFactory producerFactory() {
+ return new DefaultKafkaProducerFactory<>(producerConfigs());
+ }
+
+ /**
+ * kafkaTemplate 设置生产者监听
+ */
+ @Bean
+ public KafkaTemplate kafkaTemplate() {
+ KafkaTemplate kafkaTemplate = new KafkaTemplate<>(producerFactory());
+ kafkaTemplate.setProducerListener(new KafkaProducerListener());
+ return kafkaTemplate;
+ }
+
+ /**######################################## kafka-consumer-config ########################################*/
+
+ /**
+ * 消费者配置
+ * @return
+ */
+ public Map consumerConfigs() {
+
+ Map props = new HashMap();
+
+ props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafKaConfiguration.getBootstrapServers());
+ // 消费者组
+ props.put(ConsumerConfig.GROUP_ID_CONFIG, kafKaConfiguration.getConsumer().getGroupId());
+ // 自动位移提交
+ props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, kafKaConfiguration.getConsumer().getEnableAutoCommit());
+ // 自动位移提交间隔时间
+ props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, kafKaConfiguration.getConsumer().getAutoCommitInterval());
+ // 消费组失效超时时间
+ props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, kafKaConfiguration.getConsumer().getSessionTimeout());
+ // 设置心跳时间(默认为3000)
+ props.put(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG,kafKaConfiguration.getConsumer().getHeartbeatInterval());
+ // 位移丢失和位移越界后的恢复起始位置
+ props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, kafKaConfiguration.getConsumer().getAutoOffsetReset());
+ // key 和 value 的反序列化
+ props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
+ "org.apache.kafka.common.serialization.StringDeserializer");
+ props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
+ "org.apache.kafka.common.serialization.StringDeserializer");
+
+ return props;
+ }
+
+ /**
+ * 消费者工厂
+ */
+ @Bean
+ public ConsumerFactory consumerFactory() {
+ return new DefaultKafkaConsumerFactory<>(consumerConfigs());
+ }
+
+ /**
+ * 消费者监听器
+ */
+ @Bean
+ public KafkaListenerContainerFactory> kafkaListenerContainerFactory() {
+
+ ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>();
+ // 设置消费者工厂
+ factory.setConsumerFactory(consumerFactory());
+ // 要创建的消费者数量(10 个线程并发处理)
+ factory.setConcurrency(10);
+
+ return factory;
+ }
+}
diff --git a/src/main/java/com/kyrie/kafka/KafkaConsumerConf.java b/src/main/java/com/kyrie/kafka/KafkaConsumerConf.java
new file mode 100644
index 0000000000000000000000000000000000000000..0da38e14e6b122fd8b8c9c907c6a64c70e469a6d
--- /dev/null
+++ b/src/main/java/com/kyrie/kafka/KafkaConsumerConf.java
@@ -0,0 +1,31 @@
+package com.kyrie.kafka;
+
+import lombok.Data;
+
+/***
+ * 描述: kafka消费者conf
+ *
+ * @author wuxiang
+ * @date 2020-04-24 13:29
+ */
+@Data
+public class KafkaConsumerConf {
+
+ // 消费组id
+ private String groupId;
+
+ // 自动位移提交
+ private Boolean enableAutoCommit;
+
+ // 自动位移提交间隔时间
+ private Integer autoCommitInterval;
+
+ // 消费组失效超时时间
+ private Integer sessionTimeout;
+
+ // 位移丢失和位移越界后的恢复起始位置
+ private String autoOffsetReset;
+
+ // 心跳时间
+ private String heartbeatInterval;
+}
diff --git a/src/main/java/com/kyrie/kafka/KafkaProducerListener.java b/src/main/java/com/kyrie/kafka/KafkaProducerListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..2742e4b8795370e2b124c9eb8584790de0ca4060
--- /dev/null
+++ b/src/main/java/com/kyrie/kafka/KafkaProducerListener.java
@@ -0,0 +1,32 @@
+package com.kyrie.kafka;
+
+import org.apache.kafka.clients.producer.RecordMetadata;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.kafka.support.ProducerListener;
+
+/***
+ * 描述: kafka生产者发送回调监听器
+ *
+ * @author wuxiang
+ * @date 2020-04-23 16:27
+ */
+public class KafkaProducerListener implements ProducerListener {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ /**
+ * kafka消息发送成功回调方法
+ */
+ @Override
+ public void onSuccess(String topic, Integer partition, Object key, Object value, RecordMetadata recordMetadata) {
+ logger.info("kafka send ok: [topic:{},partition:{},key:{},value:{},recordMetadata:{}]",topic,partition,key,value,recordMetadata);
+ }
+
+ /**
+ * kafka消息发送失败回调方法
+ */
+ @Override
+ public void onError(String topic, Integer partition, Object key, Object value, Exception exception) {
+ logger.info("kafka send error: [topic:{},partition:{},key:{},value:{},exception:{}]",topic,partition,key,value,exception);
+ }
+}
diff --git a/src/main/java/com/kyrie/kafka/KafkaProductConf.java b/src/main/java/com/kyrie/kafka/KafkaProductConf.java
new file mode 100644
index 0000000000000000000000000000000000000000..cbc0e2de5c1e3d0500c56d50612ec47d1f852bb4
--- /dev/null
+++ b/src/main/java/com/kyrie/kafka/KafkaProductConf.java
@@ -0,0 +1,25 @@
+package com.kyrie.kafka;
+
+import lombok.Data;
+
+/***
+ * 描述: kafka生产者conf
+ *
+ * @author wuxiang
+ * @date 2020-04-24 13:29
+ */
+@Data
+public class KafkaProductConf {
+
+ private Integer bufferMemory;
+
+ private Integer maxBlock;
+
+ private Integer retries;
+
+ private Integer batchSize;
+
+ private Integer linger;
+
+ private String clientId;
+}
diff --git a/src/main/java/com/kyrie/redis/EnabledRedisConfiguration.java b/src/main/java/com/kyrie/redis/EnabledRedisConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..80ca37d7498116285cf70c9bdc272862fda80194
--- /dev/null
+++ b/src/main/java/com/kyrie/redis/EnabledRedisConfiguration.java
@@ -0,0 +1,68 @@
+package com.kyrie.redis;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import redis.clients.jedis.HostAndPort;
+import redis.clients.jedis.JedisCluster;
+import redis.clients.jedis.JedisPoolConfig;
+
+/***
+ * 描述:redis集群配置类
+ * @author wuxiang
+ *
+ * @date 2020-03-26
+ */
+@Configuration
+@EnableConfigurationProperties(RedisProperty.class)
+public class EnabledRedisConfiguration {
+
+ private static final Logger logger = LoggerFactory.getLogger(EnabledRedisConfiguration.class);
+
+ @Autowired
+ RedisProperty property;
+// @Autowired(required=false)
+// Cryptography cryptography;
+ @Bean
+ public JedisCluster jedisCluster(){
+ Set hostAndPortSet = new HashSet(3);
+ for(Redis redis : property.getJedis()) {
+ hostAndPortSet.add(new HostAndPort(redis.getHost(), redis.getPort()));
+ }
+// String dev = System.getProperty("spring.profiles.active");
+ String passwd = property.getPasswd();
+ logger.info("redis集群密码为: {}",passwd);
+// if(!(dev == null || "local".equals(dev))) {//生产测试环境密码需解密
+// passwd = cryptography.decrypt(passwd);
+// }
+ return new JedisCluster(hostAndPortSet, property.getConnectionTimeout(), property.getSoTimeout(), property.getMaxAttempts(),
+ passwd, jedisPoolConfig());
+ }
+
+ @Bean
+ public JedisPoolConfig jedisPoolConfig() {
+ JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
+ jedisPoolConfig.setMaxIdle(property.getMaxIdle());
+ jedisPoolConfig.setMaxTotal(property.getMaxTotal());
+ jedisPoolConfig.setMinIdle(property.getMinIdel());
+ jedisPoolConfig.setTestOnBorrow(property.isTestOnBorrow());
+ jedisPoolConfig.setTestOnReturn(property.isTestOnReturn());
+ jedisPoolConfig.setTestWhileIdle(property.isTestOnIdle());
+ jedisPoolConfig.setTimeBetweenEvictionRunsMillis(property.getTimeBetweenEvictionRunsMillis());
+ jedisPoolConfig.setNumTestsPerEvictionRun(property.getNumTestsPerEvictionRun());
+ return jedisPoolConfig;
+ }
+
+// @Bean
+// @ConditionalOnMissingBean
+// @Profile({"dev","pro","uat","ft","sit","pre"})
+// public Cryptography cryptography(){
+// return new Base64Cryptography();
+// }
+}
diff --git a/src/main/java/com/kyrie/redis/Redis.java b/src/main/java/com/kyrie/redis/Redis.java
new file mode 100644
index 0000000000000000000000000000000000000000..54c7bdaf00e8fad8fd9291da1dc61811bd564452
--- /dev/null
+++ b/src/main/java/com/kyrie/redis/Redis.java
@@ -0,0 +1,28 @@
+package com.kyrie.redis;
+
+import java.io.Serializable;
+
+/**
+ * 描述:redis集群properties映射
+ */
+public class Redis implements Serializable{
+ private static final long serialVersionUID = -6649543716294491680L;
+ private String host;
+ private int port;
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+}
diff --git a/src/main/java/com/kyrie/redis/RedisConfig.java b/src/main/java/com/kyrie/redis/RedisConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d58c96b7d7fb65f446f26813ad4fe737bcdfa01
--- /dev/null
+++ b/src/main/java/com/kyrie/redis/RedisConfig.java
@@ -0,0 +1,123 @@
+package com.kyrie.redis;
+//
+//import java.net.UnknownHostException;
+//import java.util.HashSet;
+//import java.util.Set;
+//
+//import org.springframework.beans.factory.annotation.Value;
+//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import org.springframework.data.redis.connection.RedisConnectionFactory;
+//import org.springframework.data.redis.core.RedisTemplate;
+//import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+//import org.springframework.data.redis.serializer.StringRedisSerializer;
+//import com.fasterxml.jackson.annotation.JsonAutoDetect;
+//import com.fasterxml.jackson.annotation.PropertyAccessor;
+//import com.fasterxml.jackson.databind.ObjectMapper;
+///**
+// * redis配置类--单机版
+// */
+////@Configuration
+////public class RedisConfig {
+////
+//// @Bean(name="interfaceRedisTemplate")
+//// @SuppressWarnings("all")
+//// public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
+//// RedisTemplate template = new RedisTemplate();
+//// template.setConnectionFactory(factory);
+//// Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+//// ObjectMapper om = new ObjectMapper();
+//// om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+//// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+//// jackson2JsonRedisSerializer.setObjectMapper(om);
+//// StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+//// // key采用String的序列化方式
+//// template.setKeySerializer(stringRedisSerializer);
+//// // hash的key也采用String的序列化方式
+//// template.setHashKeySerializer(stringRedisSerializer);
+//// // value序列化方式采用jackson
+//// template.setValueSerializer(jackson2JsonRedisSerializer);
+//// // hash的value序列化方式采用jackson
+//// template.setHashValueSerializer(jackson2JsonRedisSerializer);
+//// template.afterPropertiesSet();
+//// return template;
+//// }
+////}
+//
+//import redis.clients.jedis.HostAndPort;
+//import redis.clients.jedis.JedisCluster;
+//import redis.clients.jedis.JedisPoolConfig;
+//
+///**
+// * redis-集群配置
+// */
+//@Configuration
+//@ConditionalOnClass({JedisCluster.class})
+//public class RedisConfig {
+// @Value("${spring.redis.cluster.nodes}")
+// private String clusterNodes;
+// @Value("${spring.redis.timeout}")
+// private int timeout;
+// @Value("${spring.redis.pool.max-idle}")
+// private int maxIdle;
+// @Value("${spring.redis.pool.max-wait}")
+// private long maxWaitMillis;
+// @Value("${spring.redis.commandTimeout}")
+// private int commandTimeout;
+//
+// @Value("${spring.redis.password}")
+// private String password;
+//
+// // 出现异常最大重试次数
+// private static int maxAttempts = 3;
+//
+// // 返回值的超时时间
+// private static int soTimeout = 5000;
+//
+// @Bean
+// public JedisCluster getJedisCluster() {
+// String[] cNodes = clusterNodes.split(",");
+// Set nodes =new HashSet<>();
+// //分割出集群节点
+// for(String node : cNodes) {
+// String[] hp = node.split(":");
+// nodes.add(new HostAndPort(hp[0],Integer.parseInt(hp[1])));
+// }
+// JedisPoolConfig jedisPoolConfig =new JedisPoolConfig();
+// jedisPoolConfig.setMaxIdle(maxIdle);
+// jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
+//
+// //创建集群对象
+//// JedisCluster jedisCluster = new JedisCluster(nodes,commandTimeout);
+// // return new JedisCluster(nodes,commandTimeout,jedisPoolConfig);
+//
+// return new JedisCluster(nodes, commandTimeout, soTimeout, maxAttempts, password, jedisPoolConfig);
+// }
+//
+// /**
+// * 设置数据存入redis 的序列化方式
+// *redisTemplate序列化默认使用的jdkSerializeable,存储二进制字节码,导致key会出现乱码,所以自定义
+// *序列化类
+// *
+// * @paramredisConnectionFactory
+// */
+// @Bean(name="interfaceRedisTemplate")
+// public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
+// RedisTemplate redisTemplate = new RedisTemplate<>();
+// redisTemplate.setConnectionFactory(redisConnectionFactory);
+// Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =new Jackson2JsonRedisSerializer(Object.class);
+// ObjectMapper objectMapper =new ObjectMapper();
+// objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
+// objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+// jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
+//
+// redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+// redisTemplate.setKeySerializer(new StringRedisSerializer());
+//
+// redisTemplate.afterPropertiesSet();
+//
+// return redisTemplate;
+// }
+//
+//}
diff --git a/src/main/java/com/kyrie/redis/RedisProperty.java b/src/main/java/com/kyrie/redis/RedisProperty.java
new file mode 100644
index 0000000000000000000000000000000000000000..de45a68928b8703f5a0975607ccfa20aa5e9fa5b
--- /dev/null
+++ b/src/main/java/com/kyrie/redis/RedisProperty.java
@@ -0,0 +1,194 @@
+package com.kyrie.redis;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@SuppressWarnings("serial")
+//@PropertySource("classpath:config/redis.yml")
+@ConfigurationProperties(prefix = "interface.redis")
+public class RedisProperty implements Serializable{
+ /**
+ * The default value for the {@code maxTotal} configuration attribute.
+ */
+ private static final int DEFAULT_MAX_TOTAL = 8;
+
+ /**
+ * The default value for the {@code maxIdle} configuration attribute.
+ */
+ private static final int DEFAULT_MAX_IDLE = 8;
+
+ /**
+ * The default value for the {@code minIdle} configuration attribute.
+ */
+ private static final int DEFAULT_MIN_IDLE = 0;
+ /**
+ * The default value for the {@code testOnBorrow} configuration attribute.
+ */
+ private static final boolean DEFAULT_TEST_ON_BORROW = false;
+
+ /**
+ * The default value for the {@code testOnReturn} configuration attribute.
+ */
+ private static final boolean DEFAULT_TEST_ON_RETURN = false;
+
+ /**
+ * The default value for the {@code testWhileIdle} configuration attribute.
+ */
+ private static final boolean DEFAULT_TEST_WHILE_IDLE = false;
+ /**
+ * The default value for the {@code timeBetweenEvictionRunsMillis}
+ * configuration attribute.
+ */
+ private static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
+ /**
+ * The default value for the {@code numTestsPerEvictionRun} configuration
+ * attribute.
+ */
+ private static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
+ /**
+ * The default value for the {@code soTimeout} configuration attribute.
+ */
+ private static final int DEFAULT_SO_TIMEOUT = 5000;
+ /**
+ * The default value for the {@code connectionTimeout} configuration attribute.
+ */
+ private static final int DEFAULT_CONNECTION_TIMEOUT = 3000;
+ /**
+ * The default value for the {@code connectionTimeout} configuration attribute.
+ */
+ private static final int DEFAULT_MAX_ATTEMPTS = 2;
+ /**连接命令执行超时时间,默认为5秒,单位为毫秒*/
+ private int soTimeout = DEFAULT_SO_TIMEOUT;
+ /**获取连接的超时时间,默认为3秒,单位毫秒*/
+ private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
+ /**命令失败时,最大重试次数,默认为2次*/
+ private int maxAttempts = DEFAULT_MAX_ATTEMPTS;
+ /**最大连接数,默认值为8,如果赋值为-1,则表示不限制**/
+ private int maxTotal = DEFAULT_MAX_TOTAL;
+ /**最大空闲连接数,默认值为8**/
+ private int maxIdle = DEFAULT_MAX_IDLE;
+ /**最小空闲连接数,默认为0**/
+ private int minIdel = DEFAULT_MIN_IDLE;
+ /**从连接池中获取连接时是否进行有效性检查*/
+ private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW;
+ /**在连接空闲时进行是否进行有效性检查*/
+ private boolean testOnIdle = DEFAULT_TEST_WHILE_IDLE;
+ /**连接归还到连接池时是否进行有效性检查 */
+ private boolean testOnReturn = DEFAULT_TEST_ON_RETURN;
+ /**空闲连接的检测线程,检测周期时间,单位为毫秒; 如果为负值则不进行检查,默认为-1 */
+ private long timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+ /**检测线程每次检测连接的个数,默认为3,为负数时全部检查*/
+ private int numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
+ /**redis密码*/
+ private String passwd;
+ /**redis集群地址*/
+ private List jedis;
+
+ public void setSoTimeout(int soTimeout) {
+ this.soTimeout = soTimeout;
+ }
+
+ public void setConnectionTimeout(int connectionTimeout) {
+ this.connectionTimeout = connectionTimeout;
+ }
+
+ public void setMaxAttempts(int maxAttempts) {
+ this.maxAttempts = maxAttempts;
+ }
+
+ public void setPasswd(String passwd) {
+ this.passwd = passwd;
+ }
+
+ public int getSoTimeout() {
+ return soTimeout;
+ }
+
+ public int getConnectionTimeout() {
+ return connectionTimeout;
+ }
+
+ public String getPasswd() {
+ return passwd;
+ }
+
+ public int getMaxAttempts() {
+ return maxAttempts;
+ }
+
+ public void setJedis(List jedis) {
+ this.jedis = jedis;
+ }
+
+ public List getJedis() {
+ return jedis;
+ }
+
+ public int getMaxTotal() {
+ return maxTotal;
+ }
+
+ public void setMaxTotal(int maxTotal) {
+ this.maxTotal = maxTotal;
+ }
+
+ public int getMaxIdle() {
+ return maxIdle;
+ }
+
+ public void setMaxIdle(int maxIdle) {
+ this.maxIdle = maxIdle;
+ }
+
+ public int getMinIdel() {
+ return minIdel;
+ }
+
+ public void setMinIdel(int minIdel) {
+ this.minIdel = minIdel;
+ }
+
+ public boolean isTestOnBorrow() {
+ return testOnBorrow;
+ }
+
+ public void setTestOnBorrow(boolean testOnBorrow) {
+ this.testOnBorrow = testOnBorrow;
+ }
+
+ public boolean isTestOnIdle() {
+ return testOnIdle;
+ }
+
+ public void setTestOnIdle(boolean testOnIdle) {
+ this.testOnIdle = testOnIdle;
+ }
+
+ public boolean isTestOnReturn() {
+ return testOnReturn;
+ }
+
+ public void setTestOnReturn(boolean testOnReturn) {
+ this.testOnReturn = testOnReturn;
+ }
+
+ public long getTimeBetweenEvictionRunsMillis() {
+ return timeBetweenEvictionRunsMillis;
+ }
+
+ public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
+ this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ }
+
+ public int getNumTestsPerEvictionRun() {
+ return numTestsPerEvictionRun;
+ }
+
+ public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
+ this.numTestsPerEvictionRun = numTestsPerEvictionRun;
+ }
+
+
+}
diff --git a/src/main/java/com/kyrie/security/interceptor/InterceptorConfigurer.java b/src/main/java/com/kyrie/security/interceptor/InterceptorConfigurer.java
new file mode 100644
index 0000000000000000000000000000000000000000..e2b6b33e8b1a3fe7a6db0df783163fa7093fd25e
--- /dev/null
+++ b/src/main/java/com/kyrie/security/interceptor/InterceptorConfigurer.java
@@ -0,0 +1,44 @@
+package com.kyrie.security.interceptor;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/***
+ * 描述: 配置安全请求拦截器
+ *
+ * @author wuxiang
+ * @date 2020-04-12 11:55
+ */
+@Configuration
+public class InterceptorConfigurer implements WebMvcConfigurer {
+
+ @Value("${shiro.anonMappings}")
+ private String anonMappings;
+
+ /**
+ * 配置静态资源
+ */
+ /*public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
+ registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
+ super.addResourceHandlers(registry);
+ }*/
+
+ @Autowired
+ private UltraViresInterceptor ultraViresInterceptor;
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ // addPathPatterns 用于添加拦截规则
+ // excludePathPatterns 用于排除拦截
+ String[] excludePathPatterns = anonMappings.split(";");
+ // 地址拦截器
+ registry.addInterceptor(ultraViresInterceptor)
+ .addPathPatterns("/**")
+ .excludePathPatterns(excludePathPatterns);
+ }
+
+}
diff --git a/src/main/java/com/kyrie/security/interceptor/RequestWrapper.java b/src/main/java/com/kyrie/security/interceptor/RequestWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c708a7a8149db3958dfc05d95a5823e5589eb5c
--- /dev/null
+++ b/src/main/java/com/kyrie/security/interceptor/RequestWrapper.java
@@ -0,0 +1,93 @@
+package com.kyrie.security.interceptor;
+
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.*;
+
+/***
+ * 描述: 复制HttpServletRequest请求对象,便于读取参数
+ *
+ * @author wuxiang
+ * @date 2020-04-12 11:28
+ */
+public class RequestWrapper extends HttpServletRequestWrapper {
+ private final String body;
+
+ public RequestWrapper(HttpServletRequest request) {
+ super(request);
+ StringBuilder stringBuilder = new StringBuilder();
+ BufferedReader bufferedReader = null;
+ InputStream inputStream = null;
+ try {
+ inputStream = request.getInputStream();
+ if (inputStream != null) {
+ bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
+ char[] charBuffer = new char[128];
+ int bytesRead = -1;
+ while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
+ stringBuilder.append(charBuffer, 0, bytesRead);
+ }
+ } else {
+ stringBuilder.append("");
+ }
+ } catch (IOException ex) {
+
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if (bufferedReader != null) {
+ try {
+ bufferedReader.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ body = stringBuilder.toString();
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
+ ServletInputStream servletInputStream = new ServletInputStream() {
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public boolean isReady() {
+ return false;
+ }
+
+ @Override
+ public void setReadListener(ReadListener readListener) {
+ }
+
+ @Override
+ public int read() throws IOException {
+ return byteArrayInputStream.read();
+ }
+ };
+ return servletInputStream;
+
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return new BufferedReader(new InputStreamReader(this.getInputStream()));
+ }
+
+ public String getBody() {
+ return this.body;
+ }
+
+}
diff --git a/src/main/java/com/kyrie/security/interceptor/RequestWrapperFilter.java b/src/main/java/com/kyrie/security/interceptor/RequestWrapperFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..c02828ffc3b8d840c7a661fe199b3daba837bad4
--- /dev/null
+++ b/src/main/java/com/kyrie/security/interceptor/RequestWrapperFilter.java
@@ -0,0 +1,43 @@
+package com.kyrie.security.interceptor;
+
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+
+/***
+ * 描述: 传递request
+ *
+ * @author wuxiang
+ * @date 2020-04-12 12:13
+ */
+@Component
+@WebFilter(urlPatterns = "/**",filterName = "RequestWrapperFilter")
+public class RequestWrapperFilter implements Filter {
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ ServletRequest requestWrapper = null;
+ if(servletRequest instanceof HttpServletRequest) {
+ requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
+ }
+ if(requestWrapper == null) {
+ filterChain.doFilter(servletRequest, servletResponse);
+ } else {
+ filterChain.doFilter(requestWrapper, servletResponse);
+ }
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+}
diff --git a/src/main/java/com/kyrie/security/interceptor/UltraViresInterceptor.java b/src/main/java/com/kyrie/security/interceptor/UltraViresInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..57ed79cd4385ed6aa2ab383516670d35e3aa502b
--- /dev/null
+++ b/src/main/java/com/kyrie/security/interceptor/UltraViresInterceptor.java
@@ -0,0 +1,83 @@
+package com.kyrie.security.interceptor;
+
+import com.alibaba.fastjson.JSON;
+import com.kyrie.security.jwt.JWTUtil;
+import com.kyrie.utils.ConvertUtils;
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.vo.UserInfoVO;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.net.URLEncoder;
+import java.util.Map;
+
+/***
+ * 描述: 安全校验拦截器(判断是否为越权访问)
+ *
+ * @author wuxiang
+ * @date 2020-04-12 11:59
+ */
+@Component("ultraViresInterceptor")
+public class UltraViresInterceptor extends HandlerInterceptorAdapter {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Value("${shiro.anonMappings}")
+ private String anonMappings;
+
+ // 拦截前处理
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) {
+ logger.info("########## 执行自定义安全校验拦截器 ##########");
+ try {
+ RequestWrapper requestWrapper = new RequestWrapper(request);
+ // 获取@RequestBody注解参数和post请求参数
+ String body = requestWrapper.getBody();
+ String requestUri = request.getRequestURI();
+ logger.info("当前请求uri:{},拦截到的请求信息为:{}",requestUri,body);
+
+ if (anonMappings.indexOf(requestUri) > -1) {
+ // 请求不做拦截
+ return true;
+ }
+ if (StringUtils.isEmpty(body)) {
+ response.sendRedirect("/500?errorMsg=" + URLEncoder.encode(GlobalConstants.CROSS_ACCESS_MSG,"UTF-8"));
+ return false;
+ }
+ Map requestMap = JSON.parseObject(body);
+ // 从token中获取用户信息
+ UserInfoVO userInfo = ConvertUtils.stringToBean(JWTUtil.getUserInfo(request.getHeader(GlobalConstants.SECURITY_TOKEN)),UserInfoVO.class);
+ String userNoFromToken = userInfo.getUserNo();
+ String userNoFromRequest = (String) requestMap.get(GlobalConstants.BUSINESS_REQUEST_ID);
+
+ if (StringUtils.isEmpty(userNoFromRequest) || !userNoFromToken.equals(userNoFromRequest)) {
+ response.sendRedirect("/500?errorMsg=" + URLEncoder.encode(GlobalConstants.CROSS_ACCESS_MSG,"UTF-8"));
+ return false;
+ }
+ return true;
+
+ } catch (Exception e) {
+ logger.error("安全识别请求拦截器内部异常", e);
+ return false;
+ }
+ }
+
+ // 拦截后处理
+ @Override
+ public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
+ ModelAndView modelAndView) throws Exception {
+
+ }
+
+ // 全部完成后处理
+ @Override
+ public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
+ Object o, Exception e) throws Exception {
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/kyrie/security/jwt/JWTFilter.java b/src/main/java/com/kyrie/security/jwt/JWTFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f084cd5fbe4e6c7d8239947baff4d2e99922b10
--- /dev/null
+++ b/src/main/java/com/kyrie/security/jwt/JWTFilter.java
@@ -0,0 +1,106 @@
+package com.kyrie.security.jwt;
+
+import com.kyrie.utils.GlobalConstants;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RequestMethod;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URLEncoder;
+
+/***
+ * 描述: 自定义JWTFilter过滤器,对token进行认证处理
+ * 所有需要认证的请求都会到当前过滤器中,配置为anon无认证的请求不会到该过滤器
+ *
+ * @author wuxiang
+ * @date 2020-04-07 10:51
+ */
+public class JWTFilter extends BasicHttpAuthenticationFilter {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ /***
+ * 持有token进行认证
+ */
+ @Override
+ protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+ // 始终返回false来执行onAccessDenied方法
+ return false;
+ }
+
+
+ /**
+ * 当isAccessAllowed返回false时会执行该方法
+ * 重定向到/500进行controller处理返回响应结果信息
+ * @param request ServletRequest
+ * @param response ServletResponse
+ * @throws Exception
+ */
+ @Override
+ protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ // 获取请求头上的token信息
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ String token = httpRequest.getHeader(GlobalConstants.SECURITY_TOKEN);
+
+ if (StringUtils.isEmpty(token)) {
+ // 针对error的中文错误信息重定向后会乱码的解决方案,对errorMsg进行编码即可
+ httpResponse.sendRedirect("/500?errorMsg=" + URLEncoder.encode(GlobalConstants.TOKEN_LOSS_MSG,"UTF-8"));
+ return false;
+ }
+
+ // 执行token认证
+ try {
+ // 委托 realm 进行登录认证
+ JWTToken jwtToken = new JWTToken(token);
+ getSubject(request,response).login(jwtToken);
+ return true;
+ } catch (Exception e) {
+ responseError(response, e.getMessage());
+ return false;
+ }
+ }
+
+ /***
+ * 添加跨域支持
+ * @param request ServletRequest
+ * @param response ServletResponse
+ * @return boolean
+ * @throws Exception
+ */
+ @Override
+ protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+
+ httpResponse.setHeader("Access-control-Allow-Origin", httpRequest.getHeader("Origin"));
+ httpResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
+ httpResponse.setHeader("Access-Control-Allow-Headers", httpRequest.getHeader("Access-Control-Request-Headers"));
+
+ // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
+ if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
+ httpResponse.setStatus(HttpStatus.OK.value());
+ return false;
+ }
+ return super.preHandle(request, response);
+ }
+
+ /**
+ * 将非法请求跳转到 /500?errorMsg=xxx
+ */
+ private void responseError(ServletResponse response, String message) {
+ try {
+ HttpServletResponse httpServletResponse = (HttpServletResponse) response;
+ //设置编码,否则中文字符在重定向时会变为空字符串
+ httpServletResponse.sendRedirect("/500?errorMsg=" + URLEncoder.encode(message, "UTF-8"));
+
+ } catch (IOException e) {
+ logger.error(e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/com/kyrie/security/jwt/JWTToken.java b/src/main/java/com/kyrie/security/jwt/JWTToken.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a7463486d7e9dde835cd371e684f18046048dae
--- /dev/null
+++ b/src/main/java/com/kyrie/security/jwt/JWTToken.java
@@ -0,0 +1,28 @@
+package com.kyrie.security.jwt;
+
+import org.apache.shiro.authc.AuthenticationToken;
+
+/***
+ * 描述: 对JWT token进行扩展
+ *
+ * @author wuxiang
+ * @date 2020-04-07 12:55
+ */
+public class JWTToken implements AuthenticationToken {
+
+ private String token;
+
+ public JWTToken (String token) {
+ this.token = token;
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return token;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return token;
+ }
+}
diff --git a/src/main/java/com/kyrie/security/jwt/JWTUtil.java b/src/main/java/com/kyrie/security/jwt/JWTUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..15fed5856ed559945d694b502691ea76703badd5
--- /dev/null
+++ b/src/main/java/com/kyrie/security/jwt/JWTUtil.java
@@ -0,0 +1,81 @@
+package com.kyrie.security.jwt;
+
+import com.alibaba.fastjson.JSON;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTDecodeException;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.utils.OperationCommUtil;
+import com.kyrie.utils.SpringContextBean;
+import com.kyrie.vo.UserInfoVO;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+
+/***
+ * 描述: JWTUtil工具类
+ *
+ * @author wuxiang
+ * @date 2020-04-07 14:44
+ */
+public class JWTUtil {
+
+ private static OperationCommUtil operationCommUtil = SpringContextBean.getBean(OperationCommUtil.class);
+
+ /**
+ * 生成 jwtToken 签名
+ */
+ public static String createToken(UserInfoVO user) {
+ try {
+ long EXPIRE_TIME = Long.valueOf(operationCommUtil.getDictValue(GlobalConstants.TYPE_2097,GlobalConstants.TYPE_2097_JWTTOKEN_EXPIRE_TIME,"900000"));
+ String SECRET = operationCommUtil.getDictValue(GlobalConstants.TYPE_2097,GlobalConstants.TYPE_2097_SECRET,"kyrie.com.cm");
+
+ Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
+ Algorithm algorithm = Algorithm.HMAC256(SECRET);
+
+ // 附带username信息
+ return JWT.create()
+ .withClaim(GlobalConstants.JWT_CLAIM, JSON.toJSONString(user))
+ //到期时间
+ .withExpiresAt(date)
+ //创建一个新的JWT,并使用给定的算法进行标记
+ .sign(algorithm);
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+ }
+
+ /**
+ * 校验 token 是否正确
+ */
+ public static boolean verify(String token, String user) {
+ try {
+ String SECRET = operationCommUtil.getDictValue(GlobalConstants.TYPE_2097,GlobalConstants.TYPE_2097_SECRET,"kyrie.com.cm");
+ Algorithm algorithm = Algorithm.HMAC256(SECRET);
+ //在token中附带了username信息
+ JWTVerifier verifier = JWT.require(algorithm)
+ .withClaim(GlobalConstants.JWT_CLAIM, user)
+ .build();
+ //验证 token
+ verifier.verify(token);
+ return true;
+ } catch (Exception exception) {
+ return false;
+ }
+ }
+
+ /**
+ * 获得token中的信息
+ */
+ public static String getUserInfo(String token) {
+ try {
+ DecodedJWT jwt = JWT.decode(token);
+ return jwt.getClaim(GlobalConstants.JWT_CLAIM).asString();
+ } catch (JWTDecodeException e) {
+ return null;
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/kyrie/security/shiro/ShiroConfig.java b/src/main/java/com/kyrie/security/shiro/ShiroConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc9abe792cd2fabc900eedcc7ab83c2a97631c4e
--- /dev/null
+++ b/src/main/java/com/kyrie/security/shiro/ShiroConfig.java
@@ -0,0 +1,125 @@
+package com.kyrie.security.shiro;
+
+import com.kyrie.security.jwt.JWTFilter;
+import com.kyrie.system.mybatis.service.IDefaultService;
+import com.kyrie.utils.GlobalConstants;
+import com.kyrie.vo.TOperationCommTypeVal;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
+import org.apache.shiro.mgt.DefaultSubjectDAO;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.spring.LifecycleBeanPostProcessor;
+import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.servlet.Filter;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/***
+ * 描述: Shiro配置类
+ *
+ * @author wuxiang
+ * @date 2020-04-07 10:38
+ */
+@Configuration
+public class ShiroConfig {
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Value("${shiro.anonMappings}")
+ private String anonMappings;
+
+ /**
+ * 注入ShiroFilterFactoryBean
+ * @param securityManager SecurityManager
+ * @return ShiroFilterFactoryBean
+ */
+ @Bean
+ public ShiroFilterFactoryBean factory (SecurityManager securityManager) {
+ ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
+
+ // 添加jwt过滤器
+ Map filterMap = new LinkedHashMap<>();
+
+ filterMap.put("jwt", new JWTFilter());
+
+ factoryBean.setFilters(filterMap);
+ factoryBean.setSecurityManager(securityManager);
+
+ // 设置无权限时跳转的URL
+ factoryBean.setUnauthorizedUrl("/500?errorMsg=" + GlobalConstants.LIMITED_REQUEST);
+
+ // 设置请求URL规则配置
+ Map fileterRuleMap = new HashMap<>();
+ // 设置所有的请求都要通过自定义的jwt过滤器
+ fileterRuleMap.put("/**","jwt");
+
+ logger.info("无认证mappings:{}",anonMappings);
+ if (StringUtils.isNotEmpty(anonMappings)) {
+ String[] mappingArr = anonMappings.split(";");
+ for (int i = 0; i < mappingArr.length; i++) {
+ fileterRuleMap.put(mappingArr[i],"anon");
+ }
+ }
+
+ // 将规则添加到ShiroFilterFactoryBean中
+ factoryBean.setFilterChainDefinitionMap(fileterRuleMap);
+
+ return factoryBean;
+ }
+
+ /**
+ * 注入securityManager
+ *
+ */
+ @Bean
+ public SecurityManager securityManager (ShiroRealm shiroRealm) {
+ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+
+ // 设置自定义的Realm
+ securityManager.setRealm(shiroRealm);
+
+ // 关闭shiro自带的session
+ DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
+ DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
+ defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
+ subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
+ securityManager.setSubjectDAO(subjectDAO);
+ return securityManager;
+ }
+
+ /**
+ * 添加注解支持
+ */
+ @Bean
+ public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
+ DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
+ // 强制使用cglib,防止重复代理和可能引起代理出错的问题
+ defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
+ return defaultAdvisorAutoProxyCreator;
+ }
+
+ @Bean
+ public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
+ AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
+ advisor.setSecurityManager(securityManager);
+ return advisor;
+ }
+
+ /**
+ * 此处将shiro生命周期设置为静态,才能使用配置文件属性
+ */
+ @Bean
+ public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
+ return new LifecycleBeanPostProcessor();
+ }
+}
diff --git a/src/main/java/com/kyrie/security/shiro/ShiroPropertity.java b/src/main/java/com/kyrie/security/shiro/ShiroPropertity.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa8c61adfd40f578d63cc7bd402239aea7f5f52d
--- /dev/null
+++ b/src/main/java/com/kyrie/security/shiro/ShiroPropertity.java
@@ -0,0 +1,19 @@
+package com.kyrie.security.shiro;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/***
+ * 描述: 获取mappings配置信息
+ *
+ * @author wuxiang
+ * @date 2020-04-08 13:34
+ */
+@Data
+@Component
+public class ShiroPropertity {
+
+ @Value("${shiro.anonMappings}")
+ private String mappings;
+}
diff --git a/src/main/java/com/kyrie/security/shiro/ShiroRealm.java b/src/main/java/com/kyrie/security/shiro/ShiroRealm.java
new file mode 100644
index 0000000000000000000000000000000000000000..82736e36761c12cf150b65c723e47648470cb326
--- /dev/null
+++ b/src/main/java/com/kyrie/security/shiro/ShiroRealm.java
@@ -0,0 +1,98 @@
+package com.kyrie.security.shiro;
+
+import com.kyrie.security.jwt.JWTToken;
+import com.kyrie.security.jwt.JWTUtil;
+import com.kyrie.system.mybatis.service.IDefaultService;
+import com.kyrie.utils.ConvertUtils;
+import com.kyrie.vo.UserInfoVO;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/***
+ * 描述: 自定义ShiroRealm
+ *
+ * @author wuxiang
+ * @date 2020-04-07 14:06
+ */
+@Component
+public class ShiroRealm extends AuthorizingRealm {
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Resource(name = "defaultService")
+ private IDefaultService service;
+
+ /**
+ * 重写此方法
+ * 标识这个Realm是专门用来验证JwtToken,不负责验证其他的token(UsernamePasswordToken)
+ * @param token AuthenticationToken
+ * @return boolean
+ */
+ @Override
+ public boolean supports(AuthenticationToken token) {
+ //这个token就是从过滤器中传入的jwtToken
+ return token instanceof JWTToken;
+ }
+
+ /**
+ * 用户身份认证
+ * @param authenticationToken AuthenticationToken
+ * @return AuthenticationInfo
+ * @throws AuthenticationException
+ */
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
+ /*logger.info("##########执行用户身份认证##########");*/
+ // 获取token
+ String token = (String) authenticationToken.getCredentials();
+ // 通过token获取用户信息
+ String user = JWTUtil.getUserInfo(token);
+
+ if (StringUtils.isEmpty(user) || !JWTUtil.verify(token,user)) {
+ throw new AuthenticationException("token认证失败!");
+ }
+
+ // 执行数据库认证,即双重认证用户身份,防止管理员中途更改用户信息导致用户未重新登录,更改信息不生效
+ // TODO 存在问题:中途管理员修改密码怎么办?
+ /*UserInfoVO userInfoVO = service.selectOne(NAME_SPACE + "getUserInfo",userNo);
+ if (null == userInfoVO) {
+ throw new AuthenticationException("用户信息不存在或者被更改,请重新登录");
+ }*/
+
+ return new SimpleAuthenticationInfo(token,token,"ShiroRealm");
+ }
+
+ /**
+ * 用户权限认证
+ * @param principals PrincipalCollection
+ * @return AuthorizationInfo
+ */
+ @Override
+ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+ /*logger.info("##########执行用户权限认证##########");*/
+ // 获取token中的用户实体信息
+ UserInfoVO userInfo = ConvertUtils.stringToBean(JWTUtil.getUserInfo(principals.toString()),UserInfoVO.class);
+
+ SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
+ String role = userInfo.getRoleSign();
+ if (StringUtils.isNotEmpty(role)) {
+ simpleAuthorizationInfo.addRole(role);
+ }
+ /*logger.info("#####当前用户: {},的角色权限为: {}", userInfo.getUserNo(), role);*/
+ return simpleAuthorizationInfo;
+ }
+
+
+}
diff --git a/src/main/java/com/kyrie/system/druid/DatasourceAutoConfiguration.java b/src/main/java/com/kyrie/system/druid/DatasourceAutoConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..96d6c0da20a2eac10d8a1d1c07ecd1ef61f8fc1c
--- /dev/null
+++ b/src/main/java/com/kyrie/system/druid/DatasourceAutoConfiguration.java
@@ -0,0 +1,181 @@
+package com.kyrie.system.druid;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.sql.DataSource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.fastjson.JSON;
+
+/**
+ * 不同配置加载不同的数据源,非开发环境还需进行密文解密操作
+ * single 加载单一数据源,
+ * routing 加载带多数据源通过dsKey与数据源名称进行匹配,选择执行sql的数据源
+ * routingwriteread 除路由功能后,还有读写分离的能力,通过prefix属性来区分读写操作
+ * @author wuxiang
+ *
+ */
+@Configuration
+@EnableConfigurationProperties(value={DatasourceProperties.class,DatasourceProperty.class})
+public class DatasourceAutoConfiguration {
+
+ private Logger logger = LoggerFactory.getLogger(DatasourceAutoConfiguration.class);
+
+ @Autowired
+ DatasourceProperties datasourceProperties;
+
+ @Autowired
+ DatasourceProperty datasourceProperty;
+
+ /**
+ * 是否开启SQL拦截数据同步
+ */
+ @Value("${spring.datasource.sqlAop.isUse:false}")
+ boolean isUseSqlAop;
+ /**
+ * 解密器
+ */
+// @Autowired(required=false)
+// Cryptography cryptography;
+
+
+ @Value("${spring.datasource.isRemoveAbandoned:false}")
+ boolean isRemoveAbandoned;
+
+ /**
+ * 初始化数据源
+ * @return 数据源
+ */
+ @Bean
+ public DataSource datasource() {
+ logger.info("数据源连接池信息如下:{}", JSON.toJSONString(datasourceProperties));
+ logger.info("SQL AOP 状态: {}", isUseSqlAop);
+ // 判断所选用的数据源类型
+ if (DatasourceProperty.DATASOURCE_TYPE_SINGLE.equals(datasourceProperty.getType())) {
+ logger.info("亲,你选择的是single数据源,配置信息如下 :{}", JSON.toJSONString(getNodeByName(datasourceProperty.getName())));
+ return createDatasource(datasourceProperties, getNodeByName(datasourceProperty.getName()), false);
+ } else if (DatasourceProperty.DATASOURCE_TYPE_ROUTING.equals(datasourceProperty.getType())) {
+ MultipleDataSource mds = new MultipleDataSource();
+ Map dsMap = new HashMap<>();
+ logger.info("亲,你选择的是routing数据源,配置信息如下 :");
+ for(Node node : getNodeByName(datasourceProperty.getName().split(","))) {
+ logger.info("node name:{}, properties:{}", node.getName(), JSON.toJSONString(node));
+ dsMap.put(node.getName(), createDatasource(datasourceProperties, node, false));
+ }
+ mds.setTargetDataSources(dsMap);
+ String defaultName = dsMap.keySet().toArray(new String[0])[0];
+ logger.info("choose routing and default datasource is {}", defaultName);
+ mds.setDefaultTargetDataSource(dsMap.get(defaultName));
+ return mds;
+ } else if(DatasourceProperty.DATASOURCE_TYPE_ROUTING_READWRITE.equals(datasourceProperty.getType())) {
+ MultipleDataSource mds = new MultipleDataSource();
+ Map dsMap = new HashMap();
+ logger.info("亲,你选择的是routingreadwrite数据源,配置信息如下 :");
+ for(Node node : getNodeByName(datasourceProperty.getName().split(","))) {
+ dsMap.put(node.getName(), createDatasource(datasourceProperties, node, false));
+ logger.info("node name:{}, properties:{}", node.getName(), JSON.toJSONString(node));
+ Node dsp = node.getSlave();
+ if(dsp != null) {
+ logger.info("node's slave name:{}, properties:{}", dsp.getName(), JSON.toJSONString(dsp));
+ dsMap.put(node.getName() + "-slave", createDatasource(datasourceProperties, dsp, false));
+ }
+ }
+ mds.setTargetDataSources(dsMap);
+ String defaultName = dsMap.keySet().toArray(new String[0])[0];
+ logger.info("choose routingreadwrite and default datasource is {}", defaultName);
+ mds.setDefaultTargetDataSource(dsMap.get(defaultName));
+ return mds;
+ } else {
+ logger.error("亲,你的配置[{}]有问题,请仔细检查下数据源类型是否为[single,routing,routingreadwrite]中的一种", datasourceProperty.getType());
+ throw new RuntimeException("亲,你的配置["+ datasourceProperty.getType() + "]有问题,请仔细检查下数据源类型是否为[single,routing,routingreadwrite]中的一种");
+ }
+ }
+
+ /**
+ * 通过配置生成druid数据源
+ * @return 数据源
+ */
+ private DataSource createDatasource(DatasourceProperties datasourceProperties, Node node,boolean isJta) {
+ DruidDataSource datasource = new DruidDataSource();
+ datasource.setUrl(node.getUrl());
+ datasource.setUsername(node.getUsername());
+ datasource.setDriverClassName(node.getDriverClassName());
+ String passwd = node.getPassword();
+ /*Node node = datasourceProperties.getNodes().get(0);
+
+ DruidDataSource datasource = new DruidDataSource();
+ datasource.setUrl(node.getUrl());
+ datasource.setUsername(node.getUsername());
+ datasource.setDriverClassName(node.getDriverClassName());
+ String passwd = node.getPassword();*/
+ // 后续对于生产环境需要进行数据库密码加密处理
+ /*String dev = System.getProperty("spring.profiles.active");
+ if(!(dev==null || "local".equals(dev))) {//生产测试环境密码需解密
+ passwd = cryptography.decrypt(passwd);
+ }*/
+ datasource.setPassword(passwd);
+ //configuration
+ datasource.setInitialSize(datasourceProperties.getInitialSize());
+ datasource.setMinIdle(datasourceProperties.getMinIdle());
+ datasource.setMaxActive(datasourceProperties.getMaxActive());
+ datasource.setMaxWait(datasourceProperties.getMaxWait());
+ datasource.setTimeBetweenEvictionRunsMillis(datasourceProperties.getTimeBetweenEvictionRunsMillis());
+ datasource.setMinEvictableIdleTimeMillis(datasourceProperties.getMinEvictableIdleTimeMillis());
+ datasource.setValidationQuery(datasourceProperties.getValidationQuery());
+ datasource.setTestWhileIdle(datasourceProperties.isTestWhileIdle());
+ datasource.setTestOnBorrow(datasourceProperties.isTestOnBorrow());
+ datasource.setTestOnReturn(datasourceProperties.isTestOnReturn());
+ datasource.setPoolPreparedStatements(datasourceProperties.isPoolPreparedStatements());
+ datasource.setMaxPoolPreparedStatementPerConnectionSize(datasourceProperties.getMaxPoolPreparedStatementPerConnectionSize());
+ datasource.setConnectionProperties(datasourceProperties.getConnectionProperties());
+ /*datasource.setProxyFilters(druidSqlFilter());*/
+ if(this.isRemoveAbandoned) {
+ datasource.setRemoveAbandoned(datasourceProperties.isRemoveAbandoned());
+ datasource.setRemoveAbandonedTimeoutMillis(datasourceProperties.getRemoveAbandonedTimeoutMillis());
+ datasource.setLogAbandoned(true);
+ logger.info("开启removeAbandoned模式,获取连接后在{}毫秒内不执行完的SQL将会被取消", datasourceProperties.getRemoveAbandonedTimeoutMillis());
+ }
+ try {
+ datasource.setFilters(datasourceProperties.getFilters());
+ datasource.init();
+ logger.info("datasource name:[{}] url:[{}] username:[{}] inited successfully!", node.getName(), node.getUrl(), node.getUsername());
+ } catch (SQLException e) {
+ logger.error("datasource inited failed", e);
+ } catch (Exception e) {
+ logger.error("db password decrypt failed");
+ }
+ return datasource;
+ }
+
+ private Node getNodeByName(String name) {
+ Node temp = null;
+ List nodes = datasourceProperties.getNodes();
+ for(Node node : nodes) {
+ if(name.equals(node.getName())) {
+ temp = node;
+ }
+ }
+ return temp;
+ }
+
+ private List getNodeByName(String[] names) {
+ List temp = new ArrayList(names.length);
+ for(String name : names) {
+ temp.add(getNodeByName(name));
+ }
+ return temp;
+ }
+
+
+}
+
diff --git a/src/main/java/com/kyrie/system/druid/DatasourceProperties.java b/src/main/java/com/kyrie/system/druid/DatasourceProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..df56008dea8647bffaa4d77e85fc953a1804edf6
--- /dev/null
+++ b/src/main/java/com/kyrie/system/druid/DatasourceProperties.java
@@ -0,0 +1,203 @@
+package com.kyrie.system.druid;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * 读取数据源配置信息类
+ * @author wuxiang
+ * @since jdk1.8.0
+ * @version 1.0.1
+ */
+@SuppressWarnings("serial")
+@ConfigurationProperties(prefix = "spring.datasource")
+public class DatasourceProperties implements Serializable {
+ /**
+ * 初始化连接数
+ */
+ private int initialSize;
+ /**
+ * 最小连接数
+ */
+ private int minIdle;
+ /**
+ * 最大连接数
+ */
+ private int maxActive;
+ /**
+ * 连接连接时最大等待时间
+ */
+ private int maxWait;
+ /**
+ * 连接在池内空闲时,检查周期时间,单位毫秒
+ */
+ private int timeBetweenEvictionRunsMillis;
+ /**
+ * 连接在池中空闲时最小生存的时间,单位是毫秒
+ */
+ private int minEvictableIdleTimeMillis;
+ /**
+ * 检查连接是否有效的SQL语句
+ */
+ private String validationQuery;
+ /**
+ * 连接空闲时是否检查连接是否可用
+ */
+ private boolean testWhileIdle;
+ /**
+ * 获取连接内是否检查连接是否可用
+ */
+ private boolean testOnBorrow;
+ /**
+ * 归还连接时是否检查连接是否可用
+ */
+ private boolean testOnReturn;
+ /**
+ * 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭
+ */
+ private boolean poolPreparedStatements;
+ /**
+ * preparedStatement最大缓存个数
+ */
+ private int maxPoolPreparedStatementPerConnectionSize;
+ /**
+ * 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:
+ * stat : 监控统计用的filter:
+ * log4j :日志用的filter
+ * wall: 防御sql注入的filter
+ */
+ private String filters;
+ /**
+ * 物理连接初始化的时候执行的sql
+ */
+ private String connectionProperties;
+ /**
+ * 数据库节点配置集合
+ */
+ private List nodes;
+ /**
+ * 是否开启获取连接后不归还主动关闭
+ */
+ private boolean removeAbandoned;
+ /**
+ * 连接租期最长时间
+ */
+ private Long removeAbandonedTimeoutMillis;
+
+
+ public boolean isRemoveAbandoned() {
+ return removeAbandoned;
+ }
+
+
+ public void setRemoveAbandoned(Boolean removeAbandoned) {
+ this.removeAbandoned = removeAbandoned;
+ }
+
+
+ public void setRemoveAbandonedTimeoutMillis(Long removeAbandonedTimeoutMillis) {
+ this.removeAbandonedTimeoutMillis = removeAbandonedTimeoutMillis;
+ }
+
+
+ public Long getRemoveAbandonedTimeoutMillis() {
+ return removeAbandonedTimeoutMillis;
+ }
+
+ public List getNodes() {
+ return nodes;
+ }
+ public void setNodes(List nodes) {
+ this.nodes = nodes;
+ }
+ public int getInitialSize() {
+ return initialSize;
+ }
+ public void setInitialSize(int initialSize) {
+ this.initialSize = initialSize;
+ }
+ public int getMinIdle() {
+ return minIdle;
+ }
+ public void setMinIdle(int minIdle) {
+ this.minIdle = minIdle;
+ }
+ public int getMaxActive() {
+ return maxActive;
+ }
+ public void setMaxActive(int maxActive) {
+ this.maxActive = maxActive;
+ }
+ public int getMaxWait() {
+ return maxWait;
+ }
+ public void setMaxWait(int maxWait) {
+ this.maxWait = maxWait;
+ }
+ public int getTimeBetweenEvictionRunsMillis() {
+ return timeBetweenEvictionRunsMillis;
+ }
+ public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
+ this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ }
+ public int getMinEvictableIdleTimeMillis() {
+ return minEvictableIdleTimeMillis;
+ }
+ public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
+ this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+ }
+ public String getValidationQuery() {
+ return validationQuery;
+ }
+ public void setValidationQuery(String validationQuery) {
+ this.validationQuery = validationQuery;
+ }
+ public boolean isTestWhileIdle() {
+ return testWhileIdle;
+ }
+ public void setTestWhileIdle(boolean testWhileIdle) {
+ this.testWhileIdle = testWhileIdle;
+ }
+ public boolean isTestOnBorrow() {
+ return testOnBorrow;
+ }
+ public void setTestOnBorrow(boolean testOnBorrow) {
+ this.testOnBorrow = testOnBorrow;
+ }
+ public boolean isTestOnReturn() {
+ return testOnReturn;
+ }
+ public void setTestOnReturn(boolean testOnReturn) {
+ this.testOnReturn = testOnReturn;
+ }
+ public boolean isPoolPreparedStatements() {
+ return poolPreparedStatements;
+ }
+ public void setPoolPreparedStatements(boolean poolPreparedStatements) {
+ this.poolPreparedStatements = poolPreparedStatements;
+ }
+ public int getMaxPoolPreparedStatementPerConnectionSize() {
+ return maxPoolPreparedStatementPerConnectionSize;
+ }
+ public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) {
+ this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
+ }
+ public String getFilters() {
+ return filters;
+ }
+ public void setFilters(String filters) {
+ this.filters = filters;
+ }
+ public String getConnectionProperties() {
+ return connectionProperties;
+ }
+ public void setConnectionProperties(String connectionProperties) {
+ this.connectionProperties = connectionProperties;
+ }
+
+
+
+}
+
diff --git a/src/main/java/com/kyrie/system/druid/DatasourceProperty.java b/src/main/java/com/kyrie/system/druid/DatasourceProperty.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c4cad85b38008372ed923f626774dea9fa393d7
--- /dev/null
+++ b/src/main/java/com/kyrie/system/druid/DatasourceProperty.java
@@ -0,0 +1,69 @@
+package com.kyrie.system.druid;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.io.Serializable;
+
+/***
+ * 描述: 读取数据源类型配置文件
+ *
+ * @author wuxiang
+ * @date 2020-04-17 00:33
+ */
+@SuppressWarnings("serial")
+@ConfigurationProperties(prefix = "kyrie.datasource-config")
+public class DatasourceProperty implements Serializable {
+ /**
+ * 单一数据源
+ */
+ public static final String DATASOURCE_TYPE_SINGLE = "single";
+ /**
+ * 路由数据源
+ */
+ public static final String DATASOURCE_TYPE_ROUTING = "routing";
+ /**
+ * 路由数据源+读写分离
+ */
+ public static final String DATASOURCE_TYPE_ROUTING_READWRITE = "routingreadwrite";
+ /**
+ * 分布式事务数据源
+ */
+ public static final String DATASOURCE_TYPE_JTA = "jta";
+ /**
+ * 数据源类型(single,routing,routing&readwrite)三种
+ */
+ private String type;
+ /**
+ * 需要获取的数据源配置,如有多个请用逗号(,)分隔
+ */
+ private String name;
+ /**
+ * 如果数据源类型为routingreadwrite,则此属性会有效,以此前缀来区分service操作是否为写操作
+ * 多个前缀请用逗号(,)分隔
+ */
+ private String prefix;
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/com/kyrie/system/druid/DatasourceSelectHelper.java b/src/main/java/com/kyrie/system/druid/DatasourceSelectHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ec2d3ea1b173d29fdf3869f92bce0c1294f6aeb
--- /dev/null
+++ b/src/main/java/com/kyrie/system/druid/DatasourceSelectHelper.java
@@ -0,0 +1,36 @@
+package com.kyrie.system.druid;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/***
+ * 描述: 路由数据源切换
+ *
+ * @author wuxiang
+ * @date 2020-04-17 00:24
+ */
+public class DatasourceSelectHelper {
+ static final Logger LOGGER = LoggerFactory.getLogger(DatasourceSelectHelper.class);
+
+ // 数据源类型
+ public static final String BUSINESS_DB = "business";
+
+ public static final String CONFIG_DB = "config";
+
+ public static final String ROUTE_DB = "route";
+
+ public static final String REPORT_DB = "report";
+
+ public static final String ARC_DB = "arc";
+
+ private static final ThreadLocal DATASOURCEKEY = new ThreadLocal();
+
+ public static String getKey() {
+ return DATASOURCEKEY.get();
+ }
+
+ public static void setKey(String key) {
+ DATASOURCEKEY.set(key);
+ LOGGER.info("datasource dsKey switch to ######{}#####", key);
+ }
+}
diff --git a/src/main/java/com/kyrie/system/druid/MultipleDataSource.java b/src/main/java/com/kyrie/system/druid/MultipleDataSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..f35770eeef86088205b58905e4a360545e30b6fd
--- /dev/null
+++ b/src/main/java/com/kyrie/system/druid/MultipleDataSource.java
@@ -0,0 +1,17 @@
+package com.kyrie.system.druid;
+
+import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+
+/***
+ * 描述: 路由多数据源
+ *
+ * @author wuxiang
+ * @date 2020-04-17 00:23
+ */
+public class MultipleDataSource extends AbstractRoutingDataSource {
+
+ @Override
+ protected Object determineCurrentLookupKey() {
+ return DatasourceSelectHelper.getKey();
+ }
+}
diff --git a/src/main/java/com/kyrie/system/druid/MybatisConfig.java b/src/main/java/com/kyrie/system/druid/MybatisConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..42476188d245c212c2bbe2c35d74354c0838a37b
--- /dev/null
+++ b/src/main/java/com/kyrie/system/druid/MybatisConfig.java
@@ -0,0 +1,64 @@
+package com.kyrie.system.druid;
+
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.SqlSessionTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+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.support.PathMatchingResourcePatternResolver;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.transaction.annotation.TransactionManagementConfigurer;
+
+import javax.sql.DataSource;
+
+/***
+ * @author wuxiang
+ * 初始化sqlSessionFactory、sqlSession、JdbcTemplate
+ */
+@Configuration
+@EnableTransactionManagement
+public class MybatisConfig implements TransactionManagementConfigurer {
+
+ /**
+ * 指定mapper位置
+ */
+ @Value("${mybatis.location}")
+ private String mapperLocation;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Bean(name = "sqlSessionFactory")
+ public SqlSessionFactory sqlSessionFactory() throws Exception {
+ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
+ sqlSessionFactoryBean.setDataSource(dataSource);
+ PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+ sqlSessionFactoryBean.setConfigLocation(resolver.getResource(mapperLocation));
+
+ return sqlSessionFactoryBean.getObject();
+ }
+
+ @Bean(name = "sqlSession")
+ public SqlSessionTemplate sqlSession(@Qualifier(value = "sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
+ return new SqlSessionTemplate(sqlSessionFactory);
+ }
+
+ @Bean
+ @Override
+ public PlatformTransactionManager annotationDrivenTransactionManager() {
+ return new DataSourceTransactionManager(dataSource);
+ }
+
+ @Bean
+ public JdbcTemplate jdbcTemplate(DataSource dataSource){
+ return new JdbcTemplate(dataSource);
+ }
+
+
+}
diff --git a/src/main/java/com/kyrie/system/druid/Node.java b/src/main/java/com/kyrie/system/druid/Node.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4f8d00d43dfdcea5001a69e1b0e97f12d905971
--- /dev/null
+++ b/src/main/java/com/kyrie/system/druid/Node.java
@@ -0,0 +1,24 @@
+package com.kyrie.system.druid;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 数据库的节点配置
+ * 包括驱动类、数据库名、数据库用户名、数据库密码以及从库信息
+ * 数据库密码除开发环境为明文,其它环境都为密文
+ * @author wuxiang
+ */
+@SuppressWarnings("serial")
+@Data
+public class Node implements Serializable{
+ private String driverClassName;
+ private String name;
+ private String url;
+ private String username;
+ private String password;
+ private Node slave;
+
+}
+
diff --git a/src/main/java/com/kyrie/system/mybatis/dao/StoredProcedureHandler.java b/src/main/java/com/kyrie/system/mybatis/dao/StoredProcedureHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..d7e02ecc28a7d7bca4a20947b65897c795fd36cf
--- /dev/null
+++ b/src/main/java/com/kyrie/system/mybatis/dao/StoredProcedureHandler.java
@@ -0,0 +1,28 @@
+package com.kyrie.system.mybatis.dao;
+
+import javax.sql.DataSource;
+
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.object.StoredProcedure;
+
+/***
+ * @author wuxiang
+ * @date 2020-04-06
+ */
+public class StoredProcedureHandler extends StoredProcedure {
+ public StoredProcedureHandler() {
+ }
+
+ public StoredProcedureHandler(DataSource ds) {
+ this();
+ setDataSource(ds);
+ }
+
+ public StoredProcedureHandler(DataSource ds, String sql) {
+ super(ds, sql);
+ }
+
+ public StoredProcedureHandler(JdbcTemplate jdbcTemplate, String name) {
+ super(jdbcTemplate, name);
+ }
+}
diff --git a/src/main/java/com/kyrie/system/mybatis/execption/ServiceException.java b/src/main/java/com/kyrie/system/mybatis/execption/ServiceException.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a034d22fcf5b3ed13ef142398f68f55c15d4552
--- /dev/null
+++ b/src/main/java/com/kyrie/system/mybatis/execption/ServiceException.java
@@ -0,0 +1,36 @@
+package com.kyrie.system.mybatis.execption;
+
+/***
+ * @author wuxiang
+ * @date 2020-04-06
+ *
+ * mybatis通用异常处理类
+ */
+public class ServiceException extends RuntimeException {
+ private String messageCode;
+ private String message;
+
+ private static final long serialVersionUID = -8705167646414506373L;
+
+ public ServiceException() {
+ }
+
+ public ServiceException(String message) {
+ super(message);
+ }
+
+ public ServiceException(Throwable cause) {
+ super(cause);
+ }
+
+ public ServiceException(String message, Throwable cause) {
+ super(message, cause);
+ this.message = message;
+ }
+
+ public ServiceException(Throwable cause, String messageCode, String message) {
+ super("[" + messageCode + "]" + message, cause);
+ this.messageCode = messageCode;
+ }
+}
+
diff --git a/src/main/java/com/kyrie/system/mybatis/service/IDefaultService.java b/src/main/java/com/kyrie/system/mybatis/service/IDefaultService.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1e29b79af20816fbff59e53f59dde90f6799fe3
--- /dev/null
+++ b/src/main/java/com/kyrie/system/mybatis/service/IDefaultService.java
@@ -0,0 +1,135 @@
+package com.kyrie.system.mybatis.service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import com.kyrie.system.mybatis.execption.ServiceException;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.SqlOutParameter;
+import org.springframework.jdbc.core.SqlParameter;
+
+/***
+ * @author wuxiang
+ * @date 2020-04-06
+ *
+ * mybatis通用数据库访问方法
+ */
+public abstract interface IDefaultService {
+ public abstract int insert(String paramString, Object paramObject)
+ throws ServiceException;
+
+
+ public abstract int delete(String paramString, Object paramObject)
+ throws ServiceException;
+
+
+ public abstract int update(String paramString, Object paramObject)
+ throws ServiceException;
+
+
+ public abstract List selectList(String paramString)
+ throws ServiceException;
+
+ public abstract List selectList(String paramString, Object paramObject)
+ throws ServiceException;
+
+ public abstract List selectList(String paramString, Object paramObject, int paramInt1, int paramInt2)
+ throws ServiceException;
+
+ public abstract T selectOne(String paramString, Object paramObject)
+ throws ServiceException;
+
+ public abstract Object[] getCommonPaged(String paramString1, String paramString2, Object paramObject, int paramInt1, int paramInt2)
+ throws ServiceException;
+
+ public abstract void batchUpdate(String paramString, List paramList, int[] paramArrayOfInt)
+ throws ServiceException;
+
+ public abstract int[] batchUpdate(String... paramVarArgs)
+ throws ServiceException;
+
+ public abstract void batchUpdate(String paramString, List paramList)
+ throws ServiceException;
+
+ public abstract void batchUpdate(String paramString, BatchPreparedStatementSetter paramBatchPreparedStatementSetter)
+ throws ServiceException;
+
+ public abstract void batchUpdate(String paramString, Collection paramCollection, int paramInt, ParameterizedPreparedStatementSetter paramParameterizedPreparedStatementSetter)
+ throws ServiceException;
+
+ public abstract List> queryList(String paramString, List paramList, int[] paramArrayOfInt)
+ throws ServiceException;
+
+ public abstract List queryList(String paramString, List paramList, int[] paramArrayOfInt, Class paramClass)
+ throws ServiceException;
+
+ public abstract List> queryList(String paramString)
+ throws ServiceException;
+
+ public abstract List queryList(String paramString, Class paramClass)
+ throws ServiceException;
+
+ public abstract List> queryList(String paramString, Object... paramVarArgs)
+ throws ServiceException;
+
+ public abstract List queryList(String paramString, Class paramClass, Object... paramVarArgs)
+ throws ServiceException;
+
+ public abstract List queryList(String paramString, List paramList, Class paramClass)
+ throws ServiceException;
+
+ public abstract List queryList(String paramString, List paramList, RowMapper paramRowMapper)
+ throws ServiceException;
+
+ public abstract T queryOneReocrd(String paramString, Class paramClass)
+ throws ServiceException;
+
+ public abstract T queryOneReocrd(String paramString, RowMapper paramRowMapper)
+ throws ServiceException;
+
+ public abstract T queryOneReocrd(String paramString, List paramList, Class paramClass)
+ throws ServiceException;
+
+ public abstract T queryOneReocrd(String paramString, List paramList, RowMapper paramRowMapper)
+ throws ServiceException;
+
+ public abstract T queryOneReocrd(String paramString, List paramList, int[] paramArrayOfInt, Class paramClass)
+ throws ServiceException;
+
+ public abstract T queryOneReocrd(String paramString, List paramList, int[] paramArrayOfInt, RowMapper paramRowMapper)
+ throws ServiceException;
+
+ public abstract int update(String paramString)
+ throws ServiceException;
+
+ public abstract int updateJdbc(String paramString, Object... paramVarArgs)
+ throws ServiceException;
+
+ public abstract int update(String paramString, List paramList)
+ throws ServiceException;
+
+ public abstract int update(String paramString, List paramList, int[] paramArrayOfInt)
+ throws ServiceException;
+
+ public abstract Map call(String paramString, boolean paramBoolean, Map paramMap, List paramList, List paramList1)
+ throws ServiceException;
+
+ public abstract Map call(String paramString, boolean paramBoolean, Map paramMap, List paramList)
+ throws ServiceException;
+
+ public abstract String keyCreate(String paramString, Character paramCharacter)
+ throws ServiceException;
+
+ public abstract long getSeqByName(String paramString)
+ throws ServiceException;
+
+ public abstract String getIdBySeq(Character paramCharacter, long paramLong)
+ throws ServiceException;
+
+ public abstract String keyCreatePad15Bit(String paramString, Character paramCharacter)
+ throws ServiceException;
+}
+
diff --git a/src/main/java/com/kyrie/system/mybatis/service/impl/DefaultService.java b/src/main/java/com/kyrie/system/mybatis/service/impl/DefaultService.java
new file mode 100644
index 0000000000000000000000000000000000000000..f383b8ab3651823cce2334e9d953e9dd457808aa
--- /dev/null
+++ b/src/main/java/com/kyrie/system/mybatis/service/impl/DefaultService.java
@@ -0,0 +1,525 @@
+package com.kyrie.system.mybatis.service.impl;
+
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import com.kyrie.system.mybatis.dao.StoredProcedureHandler;
+import com.kyrie.system.mybatis.service.IDefaultService;
+import com.kyrie.system.mybatis.execption.ServiceException;
+import org.apache.commons.lang3.time.FastDateFormat;
+import org.apache.ibatis.session.RowBounds;
+import org.apache.ibatis.session.SqlSession;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.SqlOutParameter;
+import org.springframework.jdbc.core.SqlParameter;
+import org.springframework.jdbc.object.StoredProcedure;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/***
+ * @author wuxiang
+ * @date 2020-04-06
+ * 封装mybatis数据库通用方法
+ */
+@Service("defaultService")
+public class DefaultService implements IDefaultService {
+ @Resource(name = "sqlSession")
+ private SqlSession session;
+
+ @Autowired
+ JdbcTemplate jdbcTemplate;
+
+ public static final int BATCH_SIZE = 5000;
+
+ private IDefaultService fallback = null;
+
+ private List> fallbackExceptions = null;
+
+ public static final long INITVAL_12 = 100000000000L;
+
+ public static final long INITVAL_13 = 1000000000000L;
+
+ public static final long INITVAL_7 = 1000000L;
+
+ public static final long INITVAL_8 = 10000000L;
+
+ /*public void setJdbcTemplate(@Autowired JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }*/
+
+ @Override
+ public int insert(String statementName, Object param)
+ throws ServiceException {
+ try {
+ return this.session.insert(statementName, param);
+ } catch (Exception e) {
+ throw new ServiceException(" 插入失败", e);
+ }
+ }
+
+ @Override
+ public void batchUpdate(String sql, List batchArgs, int[] argTypes) throws ServiceException {
+ try {
+ int fromIndex = 0;
+ int toIndex = 5000;
+ while (fromIndex != batchArgs.size()) {
+ if (toIndex > batchArgs.size()) {
+ toIndex = batchArgs.size();
+ }
+ this.jdbcTemplate.batchUpdate(sql, batchArgs.subList(fromIndex, toIndex), argTypes);
+ fromIndex = toIndex;
+ toIndex += 5000;
+ if (toIndex > batchArgs.size()) {
+ toIndex = batchArgs.size();
+ }
+ }
+ } catch (Exception e) {
+ throw new ServiceException(" 批量更新失败", e);
+ }
+ }
+
+ @Override
+ public int delete(String statementName, Object param) throws ServiceException {
+ try {
+ return this.session.delete(statementName, param);
+ } catch (Exception e) {
+ throw new ServiceException(" 删除失败", e);
+ }
+ }
+
+ @Override
+ public int update(String statementName, Object param) throws ServiceException {
+ try {
+ return this.session.update(statementName, param);
+ } catch (Exception e) {
+ throw new ServiceException(" 更新失败", e);
+ }
+ }
+
+ @Override
+ public List selectList(String statementName) throws ServiceException {
+ try {
+ return this.session.selectList(statementName);
+ } catch (Exception e) {
+ if (this.fallbackExceptions != null) {
+ for (Class c : this.fallbackExceptions) {
+ if (c.isAssignableFrom(e.getClass())) {
+ return this.fallback.selectList(statementName);
+ }
+ }
+ }
+ throw new ServiceException(" 查询失败", e);
+ }
+ }
+ @Override
+ public List> queryList(String sql, List args, int[] types) {
+ try {
+ return this.jdbcTemplate.queryForList(sql, args != null ? args.toArray() : null, types);
+ } catch (DataAccessException dex) {
+ throw new ServiceException(" 查询失败", dex);
+ }
+ }
+ @Override
+ public List queryList(String sql, List args, int[] types, Class clazz) {
+ try {
+ return this.jdbcTemplate.queryForList(sql, args != null ? args.toArray() : null, types, clazz);
+ } catch (DataAccessException dex) {
+ throw new ServiceException(" 查询失败", dex);
+ }
+ }
+ @Override
+ public List> queryList(String sql) {
+ try {
+ return this.jdbcTemplate.queryForList(sql);
+ } catch (DataAccessException dex) {
+ throw new ServiceException(" 查询失败", dex);
+ }
+ }
+ @Override
+ public List queryList(String sql, Class clazz) {
+ try {
+ return this.jdbcTemplate.queryForList(sql, clazz);
+ } catch (DataAccessException dex) {
+ throw new ServiceException(" 查询失败", dex);
+ }
+ }
+ @Override
+ public List> queryList(String sql, Object... args) {
+ try {
+ return this.jdbcTemplate.queryForList(sql, args);
+ } catch (DataAccessException dex) {
+ throw new ServiceException("查询失败", dex);
+ }
+ }
+ @Override
+ public List queryList(String sql, Class clazz, Object... args) {
+ try {
+ return this.jdbcTemplate.queryForList(sql, clazz, args);
+ } catch (DataAccessException dex) {
+ throw new ServiceException("查询失败", dex);
+ }
+ }
+ @Override
+ public List queryList(String sql, List args, Class clazz) {
+ try {
+ return this.jdbcTemplate.queryForList(sql, args != null ? args.toArray() : null, clazz);
+ } catch (DataAccessException dex) {
+ throw new ServiceException("查询失败", dex);
+ }
+ }
+ @Override
+ public List queryList(String sql, List args, RowMapper rowMapper)
+ throws ServiceException {
+ try {
+ return this.jdbcTemplate.query(sql, args != null ? args.toArray() : null, rowMapper);
+ } catch (DataAccessException dex) {
+ throw new ServiceException("查询失败", dex);
+ }
+ }
+ @Override
+ public T queryOneReocrd(String sql, Class clazz) {
+ try {
+ return (T) this.jdbcTemplate.queryForObject(sql, clazz);
+ } catch (EmptyResultDataAccessException dex) {
+ return null;
+ } catch (DataAccessException dex) {
+ throw new ServiceException("查询失败", dex);
+ }
+ }
+ @Override
+ public T queryOneReocrd(String sql, RowMapper rowMapper) {
+ try {
+ return (T) this.jdbcTemplate.queryForObject(sql, rowMapper);
+ } catch (EmptyResultDataAccessException dex) {
+ return null;
+ } catch (DataAccessException dex) {
+ throw new ServiceException("查询失败", dex);
+ }
+ }
+ @Override
+ public T queryOneReocrd(String sql, List args, Class clazz) {
+ try {
+ return (T) this.jdbcTemplate.queryForObject(sql, args != null ? args.toArray() : null, clazz);
+ } catch (EmptyResultDataAccessException dex) {
+ return null;
+ } catch (DataAccessException dex) {
+ throw new ServiceException("查询失败", dex);
+ }
+ }
+ @Override
+ public T queryOneReocrd(String sql, List args, RowMapper rowMapper) {
+ try {
+ return (T) this.jdbcTemplate.queryForObject(sql, args != null ? args.toArray() : null, rowMapper);
+ } catch (EmptyResultDataAccessException dex) {
+ return null;
+ } catch (DataAccessException dex) {
+ throw new ServiceException("查询失败", dex);
+ }
+ }
+ @Override
+ public T queryOneReocrd(String sql, List args, int[] argTypes, Class clazz) {
+ try {
+ return (T) this.jdbcTemplate.queryForObject(sql, args != null ? args.toArray() : null, argTypes, clazz);
+ } catch (EmptyResultDataAccessException dex) {
+ return null;
+ } catch (DataAccessException dex) {
+ throw new ServiceException("查询失败", dex);
+ }
+ }
+ @Override
+ public T queryOneReocrd(String sql, List args, int[] argTypes, RowMapper rowMapper) {
+ try {
+ return (T) this.jdbcTemplate.queryForObject(sql, args != null ? args.toArray() : null, argTypes, rowMapper);
+ } catch (EmptyResultDataAccessException dex) {
+ return null;
+ } catch (DataAccessException dex) {
+ throw new ServiceException("查询失败", dex);
+ }
+ }
+ @Override
+ public int update(String sql) {
+ try {
+ return this.jdbcTemplate.update(sql);
+ } catch (DataAccessException dex) {
+ throw new ServiceException("更新失败", dex);
+ }
+ }
+ @Override
+ public int updateJdbc(String sql, Object... args) {
+ try {
+ return this.jdbcTemplate.update(sql, args);
+ } catch (DataAccessException dex) {
+ throw new ServiceException("更新失败", dex);
+ }
+ }
+ @Override
+ public int update(String sql, List args) {
+ try {
+ return this.jdbcTemplate.update(sql, args != null ? args.toArray() : null);
+ } catch (DataAccessException dex) {
+ throw new ServiceException("更新失败", dex);
+ }
+ }
+ @Override
+ public int update(String sql, List args, int[] argTypes) {
+ try {
+ return this.jdbcTemplate.update(sql, args != null ? args.toArray() : null, argTypes);
+ } catch (DataAccessException dex) {
+ throw new ServiceException("更新失败", dex);
+ }
+ }
+ @Override
+ public Map call(String name, boolean isFunction, Map procedureParamMap, List sqlInParameters, List sqlOutParameter) {
+ try {
+ StoredProcedure storedProcedure = new StoredProcedureHandler(this.jdbcTemplate, name);
+ if ((sqlInParameters != null) && (!sqlInParameters.isEmpty())) {
+ for (SqlParameter sqlParameter : sqlInParameters) {
+ storedProcedure.declareParameter(sqlParameter);
+ }
+ }
+ if ((sqlOutParameter != null) && (!sqlOutParameter.isEmpty())) {
+ for (SqlOutParameter sqlParameter : sqlOutParameter) {
+ storedProcedure.declareParameter(sqlParameter);
+ }
+ }
+ storedProcedure.setFunction(isFunction);
+ storedProcedure.compile();
+ return storedProcedure.execute(procedureParamMap);
+ } catch (DataAccessException dex) {
+ throw new ServiceException("存过执行失败", dex);
+ }
+ }
+ @Override
+ public Map call(String name, boolean isFunction, Map procedureParamMap, List sqlParameters)
+ throws ServiceException {
+ try {
+ StoredProcedure storedProcedure = new StoredProcedureHandler(this.jdbcTemplate, name);
+ if ((sqlParameters != null) && (!sqlParameters.isEmpty())) {
+ for (SqlParameter sqlParameter : sqlParameters) {
+ storedProcedure.declareParameter(sqlParameter);
+ }
+ }
+ storedProcedure.setFunction(isFunction);
+ storedProcedure.compile();
+ return storedProcedure.execute(procedureParamMap);
+ } catch (DataAccessException dex) {
+ throw new ServiceException("存过执行失败", dex);
+ }
+ }
+ @Override
+ public List selectList(String statementName, Object param, int offset, int limit)
+ throws ServiceException {
+ try {
+ if (limit < 0) {
+ return selectList(statementName, param);
+ }
+ return this.session.selectList(statementName, param, new RowBounds(offset, limit));
+ } catch (Exception e) {
+ if (this.fallbackExceptions != null) {
+ for (Class c : this.fallbackExceptions) {
+ if (c.isAssignableFrom(e.getClass())) {
+ return this.fallback.selectList(statementName, param, offset, limit);
+ }
+ }
+ }
+ throw new ServiceException("查询失败", e);
+ }
+ }
+ @Override
+ public List selectList(String statementName, Object param)
+ throws ServiceException {
+ try {
+ return this.session.selectList(statementName, param);
+ } catch (Exception e) {
+ if (this.fallbackExceptions != null) {
+ for (Class c : this.fallbackExceptions) {
+ if (c.isAssignableFrom(e.getClass())) {
+ return this.fallback.selectList(statementName, param);
+ }
+ }
+ }
+ throw new ServiceException("查询失败", e);
+ }
+ }
+ @Override
+ public T selectOne(String statementName, Object param)
+ throws ServiceException {
+ try {
+ return (T) this.session.selectOne(statementName, param);
+ } catch (Exception e) {
+ if (this.fallbackExceptions != null) {
+ for (Class c : this.fallbackExceptions) {
+ if (c.isAssignableFrom(e.getClass())) {
+ return (T) this.fallback.selectOne(statementName, param);
+ }
+ }
+ }
+ throw new ServiceException("查询失败", e);
+ }
+ }
+ @Override
+ public Object[] getCommonPaged(String queryStatement, String countStatement, Object param, int offset, int limit)
+ throws ServiceException {
+ try {
+ Object[] obj = new Object[2];
+ obj[0] = selectList(queryStatement, param, offset, limit);
+ obj[1] = selectOne(countStatement, param);
+ return obj;
+ } catch (Exception e) {
+ if (this.fallbackExceptions != null) {
+ for (Class c : this.fallbackExceptions) {
+ if (c.isAssignableFrom(e.getClass())) {
+ return this.fallback.getCommonPaged(queryStatement, countStatement, param, offset, limit);
+ }
+ }
+ }
+ throw new ServiceException("查询失败", e);
+ }
+ }
+
+
+ @Override
+ public int[] batchUpdate(String... sql)
+ throws ServiceException {
+ try {
+ return this.jdbcTemplate.batchUpdate(sql);
+ } catch (Exception e) {
+ throw new ServiceException("批量更新失败", e);
+ }
+ }
+ @Override
+ public void batchUpdate(String sql, List batchArgs)
+ throws ServiceException {
+ try {
+ int fromIndex = 0;
+ int toIndex = 5000;
+ while (fromIndex < batchArgs.size()) {
+ if (toIndex > batchArgs.size()) {
+ toIndex = batchArgs.size();
+ }
+ this.jdbcTemplate.batchUpdate(sql, batchArgs.subList(fromIndex, toIndex));
+ fromIndex = toIndex;
+ toIndex += 5000;
+ }
+ } catch (Exception e) {
+ throw new ServiceException("批量更新失败", e);
+ }
+ }
+ @Override
+ public void batchUpdate(String sql, BatchPreparedStatementSetter pss)
+ throws ServiceException {
+ try {
+ this.jdbcTemplate.batchUpdate(sql, pss);
+ } catch (Exception e) {
+ throw new ServiceException("批量更新失败", e);
+ }
+ }
+ @Override
+ public void batchUpdate(String sql, Collection batchArgs, int batchSize, ParameterizedPreparedStatementSetter ppss)
+ throws ServiceException {
+ try {
+ this.jdbcTemplate.batchUpdate(sql, batchArgs, batchSize, ppss);
+ } catch (Exception e) {
+ throw new ServiceException("批量更新失败", e);
+ }
+ }
+ @Override
+ public String keyCreate(String sequence, Character prefix)
+ throws ServiceException {
+ try {
+ Long seqId = (Long) this.jdbcTemplate.queryForObject("select " + sequence + ".nextval from dual", Long.class);
+ return format20bit(prefix, seqId.longValue());
+ } catch (Exception e) {
+ throw new ServiceException("seqId创建失败", e);
+ }
+ }
+ @Override
+ public String keyCreatePad15Bit(String sequence, Character prefix)
+ throws ServiceException {
+ try {
+ Long seqId = (Long) this.jdbcTemplate.queryForObject("select " + sequence + ".nextval from dual", Long.class);
+ return format15bit(prefix, seqId.longValue());
+ } catch (Exception e) {
+ throw new ServiceException("seqId创建失败", e);
+ }
+ }
+
+ private String format(long initval, long number) {
+ return String.valueOf(initval + number).substring(1);
+ }
+
+ public static final FastDateFormat df = FastDateFormat.getInstance("yyyyMMdd");
+
+ private String format20bit(Character prefix, long number) {
+ return getIdBySeq(prefix == null ? "" : prefix.toString(), String.valueOf(number));
+ }
+
+ public static String getIdBySeq(String seqId) {
+ StringBuffer seqBuf = new StringBuffer();
+ if ((seqId != null) && (seqId.length() > 0) && (seqId.length() < 13)) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
+ seqBuf.append(df.format(new Date()));
+ for (int i = 0; i < 12 - seqId.length(); i++) {
+ seqBuf.append("0");
+ }
+ seqBuf.append(seqId);
+ } else if ((seqId != null) && (seqId.length() > 12)) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
+ seqBuf.append(df.format(new Date()));
+ seqBuf.append(seqId.substring(seqId.length() - 12));
+ }
+ return seqBuf.toString();
+ }
+
+ public static String getIdBySeq(String prefix, String seqId) {
+ StringBuffer seqBuf = new StringBuffer(prefix);
+ if ((seqId != null) && (seqId.length() > 0) && (seqId.length() + prefix.length() < 13)) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
+ seqBuf.append(df.format(new Date()));
+ for (int i = 0; i < 12 - prefix.length() - seqId.length(); i++) {
+ seqBuf.append("0");
+ }
+ seqBuf.append(seqId);
+ } else if ((seqId != null) && (seqId.length() + prefix.length() > 12)) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
+ seqBuf.append(df.format(new Date()));
+ seqBuf.append(seqId.substring(seqId.length() + prefix.length() - 12));
+ }
+ return seqBuf.toString();
+ }
+
+ private String format15bit(Character prefix, long number) {
+ number %= (prefix == null ? 10000000L : 1000000L);
+ String num = format(prefix == null ? 10000000L : 1000000L, number);
+ String datestr = df.format(new Date());
+ return (prefix == null ? "" : prefix) + datestr + num;
+ }
+ @Override
+ public long getSeqByName(String sequence)
+ throws ServiceException {
+ try {
+ return ((Long) this.jdbcTemplate.queryForObject("select " + sequence + ".nextval from dual", Long.class)).longValue();
+ } catch (Exception e) {
+ throw new ServiceException("seqId创建失败", e);
+ }
+ }
+ @Override
+ public String getIdBySeq(Character prefix, long number)
+ throws ServiceException {
+ try {
+ return format20bit(prefix, number);
+ } catch (Exception e) {
+ throw new ServiceException("seqId创建失败", e);
+ }
+ }
+}
+
diff --git a/src/main/java/com/kyrie/utils/ConvertUtils.java b/src/main/java/com/kyrie/utils/ConvertUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4592394fe91d3f1033ed52e77fb7e4fd3c461b7
--- /dev/null
+++ b/src/main/java/com/kyrie/utils/ConvertUtils.java
@@ -0,0 +1,47 @@
+package com.kyrie.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/***
+ * 描述: 类型转换工具类
+ *
+ * @author wuxiang
+ * @date 2020-04-12 14:43
+ */
+public class ConvertUtils {
+
+ /**
+ * 把一个字符串转换成bean对象(by FastJson)
+ * @param str String
+ * @param T
+ * @return T
+ */
+ public static T stringToBean(String str, Class clazz) {
+ if(str == null || str.length() <= 0 || clazz == null) {
+ return null;
+ }
+ if(clazz == int.class || clazz == Integer.class) {
+ return (T)Integer.valueOf(str);
+ }else if(clazz == String.class) {
+ return (T)str;
+ }else if(clazz == long.class || clazz == Long.class) {
+ return (T)Long.valueOf(str);
+ }else {
+ return JSON.toJavaObject(JSON.parseObject(str), clazz);
+ }
+ }
+
+ /**
+ * Object类型转换为json String类型(by Gson)
+ * @param object Object
+ * @return String
+ */
+ public static String toJson(Object object) {
+ GsonBuilder gsonBuilder = new GsonBuilder();
+ gsonBuilder.setPrettyPrinting();
+ Gson gson = gsonBuilder.create();
+ return gson.toJson(object);
+ }
+}
diff --git a/src/main/java/com/kyrie/utils/GlobalConstants.java b/src/main/java/com/kyrie/utils/GlobalConstants.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7af75169be065000fff639108138a89733bd686
--- /dev/null
+++ b/src/main/java/com/kyrie/utils/GlobalConstants.java
@@ -0,0 +1,70 @@
+package com.kyrie.utils;
+
+/***
+ * 描述: 全局常量配置类
+ *
+ * @author wuxiang
+ * @date 2020-04-06 16:31
+ */
+public class GlobalConstants {
+
+ // 接口成功调用resultCode
+ public static final String SUCCESS_CODE = "1";
+
+ // 接口成功失败resultCode
+ public static final String FAIL_CODE = "0";
+
+ // 无认证数据字典类型
+ public static final String ANON_TYPE_CODE = "shiroUrl";
+
+ // 无认证数据字典值编码
+ public static final String ANON_VAL_CODE = "anno";
+
+ // jwt claim
+ public static final String JWT_CLAIM = "user";
+
+ // 安全token
+ public static final String SECURITY_TOKEN = "token";
+
+ // 越权访问错误信息
+ public static final String CROSS_ACCESS_MSG = "请求被拦截,拦截原因:当前请求存在越权访问的安全风险。";
+
+ // token认证失败
+ public static final String TOKEN_LOSS_MSG = "token认证失败,失败原因:token丢失。请重新登录。";
+
+ // 受限制请求提示
+ public static final String LIMITED_REQUEST = "受限制的请求,请核实用户权限!";
+
+ // 用户访问标识userNo,不带此标识会被拦截掉
+ public static final String BUSINESS_REQUEST_ID = "userNo";
+
+ // redis缓存失效时间
+ public static final int REDIS_EXPIRE_TIME = 300;// redis缓存失效时间
+
+ // 全局数据库mapper目录
+ public static final String NAME_SPACE = "com.kyrie.config.";
+
+ // 全局数据字典配置
+ public static final String TYPE_2097 = "2097";
+
+ // jwt token 失效时间
+ public static final String TYPE_2097_JWTTOKEN_EXPIRE_TIME = "jwtToken_expire_time";
+
+ // jwt token 密钥
+ public static final String TYPE_2097_SECRET = "secretCode";
+
+ /**################################## kafka相关常量配置 ##################################*/
+ public final static String AUTO_FLUSH_NAME = "autoFlush";
+ public final static String TOPIC_NAME = "topic";
+ public final static String KEY_SERIALIZER = "key-serializer";
+ public final static String VALUE_SERIALIZER = "value-serializer";
+
+
+ /**################################## kafka相关常量配置 ##################################*/
+
+
+
+
+
+
+}
diff --git a/src/main/java/com/kyrie/utils/IActionContext.java b/src/main/java/com/kyrie/utils/IActionContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b337373cc4023a30cbcab350a8483f8c5a67ef8
--- /dev/null
+++ b/src/main/java/com/kyrie/utils/IActionContext.java
@@ -0,0 +1,30 @@
+package com.kyrie.utils;
+
+import com.kyrie.security.jwt.JWTUtil;
+import com.kyrie.vo.UserInfoVO;
+import org.apache.shiro.SecurityUtils;
+
+/***
+ * 描述: 全局获取当前用户信息类
+ *
+ * @author wuxiang
+ * @date 2020-04-16 15:53
+ */
+public class IActionContext {
+
+ /**
+ * 获取用户姓名
+ */
+ public static String getUserNo() {
+ return getUser().getUserNo();
+ }
+
+ /**
+ * 获取用户信息
+ */
+ public static UserInfoVO getUser() {
+ UserInfoVO principal = ConvertUtils.stringToBean(
+ JWTUtil.getUserInfo(SecurityUtils.getSubject().getPrincipal().toString()), UserInfoVO.class);
+ return principal;
+ }
+}
diff --git a/src/main/java/com/kyrie/utils/OperationCommUtil.java b/src/main/java/com/kyrie/utils/OperationCommUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d8d346857a14c70ee5caf2a64a3b62612545418
--- /dev/null
+++ b/src/main/java/com/kyrie/utils/OperationCommUtil.java
@@ -0,0 +1,108 @@
+package com.kyrie.utils;
+
+import com.alibaba.druid.util.StringUtils;
+import com.kyrie.dto.OperateDictionariesDto;
+import com.kyrie.system.mybatis.execption.ServiceException;
+import com.kyrie.system.mybatis.service.IDefaultService;
+import com.kyrie.vo.TOperationCommTypeVal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import redis.clients.jedis.JedisCluster;
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/***
+ * 描述: 数据字典缓存操作工具类
+ *
+ * @author wuxiang
+ * @date 2020-04-14 11:04
+ */
+@Component("operationCommUtil")
+public class OperationCommUtil {
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Autowired
+ private JedisCluster jedisCluster;
+
+ @Resource(name = "defaultService")
+ private IDefaultService defaultService;
+
+
+ /**
+ * 获取缓存列表:通过typeId+valId查询
+ */
+ public List getDictList(String typeId,String valId) throws ServiceException {
+ return getDictionariesFromDb(typeId,valId);
+ }
+
+ /**
+ * 从数据库中获取字典信息
+ */
+ private List getDictionariesFromDb(String typeId, String valId) throws ServiceException {
+ Map map = new HashMap<>();
+ map.put("typeId",typeId);
+ map.put("valId",valId);
+ List list = defaultService.selectList(GlobalConstants.NAME_SPACE + "getDictionariesFromDb",map);
+ return list;
+ }
+
+ /**
+ * 从数据库中获取字典值
+ */
+ private String getValueFromDb(String typeId, String valId) throws ServiceException {
+ Map map = new HashMap<>();
+ map.put("typeId",typeId);
+ map.put("valId",valId);
+ return defaultService.selectOne(GlobalConstants.NAME_SPACE + "getValueFromDb",map);
+ }
+
+
+ /**
+ * 获取缓存字典值valName
+ */
+ public String getDictValue(String typeId, String valId, String defaultValue) {
+ // 首先取缓存
+ String valueName = jedisCluster.get(typeId +":" + valId);
+ if (!StringUtils.isEmpty(valueName)) {
+ return valueName;
+ }
+ // 缓存没有就从数据库获取
+ valueName = getValueFromDb(typeId,valId);
+ if (!StringUtils.isEmpty(valueName)) {
+ jedisCluster.set(typeId+":"+valId,valueName);
+ } else {
+ valueName = defaultValue;
+ }
+ return valueName;
+ }
+
+ /**
+ * 新增数据字典
+ */
+ public int addDictonaries(OperateDictionariesDto operateDictionariesDto) throws ServiceException {
+ String seqId = UUID.randomUUID().toString();
+ operateDictionariesDto.setSeqId(seqId);
+ return defaultService.insert(GlobalConstants.NAME_SPACE + "addDictonaries", operateDictionariesDto);
+ }
+
+ /**
+ * 删除数据字典
+ */
+ public int delDictonaries(OperateDictionariesDto operateDictionariesDto) throws ServiceException {
+ return defaultService.insert(GlobalConstants.NAME_SPACE + "delDictonaries", operateDictionariesDto);
+ }
+
+ /**
+ * 更新数据字典
+ */
+ public int updDictonaries(OperateDictionariesDto operateDictionariesDto) throws ServiceException {
+ return defaultService.update(GlobalConstants.NAME_SPACE + "updDictonaries", operateDictionariesDto);
+ }
+
+}
diff --git a/src/main/java/com/kyrie/utils/RequestUtil.java b/src/main/java/com/kyrie/utils/RequestUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c0fc9d1317567be6194ff32e102e854c69482aa
--- /dev/null
+++ b/src/main/java/com/kyrie/utils/RequestUtil.java
@@ -0,0 +1,63 @@
+package com.kyrie.utils;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+/***
+ * 描述:
+ *
+ * @author wuxiang
+ * @date 2020-04-09 23:54
+ */
+public class RequestUtil {
+
+ /**
+ * 从request中获得参数Map,并返回可读的Map
+ */
+ public static Map getParameterMap(HttpServletRequest request){
+ //参数Map
+ Map properties = request.getParameterMap();
+ //返回值Map
+ Map returnMap = new HashMap();
+ Iterator it = properties.keySet().iterator();
+ String name = "";
+ String value = "";
+ while(it.hasNext()){
+ String key = it.next();
+ Object valueObj = properties.get(key);
+ if(null == valueObj){
+ value = "";
+ }else if(valueObj instanceof String[]){
+ String[] values = (String[]) valueObj;
+ for(int i = 0; i trimParameter(Map param){
+ //返回值Map
+ Map returnMap = new HashMap();
+ Iterator it = param.keySet().iterator();
+ String value = "";
+ while(it.hasNext()){
+ String key = it.next();
+ Object valueObj = param.get(key);
+ if(null == valueObj){
+ value = "";
+ }else{
+ value = valueObj.toString().trim();
+ }
+ returnMap.put(key, value);
+ }
+ return returnMap;
+ }
+}
+
diff --git a/src/main/java/com/kyrie/utils/SpringContextBean.java b/src/main/java/com/kyrie/utils/SpringContextBean.java
new file mode 100644
index 0000000000000000000000000000000000000000..49aa10f2410e883c9aae252d684bd0c51af4d3ec
--- /dev/null
+++ b/src/main/java/com/kyrie/utils/SpringContextBean.java
@@ -0,0 +1,10 @@
+package com.kyrie.utils;
+
+import org.springframework.context.annotation.DependsOn;
+
+@DependsOn("springContextHolder")
+public class SpringContextBean {
+ public static T getBean(Class clazz){
+ return (T)SpringContextHolder.getBean(clazz);
+ }
+}
diff --git a/src/main/java/com/kyrie/utils/SpringContextHolder.java b/src/main/java/com/kyrie/utils/SpringContextHolder.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c2c1e90220e2460ae2b27e3f6ebae4e741bf91e
--- /dev/null
+++ b/src/main/java/com/kyrie/utils/SpringContextHolder.java
@@ -0,0 +1,46 @@
+package com.kyrie.utils;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/***
+ * 全局上下文
+ * @author wuxiang
+ *
+ */
+@Component("springContextHolder")
+public class SpringContextHolder implements ApplicationContextAware{
+
+ private static ApplicationContext application;
+
+ @Override
+ public void setApplicationContext(ApplicationContext application) throws BeansException {
+ SpringContextHolder.application = application;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T getBean(String name){
+ AssertApplication();
+ return (T)application.getBean(name);
+ }
+
+ public static T getBean(Class clazz){
+ AssertApplication();
+ return (T)application.getBean(clazz);
+ }
+
+ public void setApplicaiont(ApplicationContext applicaiont) {
+ SpringContextHolder.application = applicaiont;
+ }
+
+
+
+ private static void AssertApplication(){
+ if (application == null) {
+ throw new RuntimeException("SpringContextHolder中application为空,请检查是否注入");
+ }
+ }
+
+}
diff --git a/src/main/java/com/kyrie/vo/DataSourceEnum.java b/src/main/java/com/kyrie/vo/DataSourceEnum.java
new file mode 100644
index 0000000000000000000000000000000000000000..5afac67e86a38c23d840199e6f6a06eb98eaf466
--- /dev/null
+++ b/src/main/java/com/kyrie/vo/DataSourceEnum.java
@@ -0,0 +1,46 @@
+package com.kyrie.vo;
+
+/***
+ * 描述: 数据源枚举类
+ *
+ * @author wuxiang
+ * @date 2020-04-21 17:43
+ */
+public enum DataSourceEnum {
+
+ /**
+ * 业务库
+ */
+ BUSINESS_DB("business"),
+
+ /**
+ * 配置库
+ */
+ CONFIG_DB("config"),
+
+ /**
+ * 路由库
+ */
+ ROUTE_DB("route"),
+
+ /**
+ * 报表库
+ */
+ REPORT_DB("report"),
+
+ /**
+ * 归档库
+ */
+ ARC_DB("arc");
+
+ private String value;
+
+ DataSourceEnum(String value) {
+ this.value = value;
+ }
+
+ public String getValue(){
+ return value;
+ }
+
+}
diff --git a/src/main/java/com/kyrie/vo/DictOperateEnum.java b/src/main/java/com/kyrie/vo/DictOperateEnum.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b1de3efd64cab1a852a216ae64ca45f152d9d3a
--- /dev/null
+++ b/src/main/java/com/kyrie/vo/DictOperateEnum.java
@@ -0,0 +1,36 @@
+package com.kyrie.vo;
+
+/***
+ * 描述: 数据字典操作方式枚举类
+ *
+ * @author wuxiang
+ * @date 2020-04-21 17:43
+ */
+public enum DictOperateEnum {
+
+ /**
+ * 新增字典
+ */
+ DICT_ADD("add"),
+
+ /**
+ * 删除字典
+ */
+ DICT_DEL("delete"),
+
+ /**
+ * 更新字典
+ */
+ DICT_UPD("update");
+
+ private String value;
+
+ DictOperateEnum(String value) {
+ this.value = value;
+ }
+
+ public String getValue(){
+ return value;
+ }
+
+}
diff --git a/src/main/java/com/kyrie/vo/LoginLogVO.java b/src/main/java/com/kyrie/vo/LoginLogVO.java
new file mode 100644
index 0000000000000000000000000000000000000000..b373e70d45b1765a0a370f6e30d3f7ac2da9f53f
--- /dev/null
+++ b/src/main/java/com/kyrie/vo/LoginLogVO.java
@@ -0,0 +1,31 @@
+package com.kyrie.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/***
+ * 描述:
+ *
+ * @author wuxiang
+ * @date 2020-04-06 16:38
+ */
+@Data
+public class LoginLogVO implements Serializable {
+
+ private static final long serialVersionUID = 7253053491456999442L;
+
+ private String createTime;
+
+ private String logType;
+
+ private String ip;
+
+ private Integer id;
+
+ private String state;
+
+ private String message;
+
+ private Integer userId;
+}
diff --git a/src/main/java/com/kyrie/vo/LoginReturnBean.java b/src/main/java/com/kyrie/vo/LoginReturnBean.java
new file mode 100644
index 0000000000000000000000000000000000000000..f45d4c569511f0a7ff474809a23d301b92b8d10c
--- /dev/null
+++ b/src/main/java/com/kyrie/vo/LoginReturnBean.java
@@ -0,0 +1,30 @@
+package com.kyrie.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/***
+ * 描述: 用户登录返回信息VO
+ *
+ * @author wuxiang
+ * @date 2020-04-07 14:32
+ */
+@Data
+public class LoginReturnBean implements Serializable {
+
+
+ private static final long serialVersionUID = -6511915232912132173L;
+ private String userNo;
+
+ private String userName;
+
+ private String departmentId;
+
+ private String roleSign;
+
+ private String roleName;
+
+ private String token;
+
+}
diff --git a/src/main/java/com/kyrie/vo/ResponseBean.java b/src/main/java/com/kyrie/vo/ResponseBean.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a96799f4a3476a41285f228b14356c827bd2ac9
--- /dev/null
+++ b/src/main/java/com/kyrie/vo/ResponseBean.java
@@ -0,0 +1,90 @@
+package com.kyrie.vo;
+
+/***
+ * 描述: 接口通用返回VO
+ *
+ * @author wuxiang
+ * @date 2020-04-06 16:29:30
+ */
+public class ResponseBean {
+
+ private String resultCode;
+
+ private String resultMsg;
+
+ private T result;
+
+ private ResponseBean (T result, String resultCode, String resultMsg) {
+ this.result = result;
+ this.resultCode = resultCode;
+ this.resultMsg = resultMsg;
+ }
+
+ /***
+ * 参数校验失败的回调方法
+ * @param result 返回数据vo
+ * @param resultCode 返回resultCode
+ * @param resultMsg 返回resultMsg
+ * @return
+ */
+ public static ResponseBean notValid (T result, String resultCode, String resultMsg) {
+ return new ResponseBean(result, resultCode, resultMsg);
+ }
+
+ /***
+ * 数据库异常的回调方法
+ * @param result 返回数据vo
+ * @param resultCode 返回resultCode
+ * @param resultMsg 返回resultMsg
+ * @return
+ */
+ public static ResponseBean exception (T result, String resultCode, String resultMsg) {
+ return new ResponseBean(result, resultCode, resultMsg);
+ }
+
+ /***
+ * 成功的回调方法
+ * @param result 返回数据vo
+ * @param resultCode 返回resultCode
+ * @param resultMsg 返回resultMsg
+ * @return
+ */
+ public static ResponseBean success (T result, String resultCode, String resultMsg) {
+ return new ResponseBean(result, resultCode, resultMsg);
+ }
+
+ /***
+ * 失败的回调方法
+ * @param result 返回数据vo
+ * @param resultCode 返回resultCode
+ * @param resultMsg 返回resultMsg
+ * @return
+ */
+ public static ResponseBean fail (T result, String resultCode, String resultMsg) {
+ return new ResponseBean(result, resultCode, resultMsg);
+ }
+
+ public String getResultCode() {
+ return resultCode;
+ }
+
+ public void setResultCode(String resultCode) {
+ this.resultCode = resultCode;
+ }
+
+ public String getResultMsg() {
+ return resultMsg;
+ }
+
+ public void setResultMsg(String resultMsg) {
+ this.resultMsg = resultMsg;
+ }
+
+ public T getResult() {
+ return result;
+ }
+
+ public void setResult(T result) {
+ this.result = result;
+ }
+}
diff --git a/src/main/java/com/kyrie/vo/TOperationCommTypeVal.java b/src/main/java/com/kyrie/vo/TOperationCommTypeVal.java
new file mode 100644
index 0000000000000000000000000000000000000000..263470bab49504ad45bb123c2439e3dfd1c11629
--- /dev/null
+++ b/src/main/java/com/kyrie/vo/TOperationCommTypeVal.java
@@ -0,0 +1,41 @@
+package com.kyrie.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/***
+ * 描述: 数据字典实体VO
+ *
+ * @author wuxiang
+ * @date 2020-04-08 12:25
+ */
+@Data
+public class TOperationCommTypeVal implements Serializable {
+
+ private static final long serialVersionUID = 88339235806548762L;
+
+ private String seqId;
+
+ private String typeId;
+
+ private String typeName;
+
+ private String valId;
+
+ private String valName;
+
+ private String extVal;
+
+ private String status;
+
+ private Integer orderBy;
+
+ private String reamke;
+
+ private String createDate;
+
+ private String createPerson;
+
+
+}
diff --git a/src/main/java/com/kyrie/vo/TransLogVO.java b/src/main/java/com/kyrie/vo/TransLogVO.java
new file mode 100644
index 0000000000000000000000000000000000000000..0937491b84db60d71e69416f675142ca7556da33
--- /dev/null
+++ b/src/main/java/com/kyrie/vo/TransLogVO.java
@@ -0,0 +1,30 @@
+package com.kyrie.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/***
+ * 描述:
+ *
+ * @author wuxiang
+ * @date 2020-04-16 17:34
+ */
+@Data
+public class TransLogVO implements Serializable {
+ private static final long serialVersionUID = -2509600590043868481L;
+
+ private String logId;
+
+ private String transCode;
+
+ private String requestBody;
+
+ private String responseBody;
+
+ private String transOperator;
+
+ private String transLogDesc;
+
+ private String transTime;
+}
diff --git a/src/main/java/com/kyrie/vo/UserInfoVO.java b/src/main/java/com/kyrie/vo/UserInfoVO.java
new file mode 100644
index 0000000000000000000000000000000000000000..9fc73e14e2c434cbc1c6600f481dd994a22fa489
--- /dev/null
+++ b/src/main/java/com/kyrie/vo/UserInfoVO.java
@@ -0,0 +1,44 @@
+package com.kyrie.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/***
+ * 描述: 用户信息VO
+ *
+ * @author wuxiang
+ * @date 2020-04-07 14:32
+ */
+@Data
+public class UserInfoVO implements Serializable {
+
+ private static final long serialVersionUID = -8323890249190589223L;
+
+ private String seqId;
+
+ private String userNo;
+
+ private String userName;
+
+ private String password;
+
+ private String salt;
+
+ private String departmentId;
+
+ private String roleSign;
+
+ private String roleName;
+
+ private String isLocked;
+
+ private String ifDisplay;
+
+ private String createDate;
+
+ private String createPerson;
+
+ private String token;
+
+}
diff --git a/src/main/java/com/kyrie/vo/UserRoleVO.java b/src/main/java/com/kyrie/vo/UserRoleVO.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bad8e0abac411f932b031b79dc6d945b4dc8afe
--- /dev/null
+++ b/src/main/java/com/kyrie/vo/UserRoleVO.java
@@ -0,0 +1,31 @@
+package com.kyrie.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/***
+ * 描述: 用户角色VO
+ *
+ * @author wuxiang
+ * @date 2020-04-07 23:21
+ */
+@Data
+public class UserRoleVO implements Serializable {
+
+ private static final long serialVersionUID = 5860763071247277860L;
+
+ private String seqId;
+
+ private String roleId;
+
+ private String roleSign;
+
+ private String roleName;
+
+ private String createDate;
+
+ private String createPerson;
+
+ private String ifUseAble;
+}
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
new file mode 100644
index 0000000000000000000000000000000000000000..69bd04ce97b08db6d4959db275fc94fc1b13f4e4
--- /dev/null
+++ b/src/main/resources/application-dev.yml
@@ -0,0 +1,47 @@
+server:
+ servlet:
+ context-path: /
+ port: 31001
+
+
+spring:
+ #数据库的配置
+ datasource:
+ initialSize: 5
+ minIdle: 5
+ maxActive: 20
+ maxWait: 60000
+ timeBetweenEvictionRunsMillis: 60000
+ minEvictableIdleTimeMillis: 300000
+ validationQuery: SELECT 'x' FROM DUAL
+ testWhileIdle: true
+ testOnBorrow: false
+ testOnReturn: false
+ poolPreparedStatements: true
+ maxOpenPreparedStatements: 20
+ filters: stat,wall,log4j
+ connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+ nodes[0]:
+ name: dev-1 #dev数据库1
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+ nodes[1]:
+ name: dev-2 #dev数据库2
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+ nodes[2]:
+ name: dev-3 #dev数据库3
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+
+#使用assembly打包后的配置文件在config目录下,因此需要指定在config目录下
+logging:
+ config: config/logback-spring.xml
+mybatis:
+ location: file:config/mybatis-config.xml #dev、uat、prod环境使用文件读取config目录下的配置文件
\ No newline at end of file
diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2d2813a5382f2820a515209f9b0e27fc8b5598d1
--- /dev/null
+++ b/src/main/resources/application-local.yml
@@ -0,0 +1,110 @@
+server:
+ servlet:
+ context-path: /
+ port: 31006
+
+#数据源加载类型:routing-路由多数据源、single-单数据源,name:表示当前类型的数据源可以切换哪些数据库,prefix:表示可进行的数据库操作
+kyrie:
+ datasource-config:
+ type: routing
+ name: config,business
+ prefix: add,update,sumbit,save,delete,cancel,insert
+
+#下方为单一数据源single配置
+#kyrie:
+# datasource-config:
+# type: single
+# name: config
+
+spring:
+ datasource:
+ initialSize: 5
+ minIdle: 5
+ maxActive: 20
+ maxWait: 60000
+ timeBetweenEvictionRunsMillis: 60000
+ minEvictableIdleTimeMillis: 300000
+ validationQuery: SELECT 'x' FROM DUAL
+ testWhileIdle: true
+ testOnBorrow: false
+ testOnReturn: false
+ poolPreparedStatements: true
+ maxOpenPreparedStatements: 20
+ filters: stat,wall,log4j
+ connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+ nodes[0]:
+ name: config #配置库
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/interface_common?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+ nodes[1]:
+ name: business #业务库
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+ nodes[2]:
+ name: route #路由库
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+ nodes[3]:
+ name: report #报表库
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+ nodes[4]:
+ name: arc #归档库
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+
+#使用assembly打包后的配置文件在config目录下,因此需要指定在config目录下
+logging:
+ config: classpath:logback-spring.xml
+mybatis:
+ location: classpath:mybatis-config.xml
+
+interface:
+ redis: #redis集群配置
+ soTimeout: 2000
+ connectionTimeout: 2000
+ maxAttempts: 3
+ passwd: CSpa2s_is
+ maxTotal: 10
+ maxIdle: 10
+ minIdel: 0
+ testOnBorrow: false
+ testOnIdle: true
+ testOnReturn: false
+ timeBetweenEvictionRunsMillis: 60000
+ numTestsPerEvictionRun: -1
+ jedis[0]:
+ host: 127.0.0.1
+ port: 6379
+ jedis[1]:
+ host: 127.0.0.1
+ port: 6380
+ jedis[2]:
+ host: 127.0.0.1
+ port: 6381
+ kafka: #kafka集群配置
+ bootstrap-servers: http://127.0.0.1:9092,http://127.0.0.1:9093,http://127.0.0.1:9094
+ producer:
+ buffer-memory: 40960
+ max-block: 6000
+ retries: 0
+ batch-size: 4096
+ linger: 1
+ client-id: producer.client.id.kafka
+ consumer:
+ group-id: ci-data
+ enable-auto-commit: true
+ auto-commit-interval: 100
+ session-timeout: 9000
+ auto-offset-reset: latest
+ heartbeat-interval: 3000 #心跳时间应设置为session-timeout的1/3
\ No newline at end of file
diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7b0ca431290442a2b4786f9534deb04bc866cb75
--- /dev/null
+++ b/src/main/resources/application-prod.yml
@@ -0,0 +1,47 @@
+server:
+ servlet:
+ context-path: /
+ port: 31001
+
+
+spring:
+ #数据库的配置
+ datasource:
+ initialSize: 5
+ minIdle: 5
+ maxActive: 20
+ maxWait: 60000
+ timeBetweenEvictionRunsMillis: 60000
+ minEvictableIdleTimeMillis: 300000
+ validationQuery: SELECT 'x' FROM DUAL
+ testWhileIdle: true
+ testOnBorrow: false
+ testOnReturn: false
+ poolPreparedStatements: true
+ maxOpenPreparedStatements: 20
+ filters: stat,wall,log4j
+ connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+ nodes[0]:
+ name: uat-1 #uat数据库1
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+ nodes[1]:
+ name: uat-2 #uat数据库2
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+ nodes[2]:
+ name: uat-3 #uat数据库3
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+
+#使用assembly打包后的配置文件在config目录下,因此需要指定在config目录下
+logging:
+ config: config/logback-spring.xml
+mybatis:
+ location: file:config/mybatis-config.xml #uat、prod环境使用文件读取config目录下的配置文件
\ No newline at end of file
diff --git a/src/main/resources/application-uat.yml b/src/main/resources/application-uat.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7b0ca431290442a2b4786f9534deb04bc866cb75
--- /dev/null
+++ b/src/main/resources/application-uat.yml
@@ -0,0 +1,47 @@
+server:
+ servlet:
+ context-path: /
+ port: 31001
+
+
+spring:
+ #数据库的配置
+ datasource:
+ initialSize: 5
+ minIdle: 5
+ maxActive: 20
+ maxWait: 60000
+ timeBetweenEvictionRunsMillis: 60000
+ minEvictableIdleTimeMillis: 300000
+ validationQuery: SELECT 'x' FROM DUAL
+ testWhileIdle: true
+ testOnBorrow: false
+ testOnReturn: false
+ poolPreparedStatements: true
+ maxOpenPreparedStatements: 20
+ filters: stat,wall,log4j
+ connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+ nodes[0]:
+ name: uat-1 #uat数据库1
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+ nodes[1]:
+ name: uat-2 #uat数据库2
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+ nodes[2]:
+ name: uat-3 #uat数据库3
+ driver-class-name: com.mysql.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/edxapp?useUnicode=true&characterEncoding=utf-8
+ username: root
+ password: CSpa2s_is
+
+#使用assembly打包后的配置文件在config目录下,因此需要指定在config目录下
+logging:
+ config: config/logback-spring.xml
+mybatis:
+ location: file:config/mybatis-config.xml #uat、prod环境使用文件读取config目录下的配置文件
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a2adbbc0f6f14069b93ec7abab6381e9e528e771
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,13 @@
+spring:
+#环境自动激活
+ profiles:
+ active: @profileActive@
+ #JPA
+ jpa:
+ show-sql: true
+
+shiro:
+ anonMappings: /login;/500/**;/error
+
+kyrie:
+ loginUrl: /login
\ No newline at end of file
diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml
new file mode 100755
index 0000000000000000000000000000000000000000..e9dc39ba0f66e12cefa8e4a571852cc3e645f5c4
--- /dev/null
+++ b/src/main/resources/logback-spring.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${CONSOLE_LOG_PATTERN}
+ utf8
+
+
+
+ /Users/wuxiang/Desktop/applog/interface-common/interface-common.log
+
+ /Users/wuxiang/Desktop/applog/interface-common/interface-common.%d{yyyy-MM-dd}.%i.log.zip
+ 200MB
+ 10
+ 2GB
+
+
+ %d %5p | %t | %logger{25} - %msg%n
+ utf-8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis-config.xml b/src/main/resources/mybatis-config.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8446ab2ba04c45a462e8ead1f5c677be5cf8542e
--- /dev/null
+++ b/src/main/resources/mybatis-config.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file