bihuisong 1 سال پیش
کامیت
0d6b3af804
100فایلهای تغییر یافته به همراه5109 افزوده شده و 0 حذف شده
  1. 46 0
      .gitignore
  2. 21 0
      LICENSE
  3. 60 0
      README.md
  4. 12 0
      bin/clean.bat
  5. 12 0
      bin/package.bat
  6. 14 0
      bin/run-auth.bat
  7. 14 0
      bin/run-gateway.bat
  8. 14 0
      bin/run-modules-file.bat
  9. 14 0
      bin/run-modules-gen.bat
  10. 14 0
      bin/run-modules-job.bat
  11. 14 0
      bin/run-modules-system.bat
  12. 14 0
      bin/run-monitor.bat
  13. 41 0
      docker/copy.sh
  14. 67 0
      docker/deploy.sh
  15. 140 0
      docker/docker-compose.yml
  16. 1 0
      docker/mysql/db/readme.txt
  17. 7 0
      docker/mysql/dockerfile
  18. 24 0
      docker/nacos/conf/application.properties
  19. 7 0
      docker/nacos/dockerfile
  20. 41 0
      docker/nginx/conf/nginx.conf
  21. 15 0
      docker/nginx/dockerfile
  22. 1 0
      docker/redis/conf/redis.conf
  23. 13 0
      docker/redis/dockerfile
  24. 15 0
      docker/sooka/auth/dockerfile
  25. 1 0
      docker/sooka/auth/jar/readme.txt
  26. 15 0
      docker/sooka/gateway/dockerfile
  27. 1 0
      docker/sooka/gateway/jar/readme.txt
  28. 15 0
      docker/sooka/modules/file/dockerfile
  29. 1 0
      docker/sooka/modules/file/jar/readme.txt
  30. 15 0
      docker/sooka/modules/gen/dockerfile
  31. 1 0
      docker/sooka/modules/gen/jar/readme.txt
  32. 15 0
      docker/sooka/modules/job/dockerfile
  33. 1 0
      docker/sooka/modules/job/jar/readme.txt
  34. 15 0
      docker/sooka/modules/system/dockerfile
  35. 1 0
      docker/sooka/modules/system/jar/readme.txt
  36. 15 0
      docker/sooka/visual/monitor/dockerfile
  37. 1 0
      docker/sooka/visual/monitor/jar/readme.txt
  38. 284 0
      pom.xml
  39. 22 0
      sooka-api/pom.xml
  40. 28 0
      sooka-api/sooka-api-system/pom.xml
  41. 28 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/RemoteFileService.java
  42. 40 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/RemoteLogService.java
  43. 38 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/RemoteUserService.java
  44. 203 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysDept.java
  45. 175 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysDictData.java
  46. 96 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysDictType.java
  47. 45 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysFile.java
  48. 102 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysLogininfor.java
  49. 255 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysOperLog.java
  50. 237 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysRole.java
  51. 322 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysUser.java
  52. 31 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/factory/RemoteFileFallbackFactory.java
  53. 37 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/factory/RemoteLogFallbackFactory.java
  54. 36 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/factory/RemoteUserFallbackFactory.java
  55. 132 0
      sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/model/LoginUser.java
  56. 3 0
      sooka-api/sooka-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  57. 74 0
      sooka-auth/pom.xml
  58. 20 0
      sooka-auth/src/main/java/com/sooka/auth/SookaAuthApplication.java
  59. 72 0
      sooka-auth/src/main/java/com/sooka/auth/controller/TokenController.java
  60. 34 0
      sooka-auth/src/main/java/com/sooka/auth/form/LoginBody.java
  61. 10 0
      sooka-auth/src/main/java/com/sooka/auth/form/RegisterBody.java
  62. 127 0
      sooka-auth/src/main/java/com/sooka/auth/service/SysLoginService.java
  63. 75 0
      sooka-auth/src/main/java/com/sooka/auth/service/SysPasswordService.java
  64. 43 0
      sooka-auth/src/main/java/com/sooka/auth/service/SysRecordLogService.java
  65. 2 0
      sooka-auth/src/main/resources/banner.txt
  66. 25 0
      sooka-auth/src/main/resources/bootstrap.yml
  67. 74 0
      sooka-auth/src/main/resources/logback.xml
  68. 29 0
      sooka-common/pom.xml
  69. 118 0
      sooka-common/sooka-common-core/pom.xml
  70. 176 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/annotation/Excel.java
  71. 17 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/annotation/Excels.java
  72. 58 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/CacheConstants.java
  73. 134 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/Constants.java
  74. 186 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/GenConstants.java
  75. 93 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/HttpStatus.java
  76. 56 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/ScheduleConstants.java
  77. 48 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/SecurityConstants.java
  78. 23 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/ServiceNameConstants.java
  79. 24 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/TokenConstants.java
  80. 113 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/UserConstants.java
  81. 83 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/context/SecurityContextHolder.java
  82. 99 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/domain/R.java
  83. 26 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/enums/UserStatus.java
  84. 14 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/CaptchaException.java
  85. 26 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/CheckedException.java
  86. 13 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/DemoModeException.java
  87. 51 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/GlobalException.java
  88. 14 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/InnerAuthException.java
  89. 13 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/PreAuthorizeException.java
  90. 65 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/ServiceException.java
  91. 22 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/UtilException.java
  92. 14 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/auth/NotLoginException.java
  93. 20 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/auth/NotPermissionException.java
  94. 20 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/auth/NotRoleException.java
  95. 69 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/base/BaseException.java
  96. 17 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/file/FileException.java
  97. 14 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/file/FileNameLengthLimitExceededException.java
  98. 14 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/file/FileSizeLimitExceededException.java
  99. 52 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/file/FileUploadException.java
  100. 0 0
      sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/file/InvalidExtensionException.java

+ 46 - 0
.gitignore

@@ -0,0 +1,46 @@
+######################################################################
+# Build Tools
+
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+######################################################################
+# IDE
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### JRebel ###
+rebel.xml
+### NetBeans ###
+nbproject/private/
+build/*
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+######################################################################
+# Others
+*.log
+*.xml.versionsBackup
+*.swp
+
+!*/build/*.java
+!*/build/*.html
+!*/build/*.xml

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 sooka
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 60 - 0
README.md

@@ -0,0 +1,60 @@
+
+<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sooka v3.6.3</h1>
+<h4 align="center">基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构</h4>
+
+
+## 平台简介
+
+
+* 采用前后端分离的模式,微服务版本前端。
+* 后端采用Spring Boot、Spring Cloud & Alibaba。
+* 注册中心、配置中心选型Nacos,权限认证使用Redis。
+* 流量控制框架选型Sentinel,分布式事务选型Seata。
+
+## 系统模块
+
+~~~
+com.sooka     
+├── sooka-ui              // 前端框架 [80]
+├── sooka-gateway         // 网关模块 [8080]
+├── sooka-auth            // 认证中心 [9200]
+├── sooka-api             // 接口模块
+│       └── sooka-api-system                          // 系统接口
+├── sooka-common          // 通用模块
+│       └── sooka-common-core                         // 核心模块
+│       └── sooka-common-datascope                    // 权限范围
+│       └── sooka-common-datasource                   // 多数据源
+│       └── sooka-common-log                          // 日志记录
+│       └── sooka-common-redis                        // 缓存服务
+│       └── sooka-common-seata                        // 分布式事务
+│       └── sooka-common-security                     // 安全模块
+│       └── sooka-common-swagger                      // 系统接口
+├── sooka-modules         // 业务模块
+│       └── sooka-system                              // 系统模块 [9201]
+│       └── sooka-gen                                 // 代码生成 [9202]
+│       └── sooka-job                                 // 定时任务 [9203]
+│       └── sooka-file                                // 文件服务 [9300]
+├── sooka-visual          // 图形化管理模块
+│       └── sooka-visual-monitor                      // 监控中心 [9100]
+├──pom.xml                // 公共依赖
+~~~
+
+## 内置功能
+
+1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
+2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
+3. 岗位管理:配置系统用户所属担任职务。
+4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
+5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
+6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
+7. 参数管理:对系统动态配置常用参数。
+8. 通知公告:系统通知公告信息发布维护。
+9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
+10. 登录日志:系统登录日志记录查询包含登录异常。
+11. 在线用户:当前系统中活跃用户状态监控。
+12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
+13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。
+14. 系统接口:根据业务代码自动生成相关的api接口文档。
+15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
+16. 在线构建器:拖动表单元素生成相应的HTML代码。
+17. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。

+ 12 - 0
bin/clean.bat

@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 清理工程target生成路径。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+call mvn clean
+
+pause

+ 12 - 0
bin/package.bat

@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 打包Web工程,生成war/jar包文件。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+call mvn clean package -Dmaven.test.skip=true
+
+pause

+ 14 - 0
bin/run-auth.bat

@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [��Ϣ] ʹ��Jar��������Auth���̡�
+echo.
+
+cd %~dp0
+cd ../sooka-auth/target
+
+set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
+
+java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar sooka-auth.jar
+
+cd bin
+pause

+ 14 - 0
bin/run-gateway.bat

@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [��Ϣ] ʹ��Jar��������Gateway���̡�
+echo.
+
+cd %~dp0
+cd ../sooka-gateway/target
+
+set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
+
+java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar sooka-gateway.jar
+
+cd bin
+pause

+ 14 - 0
bin/run-modules-file.bat

@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [��Ϣ] ʹ��Jar��������Modules-File���̡�
+echo.
+
+cd %~dp0
+cd ../sooka-modules/sooka-file/target
+
+set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
+
+java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar sooka-modules-file.jar
+
+cd bin
+pause

+ 14 - 0
bin/run-modules-gen.bat

@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [��Ϣ] ʹ��Jar��������Modules-Gen���̡�
+echo.
+
+cd %~dp0
+cd ../sooka-modules/sooka-gen/target
+
+set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
+
+java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar sooka-modules-gen.jar
+
+cd bin
+pause

+ 14 - 0
bin/run-modules-job.bat

@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [��Ϣ] ʹ��Jar��������Modules-Job���̡�
+echo.
+
+cd %~dp0
+cd ../sooka-modules/sooka-job/target
+
+set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
+
+java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar sooka-modules-job.jar
+
+cd bin
+pause

+ 14 - 0
bin/run-modules-system.bat

@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [��Ϣ] ʹ��Jar��������Modules-System���̡�
+echo.
+
+cd %~dp0
+cd ../sooka-modules/sooka-system/target
+
+set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
+
+java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar sooka-modules-system.jar
+
+cd bin
+pause

+ 14 - 0
bin/run-monitor.bat

@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [��Ϣ] ʹ��Jar��������Monitor���̡�
+echo.
+
+cd %~dp0
+cd ../sooka-visual/sooka-monitor/target
+
+set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
+
+java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar sooka-visual-monitor.jar
+
+cd bin
+pause

+ 41 - 0
docker/copy.sh

@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# 复制项目的文件到对应docker路径,便于一键生成镜像。
+usage() {
+	echo "Usage: sh copy.sh"
+	exit 1
+}
+
+
+# copy sql
+echo "begin copy sql "
+cp ../sql/ry_20230706.sql ./mysql/db
+cp ../sql/ry_config_20220929.sql ./mysql/db
+
+# copy html
+echo "begin copy html "
+cp -r ../sooka-ui/dist/** ./nginx/html/dist
+
+
+# copy jar
+echo "begin copy sooka-gateway "
+cp ../sooka-gateway/target/sooka-gateway.jar ./sooka/gateway/jar
+
+echo "begin copy sooka-auth "
+cp ../sooka-auth/target/sooka-auth.jar ./sooka/auth/jar
+
+echo "begin copy sooka-visual "
+cp ../sooka-visual/sooka-monitor/target/sooka-visual-monitor.jar  ./sooka/visual/monitor/jar
+
+echo "begin copy sooka-modules-system "
+cp ../sooka-modules/sooka-system/target/sooka-modules-system.jar ./sooka/modules/system/jar
+
+echo "begin copy sooka-modules-file "
+cp ../sooka-modules/sooka-file/target/sooka-modules-file.jar ./sooka/modules/file/jar
+
+echo "begin copy sooka-modules-job "
+cp ../sooka-modules/sooka-job/target/sooka-modules-job.jar ./sooka/modules/job/jar
+
+echo "begin copy sooka-modules-gen "
+cp ../sooka-modules/sooka-gen/target/sooka-modules-gen.jar ./sooka/modules/gen/jar
+

+ 67 - 0
docker/deploy.sh

@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# 使用说明,用来提示输入参数
+usage() {
+	echo "Usage: sh 执行脚本.sh [port|base|modules|stop|rm]"
+	exit 1
+}
+
+# 开启所需端口
+port(){
+	firewall-cmd --add-port=80/tcp --permanent
+	firewall-cmd --add-port=8080/tcp --permanent
+	firewall-cmd --add-port=8848/tcp --permanent
+	firewall-cmd --add-port=9848/tcp --permanent
+	firewall-cmd --add-port=9849/tcp --permanent
+	firewall-cmd --add-port=6379/tcp --permanent
+	firewall-cmd --add-port=3306/tcp --permanent
+	firewall-cmd --add-port=9100/tcp --permanent
+	firewall-cmd --add-port=9200/tcp --permanent
+	firewall-cmd --add-port=9201/tcp --permanent
+	firewall-cmd --add-port=9202/tcp --permanent
+	firewall-cmd --add-port=9203/tcp --permanent
+	firewall-cmd --add-port=9300/tcp --permanent
+	service firewalld restart
+}
+
+# 启动基础环境(必须)
+base(){
+	docker-compose up -d sooka-mysql sooka-redis sooka-nacos
+}
+
+# 启动程序模块(必须)
+modules(){
+	docker-compose up -d sooka-nginx sooka-gateway sooka-auth sooka-modules-system
+}
+
+# 关闭所有环境/模块
+stop(){
+	docker-compose stop
+}
+
+# 删除所有环境/模块
+rm(){
+	docker-compose rm
+}
+
+# 根据输入参数,选择执行对应方法,不输入则执行使用说明
+case "$1" in
+"port")
+	port
+;;
+"base")
+	base
+;;
+"modules")
+	modules
+;;
+"stop")
+	stop
+;;
+"rm")
+	rm
+;;
+*)
+	usage
+;;
+esac

+ 140 - 0
docker/docker-compose.yml

@@ -0,0 +1,140 @@
+version: '3.8'
+services:
+  sooka-nacos:
+    container_name: sooka-nacos
+    image: nacos/nacos-server
+    build:
+      context: ./nacos
+    environment:
+      - MODE=standalone
+    volumes:
+      - ./nacos/logs/:/home/nacos/logs
+      - ./nacos/conf/application.properties:/home/nacos/conf/application.properties
+    ports:
+      - "8848:8848"
+      - "9848:9848"
+      - "9849:9849"
+    depends_on:
+      - sooka-mysql
+  sooka-mysql:
+    container_name: sooka-mysql
+    image: mysql:5.7
+    build:
+      context: ./mysql
+    ports:
+      - "3306:3306"
+    volumes:
+      - ./mysql/conf:/etc/mysql/conf.d
+      - ./mysql/logs:/logs
+      - ./mysql/data:/var/lib/mysql
+    command: [
+      'mysqld',
+      '--innodb-buffer-pool-size=80M',
+      '--character-set-server=utf8mb4',
+      '--collation-server=utf8mb4_unicode_ci',
+      '--default-time-zone=+8:00',
+      '--lower-case-table-names=1'
+    ]
+    environment:
+      MYSQL_DATABASE: 'ry-cloud'
+      MYSQL_ROOT_PASSWORD: password
+  sooka-redis:
+    container_name: sooka-redis
+    image: redis
+    build:
+      context: ./redis
+    ports:
+      - "6379:6379"
+    volumes:
+      - ./redis/conf/redis.conf:/home/sooka/redis/redis.conf
+      - ./redis/data:/data
+    command: redis-server /home/sooka/redis/redis.conf
+  sooka-nginx:
+    container_name: sooka-nginx
+    image: nginx
+    build:
+      context: ./nginx
+    ports:
+      - "80:80"
+    volumes:
+      - ./nginx/html/dist:/home/sooka/projects/sooka-ui
+      - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf
+      - ./nginx/logs:/var/log/nginx
+      - ./nginx/conf.d:/etc/nginx/conf.d
+    depends_on:
+      - sooka-gateway
+    links:
+      - sooka-gateway
+  sooka-gateway:
+    container_name: sooka-gateway
+    build:
+      context: ./sooka/gateway
+      dockerfile: dockerfile
+    ports:
+      - "8080:8080"
+    depends_on:
+      - sooka-redis
+    links:
+      - sooka-redis
+  sooka-auth:
+    container_name: sooka-auth
+    build:
+      context: ./sooka/auth
+      dockerfile: dockerfile
+    ports:
+      - "9200:9200"
+    depends_on:
+      - sooka-redis
+    links:
+      - sooka-redis
+  sooka-modules-system:
+    container_name: sooka-modules-system
+    build:
+      context: ./sooka/modules/system
+      dockerfile: dockerfile
+    ports:
+      - "9201:9201"
+    depends_on:
+      - sooka-redis
+      - sooka-mysql
+    links:
+      - sooka-redis
+      - sooka-mysql
+  sooka-modules-gen:
+    container_name: sooka-modules-gen
+    build:
+      context: ./sooka/modules/gen
+      dockerfile: dockerfile
+    ports:
+      - "9202:9202"
+    depends_on:
+      - sooka-mysql
+    links:
+      - sooka-mysql
+  sooka-modules-job:
+    container_name: sooka-modules-job
+    build:
+      context: ./sooka/modules/job
+      dockerfile: dockerfile
+    ports:
+      - "9203:9203"
+    depends_on:
+      - sooka-mysql
+    links:
+      - sooka-mysql
+  sooka-modules-file:
+    container_name: sooka-modules-file
+    build:
+      context: ./sooka/modules/file
+      dockerfile: dockerfile
+    ports:
+      - "9300:9300"
+    volumes:
+      - ./sooka/uploadPath:/home/sooka/uploadPath
+  sooka-visual-monitor:
+    container_name: sooka-visual-monitor
+    build:
+      context: ./sooka/visual/monitor
+      dockerfile: dockerfile
+    ports:
+      - "9100:9100"

+ 1 - 0
docker/mysql/db/readme.txt

@@ -0,0 +1 @@
+存放sql目录下的所有脚本,用于docker自动执行。

+ 7 - 0
docker/mysql/dockerfile

@@ -0,0 +1,7 @@
+# 基础镜像
+FROM mysql:5.7
+# author
+MAINTAINER sooka
+
+# 执行sql脚本
+ADD ./db/*.sql /docker-entrypoint-initdb.d/

+ 24 - 0
docker/nacos/conf/application.properties

@@ -0,0 +1,24 @@
+spring.datasource.platform=mysql
+db.num=1
+db.url.0=jdbc:mysql://sooka-mysql:3306/ry-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
+db.user=root
+db.password=password
+nacos.naming.empty-service.auto-clean=true
+nacos.naming.empty-service.clean.initial-delay-ms=50000
+nacos.naming.empty-service.clean.period-time-ms=30000
+management.endpoints.web.exposure.include=*
+management.metrics.export.elastic.enabled=false
+management.metrics.export.influx.enabled=false
+server.tomcat.accesslog.enabled=true
+server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
+server.tomcat.basedir=/home/sooka/nacos/tomcat/logs
+nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
+nacos.core.auth.system.type=nacos
+nacos.core.auth.enabled=false
+nacos.core.auth.default.token.expire.seconds=18000
+nacos.core.auth.default.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
+nacos.core.auth.caching.enabled=true
+nacos.core.auth.enable.userAgentAuthWhite=false
+nacos.core.auth.server.identity.key=serverIdentity
+nacos.core.auth.server.identity.value=security
+nacos.istio.mcp.server.enabled=false

+ 7 - 0
docker/nacos/dockerfile

@@ -0,0 +1,7 @@
+# 基础镜像
+FROM nacos/nacos-server
+# author
+MAINTAINER sooka
+
+# 复制conf文件到路径
+COPY ./conf/application.properties /home/nacos/conf/application.properties

+ 41 - 0
docker/nginx/conf/nginx.conf

@@ -0,0 +1,41 @@
+worker_processes  1;
+
+events {
+    worker_connections  1024;
+}
+
+http {
+    include       mime.types;
+    default_type  application/octet-stream;
+    sendfile        on;
+    keepalive_timeout  65;
+
+    server {
+        listen       80;
+        server_name  localhost;
+
+        location / {
+            root   /home/sooka/projects/sooka-ui;
+            try_files $uri $uri/ /index.html;
+            index  index.html index.htm;
+        }
+
+        location /prod-api/{
+            proxy_set_header Host $http_host;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header REMOTE-HOST $remote_addr;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_pass http://sooka-gateway:8080/;
+        }
+
+        # 避免actuator暴露
+        if ($request_uri ~ "/actuator") {
+            return 403;
+        }
+
+        error_page   500 502 503 504  /50x.html;
+        location = /50x.html {
+            root   html;
+        }
+    }
+}

+ 15 - 0
docker/nginx/dockerfile

@@ -0,0 +1,15 @@
+# 基础镜像
+FROM nginx
+# author
+MAINTAINER sooka
+
+# 挂载目录
+VOLUME /home/sooka/projects/sooka-ui
+# 创建目录
+RUN mkdir -p /home/sooka/projects/sooka-ui
+# 指定路径
+WORKDIR /home/sooka/projects/sooka-ui
+# 复制conf文件到路径
+COPY ./conf/nginx.conf /etc/nginx/nginx.conf
+# 复制html文件到路径
+COPY ./html/dist /home/sooka/projects/sooka-ui

+ 1 - 0
docker/redis/conf/redis.conf

@@ -0,0 +1 @@
+# requirepass 123456

+ 13 - 0
docker/redis/dockerfile

@@ -0,0 +1,13 @@
+# 基础镜像
+FROM redis
+# author
+MAINTAINER sooka
+
+# 挂载目录
+VOLUME /home/sooka/redis
+# 创建目录
+RUN mkdir -p /home/sooka/redis
+# 指定路径
+WORKDIR /home/sooka/redis
+# 复制conf文件到路径
+COPY ./conf/redis.conf /home/sooka/redis/redis.conf

+ 15 - 0
docker/sooka/auth/dockerfile

@@ -0,0 +1,15 @@
+# 基础镜像
+FROM  openjdk:8-jre
+# author
+MAINTAINER sooka
+
+# 挂载目录
+VOLUME /home/sooka
+# 创建目录
+RUN mkdir -p /home/sooka
+# 指定路径
+WORKDIR /home/sooka
+# 复制jar文件到路径
+COPY ./jar/sooka-auth.jar /home/sooka/sooka-auth.jar
+# 启动认证服务
+ENTRYPOINT ["java","-jar","sooka-auth.jar"]

+ 1 - 0
docker/sooka/auth/jar/readme.txt

@@ -0,0 +1 @@
+存放认证中心打包好的jar文件,用于docker启动应用。

+ 15 - 0
docker/sooka/gateway/dockerfile

@@ -0,0 +1,15 @@
+# 基础镜像
+FROM  openjdk:8-jre
+# author
+MAINTAINER sooka
+
+# 挂载目录
+VOLUME /home/sooka
+# 创建目录
+RUN mkdir -p /home/sooka
+# 指定路径
+WORKDIR /home/sooka
+# 复制jar文件到路径
+COPY ./jar/sooka-gateway.jar /home/sooka/sooka-gateway.jar
+# 启动网关服务
+ENTRYPOINT ["java","-jar","sooka-gateway.jar"]

+ 1 - 0
docker/sooka/gateway/jar/readme.txt

@@ -0,0 +1 @@
+存放网关模块打包好的jar文件,用于docker启动应用。

+ 15 - 0
docker/sooka/modules/file/dockerfile

@@ -0,0 +1,15 @@
+# 基础镜像
+FROM  openjdk:8-jre
+# author
+MAINTAINER sooka
+
+# 挂载目录
+VOLUME /home/sooka
+# 创建目录
+RUN mkdir -p /home/sooka
+# 指定路径
+WORKDIR /home/sooka
+# 复制jar文件到路径
+COPY ./jar/sooka-modules-file.jar /home/sooka/sooka-modules-file.jar
+# 启动文件服务
+ENTRYPOINT ["java","-jar","sooka-modules-file.jar"]

+ 1 - 0
docker/sooka/modules/file/jar/readme.txt

@@ -0,0 +1 @@
+存放文件服务打包好的jar文件,用于docker启动应用。

+ 15 - 0
docker/sooka/modules/gen/dockerfile

@@ -0,0 +1,15 @@
+# 基础镜像
+FROM  openjdk:8-jre
+# author
+MAINTAINER sooka
+
+# 挂载目录
+VOLUME /home/sooka
+# 创建目录
+RUN mkdir -p /home/sooka
+# 指定路径
+WORKDIR /home/sooka
+# 复制jar文件到路径
+COPY ./jar/sooka-modules-gen.jar /home/sooka/sooka-modules-gen.jar
+# 启动代码生成服务
+ENTRYPOINT ["java","-jar","sooka-modules-gen.jar"]

+ 1 - 0
docker/sooka/modules/gen/jar/readme.txt

@@ -0,0 +1 @@
+存放代码生成打包好的jar文件,用于docker启动应用。

+ 15 - 0
docker/sooka/modules/job/dockerfile

@@ -0,0 +1,15 @@
+# 基础镜像
+FROM  openjdk:8-jre
+# author
+MAINTAINER sooka
+
+# 挂载目录
+VOLUME /home/sooka
+# 创建目录
+RUN mkdir -p /home/sooka
+# 指定路径
+WORKDIR /home/sooka
+# 复制jar文件到路径
+COPY ./jar/sooka-modules-job.jar /home/sooka/sooka-modules-job.jar
+# 启动定时任务服务
+ENTRYPOINT ["java","-jar","sooka-modules-job.jar"]

+ 1 - 0
docker/sooka/modules/job/jar/readme.txt

@@ -0,0 +1 @@
+存放定时任务打包好的jar文件,用于docker启动应用。

+ 15 - 0
docker/sooka/modules/system/dockerfile

@@ -0,0 +1,15 @@
+# 基础镜像
+FROM  openjdk:8-jre
+# author
+MAINTAINER sooka
+
+# 挂载目录
+VOLUME /home/sooka
+# 创建目录
+RUN mkdir -p /home/sooka
+# 指定路径
+WORKDIR /home/sooka
+# 复制jar文件到路径
+COPY ./jar/sooka-modules-system.jar /home/sooka/sooka-modules-system.jar
+# 启动系统服务
+ENTRYPOINT ["java","-jar","sooka-modules-system.jar"]

+ 1 - 0
docker/sooka/modules/system/jar/readme.txt

@@ -0,0 +1 @@
+存放系统模块打包好的jar文件,用于docker启动应用。

+ 15 - 0
docker/sooka/visual/monitor/dockerfile

@@ -0,0 +1,15 @@
+# 基础镜像
+FROM  openjdk:8-jre
+# author
+MAINTAINER sooka
+
+# 挂载目录
+VOLUME /home/sooka
+# 创建目录
+RUN mkdir -p /home/sooka
+# 指定路径
+WORKDIR /home/sooka
+# 复制jar文件到路径
+COPY ./jar/sooka-visual-monitor.jar /home/sooka/sooka-visual-monitor.jar
+# 启动系统服务
+ENTRYPOINT ["java","-jar","sooka-visual-monitor.jar"]

+ 1 - 0
docker/sooka/visual/monitor/jar/readme.txt

@@ -0,0 +1 @@
+存放监控中心打包好的jar文件,用于docker启动应用。

+ 284 - 0
pom.xml

@@ -0,0 +1,284 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.sooka</groupId>
+    <artifactId>sooka</artifactId>
+    <version>3.6.3</version>
+
+    <name>sooka</name>
+    <description>sooka微服务系统</description>
+
+    <properties>
+        <sooka.version>3.6.3</sooka.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>1.8</java.version>
+        <spring-boot.version>2.7.18</spring-boot.version>
+        <spring-cloud.version>2021.0.8</spring-cloud.version>
+        <spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>
+        <spring-boot-admin.version>2.7.11</spring-boot-admin.version>
+        <swagger.fox.version>3.0.0</swagger.fox.version>
+        <swagger.core.version>1.6.2</swagger.core.version>
+        <tobato.version>1.27.2</tobato.version>
+        <kaptcha.version>2.3.3</kaptcha.version>
+        <pagehelper.boot.version>2.0.0</pagehelper.boot.version>
+        <druid.version>1.2.20</druid.version>
+        <dynamic-ds.version>4.2.0</dynamic-ds.version>
+        <commons.io.version>2.13.0</commons.io.version>
+        <velocity.version>2.3</velocity.version>
+        <fastjson.version>2.0.43</fastjson.version>
+        <jjwt.version>0.9.1</jjwt.version>
+        <minio.version>8.2.2</minio.version>
+        <poi.version>4.1.2</poi.version>
+        <transmittable-thread-local.version>2.14.4</transmittable-thread-local.version>
+    </properties>
+
+    <!-- 依赖声明 -->
+    <dependencyManagement>
+        <dependencies>
+
+            <!-- SpringCloud 微服务 -->
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${spring-cloud.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- SpringCloud Alibaba 微服务 -->
+            <dependency>
+                <groupId>com.alibaba.cloud</groupId>
+                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
+                <version>${spring-cloud-alibaba.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- SpringBoot 依赖配置 -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- FastDFS 分布式文件系统 -->
+            <dependency>
+                <groupId>com.github.tobato</groupId>
+                <artifactId>fastdfs-client</artifactId>
+                <version>${tobato.version}</version>
+            </dependency>
+
+            <!-- Swagger 依赖配置 -->
+            <dependency>
+                <groupId>io.swagger</groupId>
+                <artifactId>swagger-models</artifactId>
+                <version>${swagger.core.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.swagger</groupId>
+                <artifactId>swagger-annotations</artifactId>
+                <version>${swagger.core.version}</version>
+            </dependency>
+
+            <!-- 验证码 -->
+            <dependency>
+                <groupId>pro.fessional</groupId>
+                <artifactId>kaptcha</artifactId>
+                <version>${kaptcha.version}</version>
+            </dependency>
+
+            <!-- pagehelper 分页插件 -->
+            <dependency>
+                <groupId>com.github.pagehelper</groupId>
+                <artifactId>pagehelper-spring-boot-starter</artifactId>
+                <version>${pagehelper.boot.version}</version>
+            </dependency>
+
+            <!-- io常用工具类 -->
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>${commons.io.version}</version>
+            </dependency>
+
+            <!-- excel工具 -->
+            <dependency>
+                <groupId>org.apache.poi</groupId>
+                <artifactId>poi-ooxml</artifactId>
+                <version>${poi.version}</version>
+            </dependency>
+
+            <!-- 代码生成使用模板 -->
+            <dependency>
+                <groupId>org.apache.velocity</groupId>
+                <artifactId>velocity-engine-core</artifactId>
+                <version>${velocity.version}</version>
+            </dependency>
+
+            <!-- JSON 解析器和生成器 -->
+            <dependency>
+                <groupId>com.alibaba.fastjson2</groupId>
+                <artifactId>fastjson2</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+
+            <!-- JWT -->
+            <dependency>
+                <groupId>io.jsonwebtoken</groupId>
+                <artifactId>jjwt</artifactId>
+                <version>${jjwt.version}</version>
+            </dependency>
+
+            <!-- 线程传递值 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>transmittable-thread-local</artifactId>
+                <version>${transmittable-thread-local.version}</version>
+            </dependency>
+
+            <!-- 核心模块 -->
+            <dependency>
+                <groupId>com.sooka</groupId>
+                <artifactId>sooka-common-core</artifactId>
+                <version>${sooka.version}</version>
+            </dependency>
+
+            <!-- 接口模块 -->
+            <dependency>
+                <groupId>com.sooka</groupId>
+                <artifactId>sooka-common-swagger</artifactId>
+                <version>${sooka.version}</version>
+            </dependency>
+
+            <!-- 安全模块 -->
+            <dependency>
+                <groupId>com.sooka</groupId>
+                <artifactId>sooka-common-security</artifactId>
+                <version>${sooka.version}</version>
+            </dependency>
+
+            <!-- 权限范围 -->
+            <dependency>
+                <groupId>com.sooka</groupId>
+                <artifactId>sooka-common-datascope</artifactId>
+                <version>${sooka.version}</version>
+            </dependency>
+
+            <!-- 多数据源 -->
+            <dependency>
+                <groupId>com.sooka</groupId>
+                <artifactId>sooka-common-datasource</artifactId>
+                <version>${sooka.version}</version>
+            </dependency>
+
+            <!-- 分布式事务 -->
+            <dependency>
+                <groupId>com.sooka</groupId>
+                <artifactId>sooka-common-seata</artifactId>
+                <version>${sooka.version}</version>
+            </dependency>
+
+            <!-- 日志记录 -->
+            <dependency>
+                <groupId>com.sooka</groupId>
+                <artifactId>sooka-common-log</artifactId>
+                <version>${sooka.version}</version>
+            </dependency>
+
+            <!-- 缓存服务 -->
+            <dependency>
+                <groupId>com.sooka</groupId>
+                <artifactId>sooka-common-redis</artifactId>
+                <version>${sooka.version}</version>
+            </dependency>
+
+            <!-- 系统接口 -->
+            <dependency>
+                <groupId>com.sooka</groupId>
+                <artifactId>sooka-api-system</artifactId>
+                <version>${sooka.version}</version>
+            </dependency>
+
+        </dependencies>
+    </dependencyManagement>
+
+    <modules>
+        <module>sooka-auth</module>
+        <module>sooka-gateway</module>
+        <module>sooka-visual</module>
+        <module>sooka-modules</module>
+        <module>sooka-api</module>
+        <module>sooka-common</module>
+    </modules>
+    <packaging>pom</packaging>
+
+    <dependencies>
+        <!-- bootstrap 启动器 -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-maven-plugin</artifactId>
+                    <version>${spring-boot.version}</version>
+                    <executions>
+                        <execution>
+                            <goals>
+                                <goal>repackage</goal>
+                            </goals>
+                        </execution>
+                    </executions>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <repositories>
+        <repository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+        </repository>
+    </repositories>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </pluginRepository>
+    </pluginRepositories>
+
+</project>

+ 22 - 0
sooka-api/pom.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.sooka</groupId>
+        <artifactId>sooka</artifactId>
+        <version>3.6.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <modules>
+        <module>sooka-api-system</module>
+    </modules>
+
+    <artifactId>sooka-api</artifactId>
+    <packaging>pom</packaging>
+
+    <description>
+        sooka-api系统接口
+    </description>
+
+</project>

+ 28 - 0
sooka-api/sooka-api-system/pom.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.sooka</groupId>
+        <artifactId>sooka-api</artifactId>
+        <version>3.6.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sooka-api-system</artifactId>
+
+    <description>
+        sooka-api-system系统接口模块
+    </description>
+
+    <dependencies>
+
+        <!-- sooka Common Core-->
+        <dependency>
+            <groupId>com.sooka</groupId>
+            <artifactId>sooka-common-core</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 28 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/RemoteFileService.java

@@ -0,0 +1,28 @@
+package com.sooka.system.api;
+
+import com.sooka.common.core.constant.ServiceNameConstants;
+import com.sooka.common.core.domain.R;
+import com.sooka.system.api.domain.SysFile;
+import com.sooka.system.api.factory.RemoteFileFallbackFactory;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * 文件服务
+ *
+ * @author sooka
+ */
+@FeignClient(contextId = "remoteFileService" , value = ServiceNameConstants.FILE_SERVICE, fallbackFactory = RemoteFileFallbackFactory.class)
+public interface RemoteFileService {
+    /**
+     * 上传文件
+     *
+     * @param file 文件信息
+     * @return 结果
+     */
+    @PostMapping(value = "/upload" , consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public R<SysFile> upload(@RequestPart(value = "file") MultipartFile file);
+}

+ 40 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/RemoteLogService.java

@@ -0,0 +1,40 @@
+package com.sooka.system.api;
+
+import com.sooka.common.core.constant.SecurityConstants;
+import com.sooka.common.core.constant.ServiceNameConstants;
+import com.sooka.common.core.domain.R;
+import com.sooka.system.api.domain.SysLogininfor;
+import com.sooka.system.api.domain.SysOperLog;
+import com.sooka.system.api.factory.RemoteLogFallbackFactory;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+
+/**
+ * 日志服务
+ *
+ * @author sooka
+ */
+@FeignClient(contextId = "remoteLogService" , value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteLogFallbackFactory.class)
+public interface RemoteLogService {
+    /**
+     * 保存系统日志
+     *
+     * @param sysOperLog 日志实体
+     * @param source     请求来源
+     * @return 结果
+     */
+    @PostMapping("/operlog")
+    public R<Boolean> saveLog(@RequestBody SysOperLog sysOperLog, @RequestHeader(SecurityConstants.FROM_SOURCE) String source) throws Exception;
+
+    /**
+     * 保存访问记录
+     *
+     * @param sysLogininfor 访问实体
+     * @param source        请求来源
+     * @return 结果
+     */
+    @PostMapping("/logininfor")
+    public R<Boolean> saveLogininfor(@RequestBody SysLogininfor sysLogininfor, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+}

+ 38 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/RemoteUserService.java

@@ -0,0 +1,38 @@
+package com.sooka.system.api;
+
+import com.sooka.common.core.constant.SecurityConstants;
+import com.sooka.common.core.constant.ServiceNameConstants;
+import com.sooka.common.core.domain.R;
+import com.sooka.system.api.domain.SysUser;
+import com.sooka.system.api.factory.RemoteUserFallbackFactory;
+import com.sooka.system.api.model.LoginUser;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 用户服务
+ *
+ * @author sooka
+ */
+@FeignClient(contextId = "remoteUserService" , value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class)
+public interface RemoteUserService {
+    /**
+     * 通过用户名查询用户信息
+     *
+     * @param username 用户名
+     * @param source   请求来源
+     * @return 结果
+     */
+    @GetMapping("/user/info/{username}")
+    public R<LoginUser> getUserInfo(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 注册用户信息
+     *
+     * @param sysUser 用户信息
+     * @param source  请求来源
+     * @return 结果
+     */
+    @PostMapping("/user/register")
+    public R<Boolean> registerUserInfo(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+}

+ 203 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysDept.java

@@ -0,0 +1,203 @@
+package com.sooka.system.api.domain;
+
+import com.sooka.common.core.web.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 部门表 sys_dept
+ *
+ * @author sooka
+ */
+public class SysDept extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 部门ID
+     */
+    private Long deptId;
+
+    /**
+     * 父部门ID
+     */
+    private Long parentId;
+
+    /**
+     * 祖级列表
+     */
+    private String ancestors;
+
+    /**
+     * 部门名称
+     */
+    private String deptName;
+
+    /**
+     * 显示顺序
+     */
+    private Integer orderNum;
+
+    /**
+     * 负责人
+     */
+    private String leader;
+
+    /**
+     * 联系电话
+     */
+    private String phone;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 部门状态:0正常,1停用
+     */
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    private String delFlag;
+
+    /**
+     * 父部门名称
+     */
+    private String parentName;
+
+    /**
+     * 子部门
+     */
+    private List<SysDept> children = new ArrayList<SysDept>();
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public Long getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getAncestors() {
+        return ancestors;
+    }
+
+    public void setAncestors(String ancestors) {
+        this.ancestors = ancestors;
+    }
+
+    @NotBlank(message = "部门名称不能为空")
+    @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符")
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    @NotNull(message = "显示顺序不能为空")
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public String getLeader() {
+        return leader;
+    }
+
+    public void setLeader(String leader) {
+        this.leader = leader;
+    }
+
+    @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    @Email(message = "邮箱格式不正确")
+    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getDelFlag() {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    public String getParentName() {
+        return parentName;
+    }
+
+    public void setParentName(String parentName) {
+        this.parentName = parentName;
+    }
+
+    public List<SysDept> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<SysDept> children) {
+        this.children = children;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("deptId" , getDeptId())
+                .append("parentId" , getParentId())
+                .append("ancestors" , getAncestors())
+                .append("deptName" , getDeptName())
+                .append("orderNum" , getOrderNum())
+                .append("leader" , getLeader())
+                .append("phone" , getPhone())
+                .append("email" , getEmail())
+                .append("status" , getStatus())
+                .append("delFlag" , getDelFlag())
+                .append("createBy" , getCreateBy())
+                .append("createTime" , getCreateTime())
+                .append("updateBy" , getUpdateBy())
+                .append("updateTime" , getUpdateTime())
+                .toString();
+    }
+}

+ 175 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysDictData.java

@@ -0,0 +1,175 @@
+package com.sooka.system.api.domain;
+
+import com.sooka.common.core.annotation.Excel;
+import com.sooka.common.core.annotation.Excel.ColumnType;
+import com.sooka.common.core.constant.UserConstants;
+import com.sooka.common.core.web.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+/**
+ * 字典数据表 sys_dict_data
+ *
+ * @author sooka
+ */
+public class SysDictData extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 字典编码
+     */
+    @Excel(name = "字典编码" , cellType = ColumnType.NUMERIC)
+    private Long dictCode;
+
+    /**
+     * 字典排序
+     */
+    @Excel(name = "字典排序" , cellType = ColumnType.NUMERIC)
+    private Long dictSort;
+
+    /**
+     * 字典标签
+     */
+    @Excel(name = "字典标签")
+    private String dictLabel;
+
+    /**
+     * 字典键值
+     */
+    @Excel(name = "字典键值")
+    private String dictValue;
+
+    /**
+     * 字典类型
+     */
+    @Excel(name = "字典类型")
+    private String dictType;
+
+    /**
+     * 样式属性(其他样式扩展)
+     */
+    private String cssClass;
+
+    /**
+     * 表格字典样式
+     */
+    private String listClass;
+
+    /**
+     * 是否默认(Y是 N否)
+     */
+    @Excel(name = "是否默认" , readConverterExp = "Y=是,N=否")
+    private String isDefault;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @Excel(name = "状态" , readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    public Long getDictCode() {
+        return dictCode;
+    }
+
+    public void setDictCode(Long dictCode) {
+        this.dictCode = dictCode;
+    }
+
+    public Long getDictSort() {
+        return dictSort;
+    }
+
+    public void setDictSort(Long dictSort) {
+        this.dictSort = dictSort;
+    }
+
+    @NotBlank(message = "字典标签不能为空")
+    @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符")
+    public String getDictLabel() {
+        return dictLabel;
+    }
+
+    public void setDictLabel(String dictLabel) {
+        this.dictLabel = dictLabel;
+    }
+
+    @NotBlank(message = "字典键值不能为空")
+    @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符")
+    public String getDictValue() {
+        return dictValue;
+    }
+
+    public void setDictValue(String dictValue) {
+        this.dictValue = dictValue;
+    }
+
+    @NotBlank(message = "字典类型不能为空")
+    @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符")
+    public String getDictType() {
+        return dictType;
+    }
+
+    public void setDictType(String dictType) {
+        this.dictType = dictType;
+    }
+
+    @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符")
+    public String getCssClass() {
+        return cssClass;
+    }
+
+    public void setCssClass(String cssClass) {
+        this.cssClass = cssClass;
+    }
+
+    public String getListClass() {
+        return listClass;
+    }
+
+    public void setListClass(String listClass) {
+        this.listClass = listClass;
+    }
+
+    public boolean getDefault() {
+        return UserConstants.YES.equals(this.isDefault);
+    }
+
+    public String getIsDefault() {
+        return isDefault;
+    }
+
+    public void setIsDefault(String isDefault) {
+        this.isDefault = isDefault;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("dictCode" , getDictCode())
+                .append("dictSort" , getDictSort())
+                .append("dictLabel" , getDictLabel())
+                .append("dictValue" , getDictValue())
+                .append("dictType" , getDictType())
+                .append("cssClass" , getCssClass())
+                .append("listClass" , getListClass())
+                .append("isDefault" , getIsDefault())
+                .append("status" , getStatus())
+                .append("createBy" , getCreateBy())
+                .append("createTime" , getCreateTime())
+                .append("updateBy" , getUpdateBy())
+                .append("updateTime" , getUpdateTime())
+                .append("remark" , getRemark())
+                .toString();
+    }
+}

+ 96 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysDictType.java

@@ -0,0 +1,96 @@
+package com.sooka.system.api.domain;
+
+import com.sooka.common.core.annotation.Excel;
+import com.sooka.common.core.annotation.Excel.ColumnType;
+import com.sooka.common.core.web.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
+/**
+ * 字典类型表 sys_dict_type
+ *
+ * @author sooka
+ */
+public class SysDictType extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 字典主键
+     */
+    @Excel(name = "字典主键" , cellType = ColumnType.NUMERIC)
+    private Long dictId;
+
+    /**
+     * 字典名称
+     */
+    @Excel(name = "字典名称")
+    private String dictName;
+
+    /**
+     * 字典类型
+     */
+    @Excel(name = "字典类型")
+    private String dictType;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @Excel(name = "状态" , readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    public Long getDictId() {
+        return dictId;
+    }
+
+    public void setDictId(Long dictId) {
+        this.dictId = dictId;
+    }
+
+    @NotBlank(message = "字典名称不能为空")
+    @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符")
+    public String getDictName() {
+        return dictName;
+    }
+
+    public void setDictName(String dictName) {
+        this.dictName = dictName;
+    }
+
+    @NotBlank(message = "字典类型不能为空")
+    @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
+    @Pattern(regexp = "^[a-z][a-z0-9_]*$" , message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
+    public String getDictType() {
+        return dictType;
+    }
+
+    public void setDictType(String dictType) {
+        this.dictType = dictType;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("dictId" , getDictId())
+                .append("dictName" , getDictName())
+                .append("dictType" , getDictType())
+                .append("status" , getStatus())
+                .append("createBy" , getCreateBy())
+                .append("createTime" , getCreateTime())
+                .append("updateBy" , getUpdateBy())
+                .append("updateTime" , getUpdateTime())
+                .append("remark" , getRemark())
+                .toString();
+    }
+}

+ 45 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysFile.java

@@ -0,0 +1,45 @@
+package com.sooka.system.api.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 文件信息
+ *
+ * @author sooka
+ */
+public class SysFile {
+    /**
+     * 文件名称
+     */
+    private String name;
+
+    /**
+     * 文件地址
+     */
+    private String url;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("name" , getName())
+                .append("url" , getUrl())
+                .toString();
+    }
+}

+ 102 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysLogininfor.java

@@ -0,0 +1,102 @@
+package com.sooka.system.api.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.sooka.common.core.annotation.Excel;
+import com.sooka.common.core.annotation.Excel.ColumnType;
+import com.sooka.common.core.web.domain.BaseEntity;
+
+import java.util.Date;
+
+/**
+ * 系统访问记录表 sys_logininfor
+ *
+ * @author sooka
+ */
+public class SysLogininfor extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * ID
+     */
+    @Excel(name = "序号" , cellType = ColumnType.NUMERIC)
+    private Long infoId;
+
+    /**
+     * 用户账号
+     */
+    @Excel(name = "用户账号")
+    private String userName;
+
+    /**
+     * 状态 0成功 1失败
+     */
+    @Excel(name = "状态" , readConverterExp = "0=成功,1=失败")
+    private String status;
+
+    /**
+     * 地址
+     */
+    @Excel(name = "地址")
+    private String ipaddr;
+
+    /**
+     * 描述
+     */
+    @Excel(name = "描述")
+    private String msg;
+
+    /**
+     * 访问时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "访问时间" , width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date accessTime;
+
+    public Long getInfoId() {
+        return infoId;
+    }
+
+    public void setInfoId(Long infoId) {
+        this.infoId = infoId;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getIpaddr() {
+        return ipaddr;
+    }
+
+    public void setIpaddr(String ipaddr) {
+        this.ipaddr = ipaddr;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Date getAccessTime() {
+        return accessTime;
+    }
+
+    public void setAccessTime(Date accessTime) {
+        this.accessTime = accessTime;
+    }
+}

+ 255 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysOperLog.java

@@ -0,0 +1,255 @@
+package com.sooka.system.api.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.sooka.common.core.annotation.Excel;
+import com.sooka.common.core.annotation.Excel.ColumnType;
+import com.sooka.common.core.web.domain.BaseEntity;
+
+import java.util.Date;
+
+/**
+ * 操作日志记录表 oper_log
+ *
+ * @author sooka
+ */
+public class SysOperLog extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 日志主键
+     */
+    @Excel(name = "操作序号" , cellType = ColumnType.NUMERIC)
+    private Long operId;
+
+    /**
+     * 操作模块
+     */
+    @Excel(name = "操作模块")
+    private String title;
+
+    /**
+     * 业务类型(0其它 1新增 2修改 3删除)
+     */
+    @Excel(name = "业务类型" , readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据")
+    private Integer businessType;
+
+    /**
+     * 业务类型数组
+     */
+    private Integer[] businessTypes;
+
+    /**
+     * 请求方法
+     */
+    @Excel(name = "请求方法")
+    private String method;
+
+    /**
+     * 请求方式
+     */
+    @Excel(name = "请求方式")
+    private String requestMethod;
+
+    /**
+     * 操作类别(0其它 1后台用户 2手机端用户)
+     */
+    @Excel(name = "操作类别" , readConverterExp = "0=其它,1=后台用户,2=手机端用户")
+    private Integer operatorType;
+
+    /**
+     * 操作人员
+     */
+    @Excel(name = "操作人员")
+    private String operName;
+
+    /**
+     * 部门名称
+     */
+    @Excel(name = "部门名称")
+    private String deptName;
+
+    /**
+     * 请求url
+     */
+    @Excel(name = "请求地址")
+    private String operUrl;
+
+    /**
+     * 操作地址
+     */
+    @Excel(name = "操作地址")
+    private String operIp;
+
+    /**
+     * 请求参数
+     */
+    @Excel(name = "请求参数")
+    private String operParam;
+
+    /**
+     * 返回参数
+     */
+    @Excel(name = "返回参数")
+    private String jsonResult;
+
+    /**
+     * 操作状态(0正常 1异常)
+     */
+    @Excel(name = "状态" , readConverterExp = "0=正常,1=异常")
+    private Integer status;
+
+    /**
+     * 错误消息
+     */
+    @Excel(name = "错误消息")
+    private String errorMsg;
+
+    /**
+     * 操作时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "操作时间" , width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date operTime;
+
+    /**
+     * 消耗时间
+     */
+    @Excel(name = "消耗时间" , suffix = "毫秒")
+    private Long costTime;
+
+    public Long getOperId() {
+        return operId;
+    }
+
+    public void setOperId(Long operId) {
+        this.operId = operId;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Integer getBusinessType() {
+        return businessType;
+    }
+
+    public void setBusinessType(Integer businessType) {
+        this.businessType = businessType;
+    }
+
+    public Integer[] getBusinessTypes() {
+        return businessTypes;
+    }
+
+    public void setBusinessTypes(Integer[] businessTypes) {
+        this.businessTypes = businessTypes;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+    public String getRequestMethod() {
+        return requestMethod;
+    }
+
+    public void setRequestMethod(String requestMethod) {
+        this.requestMethod = requestMethod;
+    }
+
+    public Integer getOperatorType() {
+        return operatorType;
+    }
+
+    public void setOperatorType(Integer operatorType) {
+        this.operatorType = operatorType;
+    }
+
+    public String getOperName() {
+        return operName;
+    }
+
+    public void setOperName(String operName) {
+        this.operName = operName;
+    }
+
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    public String getOperUrl() {
+        return operUrl;
+    }
+
+    public void setOperUrl(String operUrl) {
+        this.operUrl = operUrl;
+    }
+
+    public String getOperIp() {
+        return operIp;
+    }
+
+    public void setOperIp(String operIp) {
+        this.operIp = operIp;
+    }
+
+    public String getOperParam() {
+        return operParam;
+    }
+
+    public void setOperParam(String operParam) {
+        this.operParam = operParam;
+    }
+
+    public String getJsonResult() {
+        return jsonResult;
+    }
+
+    public void setJsonResult(String jsonResult) {
+        this.jsonResult = jsonResult;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getErrorMsg() {
+        return errorMsg;
+    }
+
+    public void setErrorMsg(String errorMsg) {
+        this.errorMsg = errorMsg;
+    }
+
+    public Date getOperTime() {
+        return operTime;
+    }
+
+    public void setOperTime(Date operTime) {
+        this.operTime = operTime;
+    }
+
+    public Long getCostTime() {
+        return costTime;
+    }
+
+    public void setCostTime(Long costTime) {
+        this.costTime = costTime;
+    }
+}

+ 237 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysRole.java

@@ -0,0 +1,237 @@
+package com.sooka.system.api.domain;
+
+import com.sooka.common.core.annotation.Excel;
+import com.sooka.common.core.annotation.Excel.ColumnType;
+import com.sooka.common.core.web.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.Set;
+
+/**
+ * 角色表 sys_role
+ *
+ * @author sooka
+ */
+public class SysRole extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 角色ID
+     */
+    @Excel(name = "角色序号" , cellType = ColumnType.NUMERIC)
+    private Long roleId;
+
+    /**
+     * 角色名称
+     */
+    @Excel(name = "角色名称")
+    private String roleName;
+
+    /**
+     * 角色权限
+     */
+    @Excel(name = "角色权限")
+    private String roleKey;
+
+    /**
+     * 角色排序
+     */
+    @Excel(name = "角色排序")
+    private Integer roleSort;
+
+    /**
+     * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)
+     */
+    @Excel(name = "数据范围" , readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
+    private String dataScope;
+
+    /**
+     * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示)
+     */
+    private boolean menuCheckStrictly;
+
+    /**
+     * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 )
+     */
+    private boolean deptCheckStrictly;
+
+    /**
+     * 角色状态(0正常 1停用)
+     */
+    @Excel(name = "角色状态" , readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    private String delFlag;
+
+    /**
+     * 用户是否存在此角色标识 默认不存在
+     */
+    private boolean flag = false;
+
+    /**
+     * 菜单组
+     */
+    private Long[] menuIds;
+
+    /**
+     * 部门组(数据权限)
+     */
+    private Long[] deptIds;
+
+    /**
+     * 角色菜单权限
+     */
+    private Set<String> permissions;
+
+    public SysRole() {
+
+    }
+
+    public SysRole(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    public static boolean isAdmin(Long roleId) {
+        return roleId != null && 1L == roleId;
+    }
+
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    public boolean isAdmin() {
+        return isAdmin(this.roleId);
+    }
+
+    @NotBlank(message = "角色名称不能为空")
+    @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
+    public String getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName) {
+        this.roleName = roleName;
+    }
+
+    @NotBlank(message = "权限字符不能为空")
+    @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
+    public String getRoleKey() {
+        return roleKey;
+    }
+
+    public void setRoleKey(String roleKey) {
+        this.roleKey = roleKey;
+    }
+
+    @NotNull(message = "显示顺序不能为空")
+    public Integer getRoleSort() {
+        return roleSort;
+    }
+
+    public void setRoleSort(Integer roleSort) {
+        this.roleSort = roleSort;
+    }
+
+    public String getDataScope() {
+        return dataScope;
+    }
+
+    public void setDataScope(String dataScope) {
+        this.dataScope = dataScope;
+    }
+
+    public boolean isMenuCheckStrictly() {
+        return menuCheckStrictly;
+    }
+
+    public void setMenuCheckStrictly(boolean menuCheckStrictly) {
+        this.menuCheckStrictly = menuCheckStrictly;
+    }
+
+    public boolean isDeptCheckStrictly() {
+        return deptCheckStrictly;
+    }
+
+    public void setDeptCheckStrictly(boolean deptCheckStrictly) {
+        this.deptCheckStrictly = deptCheckStrictly;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getDelFlag() {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    public boolean isFlag() {
+        return flag;
+    }
+
+    public void setFlag(boolean flag) {
+        this.flag = flag;
+    }
+
+    public Long[] getMenuIds() {
+        return menuIds;
+    }
+
+    public void setMenuIds(Long[] menuIds) {
+        this.menuIds = menuIds;
+    }
+
+    public Long[] getDeptIds() {
+        return deptIds;
+    }
+
+    public void setDeptIds(Long[] deptIds) {
+        this.deptIds = deptIds;
+    }
+
+    public Set<String> getPermissions() {
+        return permissions;
+    }
+
+    public void setPermissions(Set<String> permissions) {
+        this.permissions = permissions;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("roleId" , getRoleId())
+                .append("roleName" , getRoleName())
+                .append("roleKey" , getRoleKey())
+                .append("roleSort" , getRoleSort())
+                .append("dataScope" , getDataScope())
+                .append("menuCheckStrictly" , isMenuCheckStrictly())
+                .append("deptCheckStrictly" , isDeptCheckStrictly())
+                .append("status" , getStatus())
+                .append("delFlag" , getDelFlag())
+                .append("createBy" , getCreateBy())
+                .append("createTime" , getCreateTime())
+                .append("updateBy" , getUpdateBy())
+                .append("updateTime" , getUpdateTime())
+                .append("remark" , getRemark())
+                .toString();
+    }
+}

+ 322 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/domain/SysUser.java

@@ -0,0 +1,322 @@
+package com.sooka.system.api.domain;
+
+import com.sooka.common.core.annotation.Excel;
+import com.sooka.common.core.annotation.Excel.ColumnType;
+import com.sooka.common.core.annotation.Excel.Type;
+import com.sooka.common.core.annotation.Excels;
+import com.sooka.common.core.web.domain.BaseEntity;
+import com.sooka.common.core.xss.Xss;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 用户对象 sys_user
+ *
+ * @author sooka
+ */
+public class SysUser extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户ID
+     */
+    @Excel(name = "用户序号" , cellType = ColumnType.NUMERIC, prompt = "用户编号")
+    private Long userId;
+
+    /**
+     * 部门ID
+     */
+    @Excel(name = "部门编号" , type = Type.IMPORT)
+    private Long deptId;
+
+    /**
+     * 用户账号
+     */
+    @Excel(name = "登录名称")
+    private String userName;
+
+    /**
+     * 用户昵称
+     */
+    @Excel(name = "用户名称")
+    private String nickName;
+
+    /**
+     * 用户邮箱
+     */
+    @Excel(name = "用户邮箱")
+    private String email;
+
+    /**
+     * 手机号码
+     */
+    @Excel(name = "手机号码")
+    private String phonenumber;
+
+    /**
+     * 用户性别
+     */
+    @Excel(name = "用户性别" , readConverterExp = "0=男,1=女,2=未知")
+    private String sex;
+
+    /**
+     * 用户头像
+     */
+    private String avatar;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 帐号状态(0正常 1停用)
+     */
+    @Excel(name = "帐号状态" , readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    private String delFlag;
+
+    /**
+     * 最后登录IP
+     */
+    @Excel(name = "最后登录IP" , type = Type.EXPORT)
+    private String loginIp;
+
+    /**
+     * 最后登录时间
+     */
+    @Excel(name = "最后登录时间" , width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss" , type = Type.EXPORT)
+    private Date loginDate;
+
+    /**
+     * 部门对象
+     */
+    @Excels({
+            @Excel(name = "部门名称" , targetAttr = "deptName" , type = Type.EXPORT),
+            @Excel(name = "部门负责人" , targetAttr = "leader" , type = Type.EXPORT)
+    })
+    private SysDept dept;
+
+    /**
+     * 角色对象
+     */
+    private List<SysRole> roles;
+
+    /**
+     * 角色组
+     */
+    private Long[] roleIds;
+
+    /**
+     * 岗位组
+     */
+    private Long[] postIds;
+
+    /**
+     * 角色ID
+     */
+    private Long roleId;
+
+    public SysUser() {
+
+    }
+
+    public SysUser(Long userId) {
+        this.userId = userId;
+    }
+
+    public static boolean isAdmin(Long userId) {
+        return userId != null && 1L == userId;
+    }
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public boolean isAdmin() {
+        return isAdmin(this.userId);
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    @Xss(message = "用户昵称不能包含脚本字符")
+    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
+    public String getNickName() {
+        return nickName;
+    }
+
+    public void setNickName(String nickName) {
+        this.nickName = nickName;
+    }
+
+    @Xss(message = "用户账号不能包含脚本字符")
+    @NotBlank(message = "用户账号不能为空")
+    @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    @Email(message = "邮箱格式不正确")
+    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
+    public String getPhonenumber() {
+        return phonenumber;
+    }
+
+    public void setPhonenumber(String phonenumber) {
+        this.phonenumber = phonenumber;
+    }
+
+    public String getSex() {
+        return sex;
+    }
+
+    public void setSex(String sex) {
+        this.sex = sex;
+    }
+
+    public String getAvatar() {
+        return avatar;
+    }
+
+    public void setAvatar(String avatar) {
+        this.avatar = avatar;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getDelFlag() {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    public String getLoginIp() {
+        return loginIp;
+    }
+
+    public void setLoginIp(String loginIp) {
+        this.loginIp = loginIp;
+    }
+
+    public Date getLoginDate() {
+        return loginDate;
+    }
+
+    public void setLoginDate(Date loginDate) {
+        this.loginDate = loginDate;
+    }
+
+    public SysDept getDept() {
+        return dept;
+    }
+
+    public void setDept(SysDept dept) {
+        this.dept = dept;
+    }
+
+    public List<SysRole> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(List<SysRole> roles) {
+        this.roles = roles;
+    }
+
+    public Long[] getRoleIds() {
+        return roleIds;
+    }
+
+    public void setRoleIds(Long[] roleIds) {
+        this.roleIds = roleIds;
+    }
+
+    public Long[] getPostIds() {
+        return postIds;
+    }
+
+    public void setPostIds(Long[] postIds) {
+        this.postIds = postIds;
+    }
+
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("userId" , getUserId())
+                .append("deptId" , getDeptId())
+                .append("userName" , getUserName())
+                .append("nickName" , getNickName())
+                .append("email" , getEmail())
+                .append("phonenumber" , getPhonenumber())
+                .append("sex" , getSex())
+                .append("avatar" , getAvatar())
+                .append("password" , getPassword())
+                .append("status" , getStatus())
+                .append("delFlag" , getDelFlag())
+                .append("loginIp" , getLoginIp())
+                .append("loginDate" , getLoginDate())
+                .append("createBy" , getCreateBy())
+                .append("createTime" , getCreateTime())
+                .append("updateBy" , getUpdateBy())
+                .append("updateTime" , getUpdateTime())
+                .append("remark" , getRemark())
+                .append("dept" , getDept())
+                .toString();
+    }
+}

+ 31 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/factory/RemoteFileFallbackFactory.java

@@ -0,0 +1,31 @@
+package com.sooka.system.api.factory;
+
+import com.sooka.common.core.domain.R;
+import com.sooka.system.api.RemoteFileService;
+import com.sooka.system.api.domain.SysFile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.openfeign.FallbackFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * 文件服务降级处理
+ *
+ * @author sooka
+ */
+@Component
+public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileService> {
+    private static final Logger log = LoggerFactory.getLogger(RemoteFileFallbackFactory.class);
+
+    @Override
+    public RemoteFileService create(Throwable throwable) {
+        log.error("文件服务调用失败:{}" , throwable.getMessage());
+        return new RemoteFileService() {
+            @Override
+            public R<SysFile> upload(MultipartFile file) {
+                return R.fail("上传文件失败:" + throwable.getMessage());
+            }
+        };
+    }
+}

+ 37 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/factory/RemoteLogFallbackFactory.java

@@ -0,0 +1,37 @@
+package com.sooka.system.api.factory;
+
+import com.sooka.common.core.domain.R;
+import com.sooka.system.api.RemoteLogService;
+import com.sooka.system.api.domain.SysLogininfor;
+import com.sooka.system.api.domain.SysOperLog;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.openfeign.FallbackFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * 日志服务降级处理
+ *
+ * @author sooka
+ */
+@Component
+public class RemoteLogFallbackFactory implements FallbackFactory<RemoteLogService> {
+    private static final Logger log = LoggerFactory.getLogger(RemoteLogFallbackFactory.class);
+
+    @Override
+    public RemoteLogService create(Throwable throwable) {
+        log.error("日志服务调用失败:{}" , throwable.getMessage());
+        return new RemoteLogService() {
+            @Override
+            public R<Boolean> saveLog(SysOperLog sysOperLog, String source) {
+                return R.fail("保存操作日志失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Boolean> saveLogininfor(SysLogininfor sysLogininfor, String source) {
+                return R.fail("保存登录日志失败:" + throwable.getMessage());
+            }
+        };
+
+    }
+}

+ 36 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/factory/RemoteUserFallbackFactory.java

@@ -0,0 +1,36 @@
+package com.sooka.system.api.factory;
+
+import com.sooka.common.core.domain.R;
+import com.sooka.system.api.RemoteUserService;
+import com.sooka.system.api.domain.SysUser;
+import com.sooka.system.api.model.LoginUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.openfeign.FallbackFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * 用户服务降级处理
+ *
+ * @author sooka
+ */
+@Component
+public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserService> {
+    private static final Logger log = LoggerFactory.getLogger(RemoteUserFallbackFactory.class);
+
+    @Override
+    public RemoteUserService create(Throwable throwable) {
+        log.error("用户服务调用失败:{}" , throwable.getMessage());
+        return new RemoteUserService() {
+            @Override
+            public R<LoginUser> getUserInfo(String username, String source) {
+                return R.fail("获取用户失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Boolean> registerUserInfo(SysUser sysUser, String source) {
+                return R.fail("注册用户失败:" + throwable.getMessage());
+            }
+        };
+    }
+}

+ 132 - 0
sooka-api/sooka-api-system/src/main/java/com/sooka/system/api/model/LoginUser.java

@@ -0,0 +1,132 @@
+package com.sooka.system.api.model;
+
+import com.sooka.system.api.domain.SysUser;
+
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * 用户信息
+ *
+ * @author sooka
+ */
+public class LoginUser implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户唯一标识
+     */
+    private String token;
+
+    /**
+     * 用户名id
+     */
+    private Long userid;
+
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 登录时间
+     */
+    private Long loginTime;
+
+    /**
+     * 过期时间
+     */
+    private Long expireTime;
+
+    /**
+     * 登录IP地址
+     */
+    private String ipaddr;
+
+    /**
+     * 权限列表
+     */
+    private Set<String> permissions;
+
+    /**
+     * 角色列表
+     */
+    private Set<String> roles;
+
+    /**
+     * 用户信息
+     */
+    private SysUser sysUser;
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public Long getUserid() {
+        return userid;
+    }
+
+    public void setUserid(Long userid) {
+        this.userid = userid;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public Long getLoginTime() {
+        return loginTime;
+    }
+
+    public void setLoginTime(Long loginTime) {
+        this.loginTime = loginTime;
+    }
+
+    public Long getExpireTime() {
+        return expireTime;
+    }
+
+    public void setExpireTime(Long expireTime) {
+        this.expireTime = expireTime;
+    }
+
+    public String getIpaddr() {
+        return ipaddr;
+    }
+
+    public void setIpaddr(String ipaddr) {
+        this.ipaddr = ipaddr;
+    }
+
+    public Set<String> getPermissions() {
+        return permissions;
+    }
+
+    public void setPermissions(Set<String> permissions) {
+        this.permissions = permissions;
+    }
+
+    public Set<String> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(Set<String> roles) {
+        this.roles = roles;
+    }
+
+    public SysUser getSysUser() {
+        return sysUser;
+    }
+
+    public void setSysUser(SysUser sysUser) {
+        this.sysUser = sysUser;
+    }
+}

+ 3 - 0
sooka-api/sooka-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -0,0 +1,3 @@
+com.sooka.system.api.factory.RemoteUserFallbackFactory
+com.sooka.system.api.factory.RemoteLogFallbackFactory
+com.sooka.system.api.factory.RemoteFileFallbackFactory

+ 74 - 0
sooka-auth/pom.xml

@@ -0,0 +1,74 @@
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.sooka</groupId>
+        <artifactId>sooka</artifactId>
+        <version>3.6.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sooka-auth</artifactId>
+
+    <description>
+        sooka-auth认证授权中心
+    </description>
+
+    <dependencies>
+
+        <!-- SpringCloud Alibaba Nacos -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+
+        <!-- SpringCloud Alibaba Nacos Config -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+
+        <!-- SpringCloud Alibaba Sentinel -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
+        </dependency>
+
+        <!-- SpringBoot Web -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- SpringBoot Actuator -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+
+        <!-- sooka Common Security-->
+        <dependency>
+            <groupId>com.sooka</groupId>
+            <artifactId>sooka-common-security</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 20 - 0
sooka-auth/src/main/java/com/sooka/auth/SookaAuthApplication.java

@@ -0,0 +1,20 @@
+package com.sooka.auth;
+
+import com.sooka.common.security.annotation.EnableRyFeignClients;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+
+/**
+ * 认证授权中心
+ *
+ * @author sooka
+ */
+@EnableRyFeignClients
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+public class SookaAuthApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(com.sooka.auth.SookaAuthApplication.class, args);
+        System.out.println("(♥◠‿◠)ノ゙  认证授权中心启动成功   ლ(´ڡ`ლ)゙ ");
+    }
+}

+ 72 - 0
sooka-auth/src/main/java/com/sooka/auth/controller/TokenController.java

@@ -0,0 +1,72 @@
+package com.sooka.auth.controller;
+
+import com.sooka.auth.form.LoginBody;
+import com.sooka.auth.form.RegisterBody;
+import com.sooka.auth.service.SysLoginService;
+import com.sooka.common.core.domain.R;
+import com.sooka.common.core.utils.JwtUtils;
+import com.sooka.common.core.utils.StringUtils;
+import com.sooka.common.security.auth.AuthUtil;
+import com.sooka.common.security.service.TokenService;
+import com.sooka.common.security.utils.SecurityUtils;
+import com.sooka.system.api.model.LoginUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * token 控制
+ *
+ * @author sooka
+ */
+@RestController
+public class TokenController {
+    @Autowired
+    private TokenService tokenService;
+
+    @Autowired
+    private SysLoginService sysLoginService;
+
+    @PostMapping("login")
+    public R<?> login(@RequestBody LoginBody form) {
+        // 用户登录
+        LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword());
+        // 获取登录token
+        return R.ok(tokenService.createToken(userInfo));
+    }
+
+    @DeleteMapping("logout")
+    public R<?> logout(HttpServletRequest request) {
+        String token = SecurityUtils.getToken(request);
+        if (StringUtils.isNotEmpty(token)) {
+            String username = JwtUtils.getUserName(token);
+            // 删除用户缓存记录
+            AuthUtil.logoutByToken(token);
+            // 记录用户退出日志
+            sysLoginService.logout(username);
+        }
+        return R.ok();
+    }
+
+    @PostMapping("refresh")
+    public R<?> refresh(HttpServletRequest request) {
+        LoginUser loginUser = tokenService.getLoginUser(request);
+        if (StringUtils.isNotNull(loginUser)) {
+            // 刷新令牌有效期
+            tokenService.refreshToken(loginUser);
+            return R.ok();
+        }
+        return R.ok();
+    }
+
+    @PostMapping("register")
+    public R<?> register(@RequestBody RegisterBody registerBody) {
+        // 用户注册
+        sysLoginService.register(registerBody.getUsername(), registerBody.getPassword());
+        return R.ok();
+    }
+}

+ 34 - 0
sooka-auth/src/main/java/com/sooka/auth/form/LoginBody.java

@@ -0,0 +1,34 @@
+package com.sooka.auth.form;
+
+/**
+ * 用户登录对象
+ *
+ * @author sooka
+ */
+public class LoginBody {
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 用户密码
+     */
+    private String password;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 10 - 0
sooka-auth/src/main/java/com/sooka/auth/form/RegisterBody.java

@@ -0,0 +1,10 @@
+package com.sooka.auth.form;
+
+/**
+ * 用户注册对象
+ *
+ * @author sooka
+ */
+public class RegisterBody extends LoginBody {
+
+}

+ 127 - 0
sooka-auth/src/main/java/com/sooka/auth/service/SysLoginService.java

@@ -0,0 +1,127 @@
+package com.sooka.auth.service;
+
+import com.sooka.common.core.constant.CacheConstants;
+import com.sooka.common.core.constant.Constants;
+import com.sooka.common.core.constant.SecurityConstants;
+import com.sooka.common.core.constant.UserConstants;
+import com.sooka.common.core.domain.R;
+import com.sooka.common.core.enums.UserStatus;
+import com.sooka.common.core.exception.ServiceException;
+import com.sooka.common.core.text.Convert;
+import com.sooka.common.core.utils.StringUtils;
+import com.sooka.common.core.utils.ip.IpUtils;
+import com.sooka.common.redis.service.RedisService;
+import com.sooka.common.security.utils.SecurityUtils;
+import com.sooka.system.api.RemoteUserService;
+import com.sooka.system.api.domain.SysUser;
+import com.sooka.system.api.model.LoginUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 登录校验方法
+ *
+ * @author sooka
+ */
+@Component
+public class SysLoginService {
+    @Autowired
+    private RemoteUserService remoteUserService;
+
+    @Autowired
+    private SysPasswordService passwordService;
+
+    @Autowired
+    private SysRecordLogService recordLogService;
+
+    @Autowired
+    private RedisService redisService;
+
+    /**
+     * 登录
+     */
+    public LoginUser login(String username, String password) {
+        // 用户名或密码为空 错误
+        if (StringUtils.isAnyBlank(username, password)) {
+            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写");
+            throw new ServiceException("用户/密码必须填写");
+        }
+        // 密码如果不在指定范围内 错误
+        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
+                || password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
+            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围");
+            throw new ServiceException("用户密码不在指定范围");
+        }
+        // 用户名不在指定范围内 错误
+        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
+                || username.length() > UserConstants.USERNAME_MAX_LENGTH) {
+            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围");
+            throw new ServiceException("用户名不在指定范围");
+        }
+        // IP黑名单校验
+        String blackStr = Convert.toStr(redisService.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST));
+        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) {
+            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "很遗憾,访问IP已被列入系统黑名单");
+            throw new ServiceException("很遗憾,访问IP已被列入系统黑名单");
+        }
+        // 查询用户信息
+        R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER);
+
+        if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) {
+            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在");
+            throw new ServiceException("登录用户:" + username + " 不存在");
+        }
+
+        if (R.FAIL == userResult.getCode()) {
+            throw new ServiceException(userResult.getMsg());
+        }
+
+        LoginUser userInfo = userResult.getData();
+        SysUser user = userResult.getData().getSysUser();
+        if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
+            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除");
+            throw new ServiceException("对不起,您的账号:" + username + " 已被删除");
+        }
+        if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员");
+            throw new ServiceException("对不起,您的账号:" + username + " 已停用");
+        }
+        passwordService.validate(user, password);
+        recordLogService.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功");
+        return userInfo;
+    }
+
+    public void logout(String loginName) {
+        recordLogService.recordLogininfor(loginName, Constants.LOGOUT, "退出成功");
+    }
+
+    /**
+     * 注册
+     */
+    public void register(String username, String password) {
+        // 用户名或密码为空 错误
+        if (StringUtils.isAnyBlank(username, password)) {
+            throw new ServiceException("用户/密码必须填写");
+        }
+        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
+                || username.length() > UserConstants.USERNAME_MAX_LENGTH) {
+            throw new ServiceException("账户长度必须在2到20个字符之间");
+        }
+        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
+                || password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
+            throw new ServiceException("密码长度必须在5到20个字符之间");
+        }
+
+        // 注册用户信息
+        SysUser sysUser = new SysUser();
+        sysUser.setUserName(username);
+        sysUser.setNickName(username);
+        sysUser.setPassword(SecurityUtils.encryptPassword(password));
+        R<?> registerResult = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER);
+
+        if (R.FAIL == registerResult.getCode()) {
+            throw new ServiceException(registerResult.getMsg());
+        }
+        recordLogService.recordLogininfor(username, Constants.REGISTER, "注册成功");
+    }
+}

+ 75 - 0
sooka-auth/src/main/java/com/sooka/auth/service/SysPasswordService.java

@@ -0,0 +1,75 @@
+package com.sooka.auth.service;
+
+import com.sooka.common.core.constant.CacheConstants;
+import com.sooka.common.core.constant.Constants;
+import com.sooka.common.core.exception.ServiceException;
+import com.sooka.common.redis.service.RedisService;
+import com.sooka.common.security.utils.SecurityUtils;
+import com.sooka.system.api.domain.SysUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 登录密码方法
+ *
+ * @author sooka
+ */
+@Component
+public class SysPasswordService {
+    @Autowired
+    private RedisService redisService;
+
+    private int maxRetryCount = CacheConstants.PASSWORD_MAX_RETRY_COUNT;
+
+    private Long lockTime = CacheConstants.PASSWORD_LOCK_TIME;
+
+    @Autowired
+    private SysRecordLogService recordLogService;
+
+    /**
+     * 登录账户密码错误次数缓存键名
+     *
+     * @param username 用户名
+     * @return 缓存键key
+     */
+    private String getCacheKey(String username) {
+        return CacheConstants.PWD_ERR_CNT_KEY + username;
+    }
+
+    public void validate(SysUser user, String password) {
+        String username = user.getUserName();
+
+        Integer retryCount = redisService.getCacheObject(getCacheKey(username));
+
+        if (retryCount == null) {
+            retryCount = 0;
+        }
+
+        if (retryCount >= Integer.valueOf(maxRetryCount).intValue()) {
+            String errMsg = String.format("密码输入错误%s次,帐户锁定%s分钟" , maxRetryCount, lockTime);
+            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, errMsg);
+            throw new ServiceException(errMsg);
+        }
+
+        if (!matches(user, password)) {
+            retryCount = retryCount + 1;
+            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, String.format("密码输入错误%s次" , retryCount));
+            redisService.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
+            throw new ServiceException("用户不存在/密码错误");
+        } else {
+            clearLoginRecordCache(username);
+        }
+    }
+
+    public boolean matches(SysUser user, String rawPassword) {
+        return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
+    }
+
+    public void clearLoginRecordCache(String loginName) {
+        if (redisService.hasKey(getCacheKey(loginName))) {
+            redisService.deleteObject(getCacheKey(loginName));
+        }
+    }
+}

+ 43 - 0
sooka-auth/src/main/java/com/sooka/auth/service/SysRecordLogService.java

@@ -0,0 +1,43 @@
+package com.sooka.auth.service;
+
+import com.sooka.common.core.constant.Constants;
+import com.sooka.common.core.constant.SecurityConstants;
+import com.sooka.common.core.utils.StringUtils;
+import com.sooka.common.core.utils.ip.IpUtils;
+import com.sooka.system.api.RemoteLogService;
+import com.sooka.system.api.domain.SysLogininfor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 记录日志方法
+ *
+ * @author sooka
+ */
+@Component
+public class SysRecordLogService {
+    @Autowired
+    private RemoteLogService remoteLogService;
+
+    /**
+     * 记录登录信息
+     *
+     * @param username 用户名
+     * @param status   状态
+     * @param message  消息内容
+     * @return
+     */
+    public void recordLogininfor(String username, String status, String message) {
+        SysLogininfor logininfor = new SysLogininfor();
+        logininfor.setUserName(username);
+        logininfor.setIpaddr(IpUtils.getIpAddr());
+        logininfor.setMsg(message);
+        // 日志状态
+        if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
+            logininfor.setStatus(Constants.LOGIN_SUCCESS_STATUS);
+        } else if (Constants.LOGIN_FAIL.equals(status)) {
+            logininfor.setStatus(Constants.LOGIN_FAIL_STATUS);
+        }
+        remoteLogService.saveLogininfor(logininfor, SecurityConstants.INNER);
+    }
+}

+ 2 - 0
sooka-auth/src/main/resources/banner.txt

@@ -0,0 +1,2 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}

+ 25 - 0
sooka-auth/src/main/resources/bootstrap.yml

@@ -0,0 +1,25 @@
+# Tomcat
+server:
+  port: 9200
+
+# Spring
+spring:
+  application:
+    # 应用名称
+    name: sooka-auth
+  profiles:
+    # 环境配置
+    active: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

+ 74 - 0
sooka-auth/src/main/resources/logback.xml

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+    <!-- 日志存放路径 -->
+    <property name="log.path" value="logs/sooka-auth"/>
+    <!-- 日志输出格式 -->
+    <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
+
+    <!-- 控制台输出 -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <!-- 系统日志输出 -->
+    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/info.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 60天 -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>INFO</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/error.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 60天 -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>ERROR</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 系统模块日志级别控制  -->
+    <logger name="com.sooka" level="info"/>
+    <!-- Spring日志级别控制  -->
+    <logger name="org.springframework" level="warn"/>
+
+    <root level="info">
+        <appender-ref ref="console"/>
+    </root>
+
+    <!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="file_info"/>
+        <appender-ref ref="file_error"/>
+    </root>
+</configuration>

+ 29 - 0
sooka-common/pom.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.sooka</groupId>
+        <artifactId>sooka</artifactId>
+        <version>3.6.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <modules>
+        <module>sooka-common-log</module>
+        <module>sooka-common-core</module>
+        <module>sooka-common-redis</module>
+        <module>sooka-common-seata</module>
+        <module>sooka-common-swagger</module>
+        <module>sooka-common-security</module>
+        <module>sooka-common-datascope</module>
+        <module>sooka-common-datasource</module>
+    </modules>
+
+    <artifactId>sooka-common</artifactId>
+    <packaging>pom</packaging>
+
+    <description>
+        sooka-common通用模块
+    </description>
+
+</project>

+ 118 - 0
sooka-common/sooka-common-core/pom.xml

@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.sooka</groupId>
+        <artifactId>sooka-common</artifactId>
+        <version>3.6.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sooka-common-core</artifactId>
+
+    <description>
+        sooka-common-core核心模块
+    </description>
+
+    <dependencies>
+
+        <!-- SpringCloud Openfeign -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+
+        <!-- SpringCloud Loadbalancer -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
+        </dependency>
+
+        <!-- Spring Context Support -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+        </dependency>
+
+        <!-- Spring Web -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+        </dependency>
+
+        <!-- Transmittable ThreadLocal -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>transmittable-thread-local</artifactId>
+        </dependency>
+
+        <!-- Pagehelper -->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- Hibernate Validator -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!-- Jackson -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <!-- Alibaba Fastjson -->
+        <dependency>
+            <groupId>com.alibaba.fastjson2</groupId>
+            <artifactId>fastjson2</artifactId>
+        </dependency>
+
+        <!-- Jwt -->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+        </dependency>
+
+        <!-- Jaxb -->
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+        </dependency>
+
+        <!-- Apache Lang3 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+
+        <!-- Commons Io -->
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+        <!-- excel工具 -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+        </dependency>
+
+        <!-- Java Servlet -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+
+        <!-- Swagger -->
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 176 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/annotation/Excel.java

@@ -0,0 +1,176 @@
+package com.sooka.common.core.annotation;
+
+import com.sooka.common.core.utils.poi.ExcelHandlerAdapter;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+
+/**
+ * 自定义导出Excel数据注解
+ *
+ * @author sooka
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Excel {
+    /**
+     * 导出时在excel中排序
+     */
+    public int sort() default Integer.MAX_VALUE;
+
+    /**
+     * 导出到Excel中的名字.
+     */
+    public String name() default "";
+
+    /**
+     * 日期格式, 如: yyyy-MM-dd
+     */
+    public String dateFormat() default "";
+
+    /**
+     * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+     */
+    public String readConverterExp() default "";
+
+    /**
+     * 分隔符,读取字符串组内容
+     */
+    public String separator() default ",";
+
+    /**
+     * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
+     */
+    public int scale() default -1;
+
+    /**
+     * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
+     */
+    public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
+
+    /**
+     * 导出时在excel中每个列的高度
+     */
+    public double height() default 14;
+
+    /**
+     * 导出时在excel中每个列的宽度
+     */
+    public double width() default 16;
+
+    /**
+     * 文字后缀,如% 90 变成90%
+     */
+    public String suffix() default "";
+
+    /**
+     * 当值为空时,字段的默认值
+     */
+    public String defaultValue() default "";
+
+    /**
+     * 提示信息
+     */
+    public String prompt() default "";
+
+    /**
+     * 设置只能选择不能输入的列内容.
+     */
+    public String[] combo() default {};
+
+    /**
+     * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
+     */
+    public boolean needMerge() default false;
+
+    /**
+     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
+     */
+    public boolean isExport() default true;
+
+    /**
+     * 另一个类中的属性名称,支持多级获取,以小数点隔开
+     */
+    public String targetAttr() default "";
+
+    /**
+     * 是否自动统计数据,在最后追加一行统计数据总和
+     */
+    public boolean isStatistics() default false;
+
+    /**
+     * 导出类型(0数字 1字符串)
+     */
+    public ColumnType cellType() default ColumnType.STRING;
+
+    /**
+     * 导出列头背景颜色
+     */
+    public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
+
+    /**
+     * 导出列头字体颜色
+     */
+    public IndexedColors headerColor() default IndexedColors.WHITE;
+
+    /**
+     * 导出单元格背景颜色
+     */
+    public IndexedColors backgroundColor() default IndexedColors.WHITE;
+
+    /**
+     * 导出单元格字体颜色
+     */
+    public IndexedColors color() default IndexedColors.BLACK;
+
+    /**
+     * 导出字段对齐方式
+     */
+    public HorizontalAlignment align() default HorizontalAlignment.CENTER;
+
+    /**
+     * 自定义数据处理器
+     */
+    public Class<?> handler() default ExcelHandlerAdapter.class;
+
+    /**
+     * 自定义数据处理器参数
+     */
+    public String[] args() default {};
+
+    /**
+     * 字段类型(0:导出导入;1:仅导出;2:仅导入)
+     */
+    Type type() default Type.ALL;
+
+    public enum Type {
+        ALL(0), EXPORT(1), IMPORT(2);
+        private final int value;
+
+        Type(int value) {
+            this.value = value;
+        }
+
+        public int value() {
+            return this.value;
+        }
+    }
+
+    public enum ColumnType {
+        NUMERIC(0), STRING(1), IMAGE(2);
+        private final int value;
+
+        ColumnType(int value) {
+            this.value = value;
+        }
+
+        public int value() {
+            return this.value;
+        }
+    }
+}

+ 17 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/annotation/Excels.java

@@ -0,0 +1,17 @@
+package com.sooka.common.core.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Excel注解集
+ *
+ * @author sooka
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Excels {
+    Excel[] value();
+}

+ 58 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/CacheConstants.java

@@ -0,0 +1,58 @@
+package com.sooka.common.core.constant;
+
+/**
+ * 缓存常量信息
+ *
+ * @author sooka
+ */
+public class CacheConstants {
+    /**
+     * 缓存有效期,默认720(分钟)
+     */
+    public final static long EXPIRATION = 720;
+
+    /**
+     * 缓存刷新时间,默认120(分钟)
+     */
+    public final static long REFRESH_TIME = 120;
+
+    /**
+     * 密码最大错误次数
+     */
+    public final static int PASSWORD_MAX_RETRY_COUNT = 5;
+
+    /**
+     * 密码锁定时间,默认10(分钟)
+     */
+    public final static long PASSWORD_LOCK_TIME = 10;
+
+    /**
+     * 权限缓存前缀
+     */
+    public final static String LOGIN_TOKEN_KEY = "login_tokens:";
+
+    /**
+     * 验证码 redis key
+     */
+    public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
+
+    /**
+     * 参数管理 cache key
+     */
+    public static final String SYS_CONFIG_KEY = "sys_config:";
+
+    /**
+     * 字典管理 cache key
+     */
+    public static final String SYS_DICT_KEY = "sys_dict:";
+
+    /**
+     * 登录账户密码错误次数 redis key
+     */
+    public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
+
+    /**
+     * 登录IP黑名单 cache key
+     */
+    public static final String SYS_LOGIN_BLACKIPLIST = SYS_CONFIG_KEY + "sys.login.blackIPList";
+}

+ 134 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/Constants.java

@@ -0,0 +1,134 @@
+package com.sooka.common.core.constant;
+
+/**
+ * 通用常量信息
+ *
+ * @author sooka
+ */
+public class Constants {
+    /**
+     * UTF-8 字符集
+     */
+    public static final String UTF8 = "UTF-8";
+
+    /**
+     * GBK 字符集
+     */
+    public static final String GBK = "GBK";
+
+    /**
+     * www主域
+     */
+    public static final String WWW = "www.";
+
+    /**
+     * RMI 远程方法调用
+     */
+    public static final String LOOKUP_RMI = "rmi:";
+
+    /**
+     * LDAP 远程方法调用
+     */
+    public static final String LOOKUP_LDAP = "ldap:";
+
+    /**
+     * LDAPS 远程方法调用
+     */
+    public static final String LOOKUP_LDAPS = "ldaps:";
+
+    /**
+     * http请求
+     */
+    public static final String HTTP = "http://";
+
+    /**
+     * https请求
+     */
+    public static final String HTTPS = "https://";
+
+    /**
+     * 成功标记
+     */
+    public static final Integer SUCCESS = 200;
+
+    /**
+     * 失败标记
+     */
+    public static final Integer FAIL = 500;
+
+    /**
+     * 登录成功状态
+     */
+    public static final String LOGIN_SUCCESS_STATUS = "0";
+
+    /**
+     * 登录失败状态
+     */
+    public static final String LOGIN_FAIL_STATUS = "1";
+
+    /**
+     * 登录成功
+     */
+    public static final String LOGIN_SUCCESS = "Success";
+
+    /**
+     * 注销
+     */
+    public static final String LOGOUT = "Logout";
+
+    /**
+     * 注册
+     */
+    public static final String REGISTER = "Register";
+
+    /**
+     * 登录失败
+     */
+    public static final String LOGIN_FAIL = "Error";
+
+    /**
+     * 当前记录起始索引
+     */
+    public static final String PAGE_NUM = "pageNum";
+
+    /**
+     * 每页显示记录数
+     */
+    public static final String PAGE_SIZE = "pageSize";
+
+    /**
+     * 排序列
+     */
+    public static final String ORDER_BY_COLUMN = "orderByColumn";
+
+    /**
+     * 排序的方向 "desc" 或者 "asc".
+     */
+    public static final String IS_ASC = "isAsc";
+
+    /**
+     * 验证码有效期(分钟)
+     */
+    public static final long CAPTCHA_EXPIRATION = 2;
+
+    /**
+     * 资源映射路径 前缀
+     */
+    public static final String RESOURCE_PREFIX = "/profile";
+
+    /**
+     * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
+     */
+    public static final String[] JSON_WHITELIST_STR = {"org.springframework" , "com.sooka"};
+
+    /**
+     * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
+     */
+    public static final String[] JOB_WHITELIST_STR = {"com.sooka.job.task"};
+
+    /**
+     * 定时任务违规的字符
+     */
+    public static final String[] JOB_ERROR_STR = {"java.net.URL" , "javax.naming.InitialContext" , "org.yaml.snakeyaml" ,
+            "org.springframework" , "org.apache" , "com.sooka.common.core.utils.file"};
+}

+ 186 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/GenConstants.java

@@ -0,0 +1,186 @@
+package com.sooka.common.core.constant;
+
+/**
+ * 代码生成通用常量
+ *
+ * @author sooka
+ */
+public class GenConstants {
+    /**
+     * 单表(增删改查)
+     */
+    public static final String TPL_CRUD = "crud";
+
+    /**
+     * 树表(增删改查)
+     */
+    public static final String TPL_TREE = "tree";
+
+    /**
+     * 主子表(增删改查)
+     */
+    public static final String TPL_SUB = "sub";
+
+    /**
+     * 树编码字段
+     */
+    public static final String TREE_CODE = "treeCode";
+
+    /**
+     * 树父编码字段
+     */
+    public static final String TREE_PARENT_CODE = "treeParentCode";
+
+    /**
+     * 树名称字段
+     */
+    public static final String TREE_NAME = "treeName";
+
+    /**
+     * 上级菜单ID字段
+     */
+    public static final String PARENT_MENU_ID = "parentMenuId";
+
+    /**
+     * 上级菜单名称字段
+     */
+    public static final String PARENT_MENU_NAME = "parentMenuName";
+
+    /**
+     * 数据库字符串类型
+     */
+    public static final String[] COLUMNTYPE_STR = {"char" , "varchar" , "nvarchar" , "varchar2"};
+
+    /**
+     * 数据库文本类型
+     */
+    public static final String[] COLUMNTYPE_TEXT = {"tinytext" , "text" , "mediumtext" , "longtext"};
+
+    /**
+     * 数据库时间类型
+     */
+    public static final String[] COLUMNTYPE_TIME = {"datetime" , "time" , "date" , "timestamp"};
+
+    /**
+     * 数据库数字类型
+     */
+    public static final String[] COLUMNTYPE_NUMBER = {"tinyint" , "smallint" , "mediumint" , "int" , "number" , "integer" ,
+            "bit" , "bigint" , "float" , "double" , "decimal"};
+
+    /**
+     * 页面不需要编辑字段
+     */
+    public static final String[] COLUMNNAME_NOT_EDIT = {"id" , "create_by" , "create_time" , "del_flag"};
+
+    /**
+     * 页面不需要显示的列表字段
+     */
+    public static final String[] COLUMNNAME_NOT_LIST = {"id" , "create_by" , "create_time" , "del_flag" , "update_by" ,
+            "update_time"};
+
+    /**
+     * 页面不需要查询字段
+     */
+    public static final String[] COLUMNNAME_NOT_QUERY = {"id" , "create_by" , "create_time" , "del_flag" , "update_by" ,
+            "update_time" , "remark"};
+
+    /**
+     * Entity基类字段
+     */
+    public static final String[] BASE_ENTITY = {"createBy" , "createTime" , "updateBy" , "updateTime" , "remark"};
+
+    /**
+     * Tree基类字段
+     */
+    public static final String[] TREE_ENTITY = {"parentName" , "parentId" , "orderNum" , "ancestors"};
+
+    /**
+     * 文本框
+     */
+    public static final String HTML_INPUT = "input";
+
+    /**
+     * 文本域
+     */
+    public static final String HTML_TEXTAREA = "textarea";
+
+    /**
+     * 下拉框
+     */
+    public static final String HTML_SELECT = "select";
+
+    /**
+     * 单选框
+     */
+    public static final String HTML_RADIO = "radio";
+
+    /**
+     * 复选框
+     */
+    public static final String HTML_CHECKBOX = "checkbox";
+
+    /**
+     * 日期控件
+     */
+    public static final String HTML_DATETIME = "datetime";
+
+    /**
+     * 图片上传控件
+     */
+    public static final String HTML_IMAGE_UPLOAD = "imageUpload";
+
+    /**
+     * 文件上传控件
+     */
+    public static final String HTML_FILE_UPLOAD = "fileUpload";
+
+    /**
+     * 富文本控件
+     */
+    public static final String HTML_EDITOR = "editor";
+
+    /**
+     * 字符串类型
+     */
+    public static final String TYPE_STRING = "String";
+
+    /**
+     * 整型
+     */
+    public static final String TYPE_INTEGER = "Integer";
+
+    /**
+     * 长整型
+     */
+    public static final String TYPE_LONG = "Long";
+
+    /**
+     * 浮点型
+     */
+    public static final String TYPE_DOUBLE = "Double";
+
+    /**
+     * 高精度计算类型
+     */
+    public static final String TYPE_BIGDECIMAL = "BigDecimal";
+
+    /**
+     * 时间类型
+     */
+    public static final String TYPE_DATE = "Date";
+
+    /**
+     * 模糊查询
+     */
+    public static final String QUERY_LIKE = "LIKE";
+
+    /**
+     * 相等查询
+     */
+    public static final String QUERY_EQ = "EQ";
+
+    /**
+     * 需要
+     */
+    public static final String REQUIRE = "1";
+}

+ 93 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/HttpStatus.java

@@ -0,0 +1,93 @@
+package com.sooka.common.core.constant;
+
+/**
+ * 返回状态码
+ *
+ * @author sooka
+ */
+public class HttpStatus {
+    /**
+     * 操作成功
+     */
+    public static final int SUCCESS = 200;
+
+    /**
+     * 对象创建成功
+     */
+    public static final int CREATED = 201;
+
+    /**
+     * 请求已经被接受
+     */
+    public static final int ACCEPTED = 202;
+
+    /**
+     * 操作已经执行成功,但是没有返回数据
+     */
+    public static final int NO_CONTENT = 204;
+
+    /**
+     * 资源已被移除
+     */
+    public static final int MOVED_PERM = 301;
+
+    /**
+     * 重定向
+     */
+    public static final int SEE_OTHER = 303;
+
+    /**
+     * 资源没有被修改
+     */
+    public static final int NOT_MODIFIED = 304;
+
+    /**
+     * 参数列表错误(缺少,格式不匹配)
+     */
+    public static final int BAD_REQUEST = 400;
+
+    /**
+     * 未授权
+     */
+    public static final int UNAUTHORIZED = 401;
+
+    /**
+     * 访问受限,授权过期
+     */
+    public static final int FORBIDDEN = 403;
+
+    /**
+     * 资源,服务未找到
+     */
+    public static final int NOT_FOUND = 404;
+
+    /**
+     * 不允许的http方法
+     */
+    public static final int BAD_METHOD = 405;
+
+    /**
+     * 资源冲突,或者资源被锁
+     */
+    public static final int CONFLICT = 409;
+
+    /**
+     * 不支持的数据,媒体类型
+     */
+    public static final int UNSUPPORTED_TYPE = 415;
+
+    /**
+     * 系统内部错误
+     */
+    public static final int ERROR = 500;
+
+    /**
+     * 接口未实现
+     */
+    public static final int NOT_IMPLEMENTED = 501;
+
+    /**
+     * 系统警告消息
+     */
+    public static final int WARN = 601;
+}

+ 56 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/ScheduleConstants.java

@@ -0,0 +1,56 @@
+package com.sooka.common.core.constant;
+
+/**
+ * 任务调度通用常量
+ *
+ * @author sooka
+ */
+public class ScheduleConstants {
+    public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
+
+    /**
+     * 执行目标key
+     */
+    public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
+
+    /**
+     * 默认
+     */
+    public static final String MISFIRE_DEFAULT = "0";
+
+    /**
+     * 立即触发执行
+     */
+    public static final String MISFIRE_IGNORE_MISFIRES = "1";
+
+    /**
+     * 触发一次执行
+     */
+    public static final String MISFIRE_FIRE_AND_PROCEED = "2";
+
+    /**
+     * 不触发立即执行
+     */
+    public static final String MISFIRE_DO_NOTHING = "3";
+
+    public enum Status {
+        /**
+         * 正常
+         */
+        NORMAL("0"),
+        /**
+         * 暂停
+         */
+        PAUSE("1");
+
+        private String value;
+
+        private Status(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+}

+ 48 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/SecurityConstants.java

@@ -0,0 +1,48 @@
+package com.sooka.common.core.constant;
+
+/**
+ * 权限相关通用常量
+ *
+ * @author sooka
+ */
+public class SecurityConstants {
+    /**
+     * 用户ID字段
+     */
+    public static final String DETAILS_USER_ID = "user_id";
+
+    /**
+     * 用户名字段
+     */
+    public static final String DETAILS_USERNAME = "username";
+
+    /**
+     * 授权信息字段
+     */
+    public static final String AUTHORIZATION_HEADER = "authorization";
+
+    /**
+     * 请求来源
+     */
+    public static final String FROM_SOURCE = "from-source";
+
+    /**
+     * 内部请求
+     */
+    public static final String INNER = "inner";
+
+    /**
+     * 用户标识
+     */
+    public static final String USER_KEY = "user_key";
+
+    /**
+     * 登录用户
+     */
+    public static final String LOGIN_USER = "login_user";
+
+    /**
+     * 角色权限
+     */
+    public static final String ROLE_PERMISSION = "role_permission";
+}

+ 23 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/ServiceNameConstants.java

@@ -0,0 +1,23 @@
+package com.sooka.common.core.constant;
+
+/**
+ * 服务名称
+ *
+ * @author sooka
+ */
+public class ServiceNameConstants {
+    /**
+     * 认证服务的serviceid
+     */
+    public static final String AUTH_SERVICE = "sooka-auth";
+
+    /**
+     * 系统模块的serviceid
+     */
+    public static final String SYSTEM_SERVICE = "sooka-system";
+
+    /**
+     * 文件服务的serviceid
+     */
+    public static final String FILE_SERVICE = "sooka-file";
+}

+ 24 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/TokenConstants.java

@@ -0,0 +1,24 @@
+package com.sooka.common.core.constant;
+
+/**
+ * Token的Key常量
+ *
+ * @author sooka
+ */
+public class TokenConstants {
+    /**
+     * 令牌自定义标识
+     */
+    public static final String AUTHENTICATION = "Authorization";
+
+    /**
+     * 令牌前缀
+     */
+    public static final String PREFIX = "Bearer ";
+
+    /**
+     * 令牌秘钥
+     */
+    public final static String SECRET = "abcdefghijklmnopqrstuvwxyz";
+
+}

+ 113 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/constant/UserConstants.java

@@ -0,0 +1,113 @@
+package com.sooka.common.core.constant;
+
+/**
+ * 用户常量信息
+ *
+ * @author sooka
+ */
+public class UserConstants {
+    /**
+     * 平台内系统用户的唯一标志
+     */
+    public static final String SYS_USER = "SYS_USER";
+
+    /**
+     * 正常状态
+     */
+    public static final String NORMAL = "0";
+
+    /**
+     * 异常状态
+     */
+    public static final String EXCEPTION = "1";
+
+    /**
+     * 用户封禁状态
+     */
+    public static final String USER_DISABLE = "1";
+
+    /**
+     * 角色封禁状态
+     */
+    public static final String ROLE_DISABLE = "1";
+
+    /**
+     * 部门正常状态
+     */
+    public static final String DEPT_NORMAL = "0";
+
+    /**
+     * 部门停用状态
+     */
+    public static final String DEPT_DISABLE = "1";
+
+    /**
+     * 字典正常状态
+     */
+    public static final String DICT_NORMAL = "0";
+
+    /**
+     * 是否为系统默认(是)
+     */
+    public static final String YES = "Y";
+
+    /**
+     * 是否菜单外链(是)
+     */
+    public static final String YES_FRAME = "0";
+
+    /**
+     * 是否菜单外链(否)
+     */
+    public static final String NO_FRAME = "1";
+
+    /**
+     * 菜单类型(目录)
+     */
+    public static final String TYPE_DIR = "M";
+
+    /**
+     * 菜单类型(菜单)
+     */
+    public static final String TYPE_MENU = "C";
+
+    /**
+     * 菜单类型(按钮)
+     */
+    public static final String TYPE_BUTTON = "F";
+
+    /**
+     * Layout组件标识
+     */
+    public final static String LAYOUT = "Layout";
+
+    /**
+     * ParentView组件标识
+     */
+    public final static String PARENT_VIEW = "ParentView";
+
+    /**
+     * InnerLink组件标识
+     */
+    public final static String INNER_LINK = "InnerLink";
+
+    /**
+     * 校验是否唯一的返回标识
+     */
+    public final static boolean UNIQUE = true;
+    public final static boolean NOT_UNIQUE = false;
+
+    /**
+     * 用户名长度限制
+     */
+    public static final int USERNAME_MIN_LENGTH = 2;
+
+    public static final int USERNAME_MAX_LENGTH = 20;
+
+    /**
+     * 密码长度限制
+     */
+    public static final int PASSWORD_MIN_LENGTH = 5;
+
+    public static final int PASSWORD_MAX_LENGTH = 20;
+}

+ 83 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/context/SecurityContextHolder.java

@@ -0,0 +1,83 @@
+package com.sooka.common.core.context;
+
+import com.alibaba.ttl.TransmittableThreadLocal;
+import com.sooka.common.core.constant.SecurityConstants;
+import com.sooka.common.core.text.Convert;
+import com.sooka.common.core.utils.StringUtils;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 获取当前线程变量中的 用户id、用户名称、Token等信息
+ * 注意: 必须在网关通过请求头的方法传入,同时在HeaderInterceptor拦截器设置值。 否则这里无法获取
+ *
+ * @author sooka
+ */
+public class SecurityContextHolder {
+    private static final TransmittableThreadLocal<Map<String, Object>> THREAD_LOCAL = new TransmittableThreadLocal<>();
+
+    public static void set(String key, Object value) {
+        Map<String, Object> map = getLocalMap();
+        map.put(key, value == null ? StringUtils.EMPTY : value);
+    }
+
+    public static String get(String key) {
+        Map<String, Object> map = getLocalMap();
+        return Convert.toStr(map.getOrDefault(key, StringUtils.EMPTY));
+    }
+
+    public static <T> T get(String key, Class<T> clazz) {
+        Map<String, Object> map = getLocalMap();
+        return StringUtils.cast(map.getOrDefault(key, null));
+    }
+
+    public static Map<String, Object> getLocalMap() {
+        Map<String, Object> map = THREAD_LOCAL.get();
+        if (map == null) {
+            map = new ConcurrentHashMap<String, Object>();
+            THREAD_LOCAL.set(map);
+        }
+        return map;
+    }
+
+    public static void setLocalMap(Map<String, Object> threadLocalMap) {
+        THREAD_LOCAL.set(threadLocalMap);
+    }
+
+    public static Long getUserId() {
+        return Convert.toLong(get(SecurityConstants.DETAILS_USER_ID), 0L);
+    }
+
+    public static void setUserId(String account) {
+        set(SecurityConstants.DETAILS_USER_ID, account);
+    }
+
+    public static String getUserName() {
+        return get(SecurityConstants.DETAILS_USERNAME);
+    }
+
+    public static void setUserName(String username) {
+        set(SecurityConstants.DETAILS_USERNAME, username);
+    }
+
+    public static String getUserKey() {
+        return get(SecurityConstants.USER_KEY);
+    }
+
+    public static void setUserKey(String userKey) {
+        set(SecurityConstants.USER_KEY, userKey);
+    }
+
+    public static String getPermission() {
+        return get(SecurityConstants.ROLE_PERMISSION);
+    }
+
+    public static void setPermission(String permissions) {
+        set(SecurityConstants.ROLE_PERMISSION, permissions);
+    }
+
+    public static void remove() {
+        THREAD_LOCAL.remove();
+    }
+}

+ 99 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/domain/R.java

@@ -0,0 +1,99 @@
+package com.sooka.common.core.domain;
+
+import com.sooka.common.core.constant.Constants;
+
+import java.io.Serializable;
+
+/**
+ * 响应信息主体
+ *
+ * @author sooka
+ */
+public class R<T> implements Serializable {
+    /**
+     * 成功
+     */
+    public static final int SUCCESS = Constants.SUCCESS;
+    /**
+     * 失败
+     */
+    public static final int FAIL = Constants.FAIL;
+    private static final long serialVersionUID = 1L;
+    private int code;
+
+    private String msg;
+
+    private T data;
+
+    public static <T> R<T> ok() {
+        return restResult(null, SUCCESS, null);
+    }
+
+    public static <T> R<T> ok(T data) {
+        return restResult(data, SUCCESS, null);
+    }
+
+    public static <T> R<T> ok(T data, String msg) {
+        return restResult(data, SUCCESS, msg);
+    }
+
+    public static <T> R<T> fail() {
+        return restResult(null, FAIL, null);
+    }
+
+    public static <T> R<T> fail(String msg) {
+        return restResult(null, FAIL, msg);
+    }
+
+    public static <T> R<T> fail(T data) {
+        return restResult(data, FAIL, null);
+    }
+
+    public static <T> R<T> fail(T data, String msg) {
+        return restResult(data, FAIL, msg);
+    }
+
+    public static <T> R<T> fail(int code, String msg) {
+        return restResult(null, code, msg);
+    }
+
+    private static <T> R<T> restResult(T data, int code, String msg) {
+        R<T> apiResult = new R<>();
+        apiResult.setCode(code);
+        apiResult.setData(data);
+        apiResult.setMsg(msg);
+        return apiResult;
+    }
+
+    public static <T> Boolean isError(R<T> ret) {
+        return !isSuccess(ret);
+    }
+
+    public static <T> Boolean isSuccess(R<T> ret) {
+        return R.SUCCESS == ret.getCode();
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+}

+ 26 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/enums/UserStatus.java

@@ -0,0 +1,26 @@
+package com.sooka.common.core.enums;
+
+/**
+ * 用户状态
+ *
+ * @author sooka
+ */
+public enum UserStatus {
+    OK("0" , "正常"), DISABLE("1" , "停用"), DELETED("2" , "删除");
+
+    private final String code;
+    private final String info;
+
+    UserStatus(String code, String info) {
+        this.code = code;
+        this.info = info;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getInfo() {
+        return info;
+    }
+}

+ 14 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/CaptchaException.java

@@ -0,0 +1,14 @@
+package com.sooka.common.core.exception;
+
+/**
+ * 验证码错误异常类
+ *
+ * @author sooka
+ */
+public class CaptchaException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public CaptchaException(String msg) {
+        super(msg);
+    }
+}

+ 26 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/CheckedException.java

@@ -0,0 +1,26 @@
+package com.sooka.common.core.exception;
+
+/**
+ * 检查异常
+ *
+ * @author sooka
+ */
+public class CheckedException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public CheckedException(String message) {
+        super(message);
+    }
+
+    public CheckedException(Throwable cause) {
+        super(cause);
+    }
+
+    public CheckedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public CheckedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

+ 13 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/DemoModeException.java

@@ -0,0 +1,13 @@
+package com.sooka.common.core.exception;
+
+/**
+ * 演示模式异常
+ *
+ * @author sooka
+ */
+public class DemoModeException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public DemoModeException() {
+    }
+}

+ 51 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/GlobalException.java

@@ -0,0 +1,51 @@
+package com.sooka.common.core.exception;
+
+/**
+ * 全局异常
+ *
+ * @author sooka
+ */
+public class GlobalException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 错误提示
+     */
+    private String message;
+
+    /**
+     * 错误明细,内部调试错误
+     * <p>
+     * 和 {@link CommonResult#getDetailMessage()} 一致的设计
+     */
+    private String detailMessage;
+
+    /**
+     * 空构造方法,避免反序列化问题
+     */
+    public GlobalException() {
+    }
+
+    public GlobalException(String message) {
+        this.message = message;
+    }
+
+    public String getDetailMessage() {
+        return detailMessage;
+    }
+
+    public GlobalException setDetailMessage(String detailMessage) {
+        this.detailMessage = detailMessage;
+        return this;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public GlobalException setMessage(String message) {
+        this.message = message;
+        return this;
+    }
+}

+ 14 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/InnerAuthException.java

@@ -0,0 +1,14 @@
+package com.sooka.common.core.exception;
+
+/**
+ * 内部认证异常
+ *
+ * @author sooka
+ */
+public class InnerAuthException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public InnerAuthException(String message) {
+        super(message);
+    }
+}

+ 13 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/PreAuthorizeException.java

@@ -0,0 +1,13 @@
+package com.sooka.common.core.exception;
+
+/**
+ * 权限异常
+ *
+ * @author sooka
+ */
+public class PreAuthorizeException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public PreAuthorizeException() {
+    }
+}

+ 65 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/ServiceException.java

@@ -0,0 +1,65 @@
+package com.sooka.common.core.exception;
+
+/**
+ * 业务异常
+ *
+ * @author sooka
+ */
+public final class ServiceException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 错误码
+     */
+    private Integer code;
+
+    /**
+     * 错误提示
+     */
+    private String message;
+
+    /**
+     * 错误明细,内部调试错误
+     * <p>
+     * 和 {@link CommonResult#getDetailMessage()} 一致的设计
+     */
+    private String detailMessage;
+
+    /**
+     * 空构造方法,避免反序列化问题
+     */
+    public ServiceException() {
+    }
+
+    public ServiceException(String message) {
+        this.message = message;
+    }
+
+    public ServiceException(String message, Integer code) {
+        this.message = message;
+        this.code = code;
+    }
+
+    public String getDetailMessage() {
+        return detailMessage;
+    }
+
+    public ServiceException setDetailMessage(String detailMessage) {
+        this.detailMessage = detailMessage;
+        return this;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public ServiceException setMessage(String message) {
+        this.message = message;
+        return this;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+}

+ 22 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/UtilException.java

@@ -0,0 +1,22 @@
+package com.sooka.common.core.exception;
+
+/**
+ * 工具类异常
+ *
+ * @author sooka
+ */
+public class UtilException extends RuntimeException {
+    private static final long serialVersionUID = 8247610319171014183L;
+
+    public UtilException(Throwable e) {
+        super(e.getMessage(), e);
+    }
+
+    public UtilException(String message) {
+        super(message);
+    }
+
+    public UtilException(String message, Throwable throwable) {
+        super(message, throwable);
+    }
+}

+ 14 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/auth/NotLoginException.java

@@ -0,0 +1,14 @@
+package com.sooka.common.core.exception.auth;
+
+/**
+ * 未能通过的登录认证异常
+ *
+ * @author sooka
+ */
+public class NotLoginException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public NotLoginException(String message) {
+        super(message);
+    }
+}

+ 20 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/auth/NotPermissionException.java

@@ -0,0 +1,20 @@
+package com.sooka.common.core.exception.auth;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 未能通过的权限认证异常
+ *
+ * @author sooka
+ */
+public class NotPermissionException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public NotPermissionException(String permission) {
+        super(permission);
+    }
+
+    public NotPermissionException(String[] permissions) {
+        super(StringUtils.join(permissions, ","));
+    }
+}

+ 20 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/auth/NotRoleException.java

@@ -0,0 +1,20 @@
+package com.sooka.common.core.exception.auth;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 未能通过的角色认证异常
+ *
+ * @author sooka
+ */
+public class NotRoleException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public NotRoleException(String role) {
+        super(role);
+    }
+
+    public NotRoleException(String[] roles) {
+        super(StringUtils.join(roles, ","));
+    }
+}

+ 69 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/base/BaseException.java

@@ -0,0 +1,69 @@
+package com.sooka.common.core.exception.base;
+
+/**
+ * 基础异常
+ *
+ * @author sooka
+ */
+public class BaseException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 所属模块
+     */
+    private String module;
+
+    /**
+     * 错误码
+     */
+    private String code;
+
+    /**
+     * 错误码对应的参数
+     */
+    private Object[] args;
+
+    /**
+     * 错误消息
+     */
+    private String defaultMessage;
+
+    public BaseException(String module, String code, Object[] args, String defaultMessage) {
+        this.module = module;
+        this.code = code;
+        this.args = args;
+        this.defaultMessage = defaultMessage;
+    }
+
+    public BaseException(String module, String code, Object[] args) {
+        this(module, code, args, null);
+    }
+
+    public BaseException(String module, String defaultMessage) {
+        this(module, null, null, defaultMessage);
+    }
+
+    public BaseException(String code, Object[] args) {
+        this(null, code, args, null);
+    }
+
+    public BaseException(String defaultMessage) {
+        this(null, null, null, defaultMessage);
+    }
+
+    public String getModule() {
+        return module;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public Object[] getArgs() {
+        return args;
+    }
+
+    public String getDefaultMessage() {
+        return defaultMessage;
+    }
+}

+ 17 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/file/FileException.java

@@ -0,0 +1,17 @@
+package com.sooka.common.core.exception.file;
+
+import com.sooka.common.core.exception.base.BaseException;
+
+/**
+ * 文件信息异常类
+ *
+ * @author sooka
+ */
+public class FileException extends BaseException {
+    private static final long serialVersionUID = 1L;
+
+    public FileException(String code, Object[] args, String msg) {
+        super("file" , code, args, msg);
+    }
+
+}

+ 14 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/file/FileNameLengthLimitExceededException.java

@@ -0,0 +1,14 @@
+package com.sooka.common.core.exception.file;
+
+/**
+ * 文件名称超长限制异常类
+ *
+ * @author sooka
+ */
+public class FileNameLengthLimitExceededException extends FileException {
+    private static final long serialVersionUID = 1L;
+
+    public FileNameLengthLimitExceededException(int defaultFileNameLength) {
+        super("upload.filename.exceed.length" , new Object[]{defaultFileNameLength}, "the filename is too long");
+    }
+}

+ 14 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/file/FileSizeLimitExceededException.java

@@ -0,0 +1,14 @@
+package com.sooka.common.core.exception.file;
+
+/**
+ * 文件名大小限制异常类
+ *
+ * @author sooka
+ */
+public class FileSizeLimitExceededException extends FileException {
+    private static final long serialVersionUID = 1L;
+
+    public FileSizeLimitExceededException(long defaultMaxSize) {
+        super("upload.exceed.maxSize" , new Object[]{defaultMaxSize}, "the filesize is too large");
+    }
+}

+ 52 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/file/FileUploadException.java

@@ -0,0 +1,52 @@
+package com.sooka.common.core.exception.file;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * 文件上传异常类
+ *
+ * @author sooka
+ */
+public class FileUploadException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    private final Throwable cause;
+
+    public FileUploadException() {
+        this(null, null);
+    }
+
+    public FileUploadException(final String msg) {
+        this(msg, null);
+    }
+
+    public FileUploadException(String msg, Throwable cause) {
+        super(msg);
+        this.cause = cause;
+    }
+
+    @Override
+    public void printStackTrace(PrintStream stream) {
+        super.printStackTrace(stream);
+        if (cause != null) {
+            stream.println("Caused by:");
+            cause.printStackTrace(stream);
+        }
+    }
+
+    @Override
+    public void printStackTrace(PrintWriter writer) {
+        super.printStackTrace(writer);
+        if (cause != null) {
+            writer.println("Caused by:");
+            cause.printStackTrace(writer);
+        }
+    }
+
+    @Override
+    public Throwable getCause() {
+        return cause;
+    }
+}

+ 0 - 0
sooka-common/sooka-common-core/src/main/java/com/sooka/common/core/exception/file/InvalidExtensionException.java


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است