Pārlūkot izejas kodu

日志demo第一次添加

bobo 3 gadi atpakaļ
revīzija
9881ae4582
100 mainītis faili ar 9232 papildinājumiem un 0 dzēšanām
  1. 20 0
      Future/LICENSE
  2. 112 0
      Future/README.md
  3. 12 0
      Future/bin/clean.bat
  4. 12 0
      Future/bin/package.bat
  5. 14 0
      Future/bin/run.bat
  6. BIN
      Future/doc/若依环境使用手册.docx
  7. 148 0
      Future/future-admin/pom.xml
  8. 32 0
      Future/future-admin/src/main/java/com/future/FutureApplication.java
  9. 18 0
      Future/future-admin/src/main/java/com/future/FutureServletInitializer.java
  10. 132 0
      Future/future-admin/src/main/java/com/future/config/SwaggerConfig.java
  11. 68 0
      Future/future-admin/src/main/java/com/future/filter/LogUserNameFilter.java
  12. 36 0
      Future/future-admin/src/main/java/com/future/module/area/controller/PmsBasePositiontController.java
  13. 32 0
      Future/future-admin/src/main/java/com/future/module/area/mapper/PmsBasePositionMapper.java
  14. 273 0
      Future/future-admin/src/main/java/com/future/module/area/mapper/PmsBasePositionMapper.xml
  15. 127 0
      Future/future-admin/src/main/java/com/future/module/area/model/entity/PmsBasePosition.java
  16. 810 0
      Future/future-admin/src/main/java/com/future/module/area/model/entity/PmsBasePositionExample.java
  17. 19 0
      Future/future-admin/src/main/java/com/future/module/area/model/vo/AreaVo.java
  18. 10 0
      Future/future-admin/src/main/java/com/future/module/area/service/PmsBasePositiontService.java
  19. 43 0
      Future/future-admin/src/main/java/com/future/module/area/service/impl/PmsBasePositiontServiceImpl.java
  20. 87 0
      Future/future-admin/src/main/java/com/future/module/common/controller/CaptchaController.java
  21. 119 0
      Future/future-admin/src/main/java/com/future/module/common/controller/CommonController.java
  22. 286 0
      Future/future-admin/src/main/java/com/future/module/demo/log/LogQuaController.java
  23. 272 0
      Future/future-admin/src/main/java/com/future/module/demo/log/MaskingPatternLayout.java
  24. 28 0
      Future/future-admin/src/main/java/com/future/module/demo/log/entity/DesensitizationTestEntity.java
  25. 89 0
      Future/future-admin/src/main/java/com/future/module/demo/log/entity/ErrorLogDemo.java
  26. 70 0
      Future/future-admin/src/main/java/com/future/module/demo/log/entity/LogEntityRealiztion.java
  27. 19 0
      Future/future-admin/src/main/java/com/future/module/demo/log/entity/LogUserInfo.java
  28. 15 0
      Future/future-admin/src/main/java/com/future/module/demo/log/entity/Symbol.java
  29. 53 0
      Future/future-admin/src/main/java/com/future/module/monitor/controller/CacheController.java
  30. 27 0
      Future/future-admin/src/main/java/com/future/module/monitor/controller/ServerController.java
  31. 67 0
      Future/future-admin/src/main/java/com/future/module/monitor/controller/SysLogininforController.java
  32. 66 0
      Future/future-admin/src/main/java/com/future/module/monitor/controller/SysOperlogController.java
  33. 92 0
      Future/future-admin/src/main/java/com/future/module/monitor/controller/SysUserOnlineController.java
  34. 135 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysConfigController.java
  35. 163 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysDeptController.java
  36. 120 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysDictDataController.java
  37. 131 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysDictTypeController.java
  38. 101 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysLoginController.java
  39. 157 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysMenuController.java
  40. 92 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysNoticeController.java
  41. 130 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysPostController.java
  42. 139 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysProfileController.java
  43. 182 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysRoleController.java
  44. 210 0
      Future/future-admin/src/main/java/com/future/module/system/controller/SysUserController.java
  45. 31 0
      Future/future-admin/src/main/java/com/future/module/tool/controller/SwaggerController.java
  46. 1 0
      Future/future-admin/src/main/resources/META-INF/spring-devtools.properties
  47. 57 0
      Future/future-admin/src/main/resources/application-druid.yml
  48. 141 0
      Future/future-admin/src/main/resources/application.yml
  49. 11 0
      Future/future-admin/src/main/resources/banner.txt
  50. 36 0
      Future/future-admin/src/main/resources/i18n/messages.properties
  51. 40 0
      Future/future-admin/src/main/resources/logConfig/logBackDBAppender.xml
  52. 97 0
      Future/future-admin/src/main/resources/logConfig/logBackDemo1.xml
  53. 38 0
      Future/future-admin/src/main/resources/logConfig/logBackFileAppender.xml
  54. 45 0
      Future/future-admin/src/main/resources/logConfig/logBackFixedWindowRollingPolicy.xml
  55. 45 0
      Future/future-admin/src/main/resources/logConfig/logBackSMTPAppender.xml
  56. 49 0
      Future/future-admin/src/main/resources/logConfig/logBackSiftingAppender.xml
  57. 110 0
      Future/future-admin/src/main/resources/logConfig/logbackDemo2.xml
  58. 112 0
      Future/future-admin/src/main/resources/logback.xml
  59. 15 0
      Future/future-admin/src/main/resources/mybatis/mybatis-config.xml
  60. 70 0
      Future/future-framework/pom.xml
  61. 169 0
      Future/future-framework/src/main/java/com/future/framework/aspectj/DataScopeAspect.java
  62. 72 0
      Future/future-framework/src/main/java/com/future/framework/aspectj/DataSourceAspect.java
  63. 246 0
      Future/future-framework/src/main/java/com/future/framework/aspectj/LogAspect.java
  64. 30 0
      Future/future-framework/src/main/java/com/future/framework/config/ApplicationConfig.java
  65. 83 0
      Future/future-framework/src/main/java/com/future/framework/config/CaptchaConfig.java
  66. 126 0
      Future/future-framework/src/main/java/com/future/framework/config/DruidConfig.java
  67. 71 0
      Future/future-framework/src/main/java/com/future/framework/config/FastJson2JsonRedisSerializer.java
  68. 60 0
      Future/future-framework/src/main/java/com/future/framework/config/FilterConfig.java
  69. 75 0
      Future/future-framework/src/main/java/com/future/framework/config/KaptchaTextCreator.java
  70. 132 0
      Future/future-framework/src/main/java/com/future/framework/config/MyBatisConfig.java
  71. 45 0
      Future/future-framework/src/main/java/com/future/framework/config/RedisConfig.java
  72. 66 0
      Future/future-framework/src/main/java/com/future/framework/config/ResourcesConfig.java
  73. 148 0
      Future/future-framework/src/main/java/com/future/framework/config/SecurityConfig.java
  74. 32 0
      Future/future-framework/src/main/java/com/future/framework/config/ServerConfig.java
  75. 62 0
      Future/future-framework/src/main/java/com/future/framework/config/ThreadPoolConfig.java
  76. 77 0
      Future/future-framework/src/main/java/com/future/framework/config/properties/DruidProperties.java
  77. 26 0
      Future/future-framework/src/main/java/com/future/framework/datasource/DynamicDataSource.java
  78. 45 0
      Future/future-framework/src/main/java/com/future/framework/datasource/DynamicDataSourceContextHolder.java
  79. 55 0
      Future/future-framework/src/main/java/com/future/framework/interceptor/RepeatSubmitInterceptor.java
  80. 125 0
      Future/future-framework/src/main/java/com/future/framework/interceptor/impl/SameUrlDataInterceptor.java
  81. 55 0
      Future/future-framework/src/main/java/com/future/framework/manager/AsyncManager.java
  82. 39 0
      Future/future-framework/src/main/java/com/future/framework/manager/ShutdownManager.java
  83. 101 0
      Future/future-framework/src/main/java/com/future/framework/manager/factory/AsyncFactory.java
  84. 44 0
      Future/future-framework/src/main/java/com/future/framework/security/filter/JwtAuthenticationTokenFilter.java
  85. 34 0
      Future/future-framework/src/main/java/com/future/framework/security/handle/AuthenticationEntryPointImpl.java
  86. 53 0
      Future/future-framework/src/main/java/com/future/framework/security/handle/LogoutSuccessHandlerImpl.java
  87. 240 0
      Future/future-framework/src/main/java/com/future/framework/web/domain/Server.java
  88. 101 0
      Future/future-framework/src/main/java/com/future/framework/web/domain/server/Cpu.java
  89. 122 0
      Future/future-framework/src/main/java/com/future/framework/web/domain/server/Jvm.java
  90. 61 0
      Future/future-framework/src/main/java/com/future/framework/web/domain/server/Mem.java
  91. 84 0
      Future/future-framework/src/main/java/com/future/framework/web/domain/server/Sys.java
  92. 114 0
      Future/future-framework/src/main/java/com/future/framework/web/domain/server/SysFile.java
  93. 126 0
      Future/future-framework/src/main/java/com/future/framework/web/exception/GlobalExceptionHandler.java
  94. 170 0
      Future/future-framework/src/main/java/com/future/framework/web/service/PermissionService.java
  95. 92 0
      Future/future-framework/src/main/java/com/future/framework/web/service/SysLoginService.java
  96. 68 0
      Future/future-framework/src/main/java/com/future/framework/web/service/SysPermissionService.java
  97. 220 0
      Future/future-framework/src/main/java/com/future/framework/web/service/TokenService.java
  98. 60 0
      Future/future-framework/src/main/java/com/future/framework/web/service/UserDetailsServiceImpl.java
  99. 37 0
      Future/future-gencodelocal/pom.xml
  100. 0 0
      Future/future-gencodelocal/src/main/java/com/CommentGenerator.java

+ 20 - 0
Future/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 future
+
+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.

+ 112 - 0
Future/README.md

@@ -0,0 +1,112 @@
+
+# 开发须知
+## 新增代码
+### 工具类
+    ShortCodeUtil 用于短编码生成 试用在邀请码,验证码等生成
+        ShortCodeUtil.generateShortUuid()
+    SnowFlakeUtil 用户组件id生成 采用雪花算法有效保证id的唯一性
+        SnowFlakeUtil snowFlakeUtil = new SnowFlakeUtil(2, 3);
+        snowFlakeUtil.nextId();
+### 返回体包装        
+    AjaxResultVo<Xxx> 接口实体返回推荐试用可定义泛型 用于Swagger返回体实体展示
+        AjaxResultVo.success(xxx)
+    TableDataInfo<Xxxx> 接口返回分页数据
+        TableDataInfo.getDataTable(list);
+## 推荐编码包结构
+    java
+        com.future
+            module (代码模块)
+                area
+                    controller
+                        XxxController
+                    mapper
+                        XxxMapper
+                        XxxMapper.xml
+                    model
+                        entity 
+                            Xxx 实体
+                        enum 
+                            XxxEnum 枚举
+                        form 
+                            XxxForm 表单实体
+                        parms 
+                            XxxParms 查询实体
+                        vo 
+                            XxxVo 返回实体
+                    service
+                        impl
+                            XxxServiceImpl
+                        XxxService
+
+
+## 平台简介
+
+Future是一套全部开源的快速开发平台.
+
+* 前端采用Vue、Element UI。
+* 后端采用Spring Boot、Spring Security、Redis & Jwt。
+* 权限认证使用Jwt,支持多终端认证系统。
+* 支持加载动态权限菜单,多方式轻松权限控制。
+* 高效率开发,使用代码生成器可以一键生成前后端代码。
+* 提供了单应用版本[future-Vue-fast](https://github.com/yangzongzhuan/future-Vue-fast),Oracle版本[future-Vue-Oracle](https://github.com/yangzongzhuan/future-Vue-Oracle),保持同步更新。
+* 不分离版本,请移步[future](https://gitee.com/y_project/future),微服务版本,请移步[future-Cloud](https://gitee.com/y_project/future-Cloud)
+* 特别鸣谢:[element](https://github.com/ElemeFE/element),[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin),[eladmin-web](https://github.com/elunez/eladmin-web)。
+
+## 内置功能
+
+1.  用户管理:用户是系统操作者,该功能主要完成系统用户配置。
+2.  部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
+3.  岗位管理:配置系统用户所属担任职务。
+4.  菜单管理:配置系统菜单,操作权限,按钮权限标识等。
+5.  角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
+6.  字典管理:对系统中经常使用的一些较为固定的数据进行维护。
+7.  参数管理:对系统动态配置常用参数。
+8.  通知公告:系统通知公告信息发布维护。
+9.  操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
+10. 登录日志:系统登录日志记录查询包含登录异常。
+11. 在线用户:当前系统中活跃用户状态监控。
+12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
+13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。
+14. 系统接口:根据业务代码自动生成相关的api接口文档。
+15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
+16. 缓存监控:对系统的缓存信息查询,命令统计等。
+17. 在线构建器:拖动表单元素生成相应的HTML代码。
+18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
+
+
+## 演示图
+
+<table>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/cd1f90be5f2684f4560c9519c0f2a232ee8.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-8074972883b5ba0622e13246738ebba237a.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-9f88719cdfca9af2e58b352a20e23d43b12.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-39bf2584ec3a529b0d5a3b70d15c9b37646.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-936ec82d1f4872e1bc980927654b6007307.png"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-b2d62ceb95d2dd9b3fbe157bb70d26001e9.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-d67451d308b7a79ad6819723396f7c3d77a.png"/></td>
+    </tr>	 
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-8370a0d02977eebf6dbf854c8450293c937.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-49003ed83f60f633e7153609a53a2b644f7.png"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-d4fe726319ece268d4746602c39cffc0621.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
+    </tr>
+</table>
+

+ 12 - 0
Future/bin/clean.bat

@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [ÐÅÏ¢] ÇåÀíÉú³É·¾¶¡£
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+call mvn clean
+
+pause

+ 12 - 0
Future/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
Future/bin/run.bat

@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [ÐÅÏ¢] ÔËÐÐWeb¹¤³Ì¡£
+echo.
+
+cd %~dp0
+cd ../ruoyi-admin/target
+
+set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
+
+java -jar %JAVA_OPTS% ruoyi-admin.jar
+
+cd bin
+pause

BIN
Future/doc/若依环境使用手册.docx


+ 148 - 0
Future/future-admin/pom.xml

@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>future</artifactId>
+        <groupId>com.future</groupId>
+        <version>3.4.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>future-admin</artifactId>
+
+    <description>
+        web服务入口
+    </description>
+
+    <dependencies>
+        <!-- spring-boot-devtools -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional> <!-- 表示依赖不会传递 -->
+        </dependency>
+
+        <!-- swagger2-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+        </dependency>
+
+        <!--防止进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.21版本-->
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>1.5.21</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.5.21</version>
+        </dependency>
+
+        <!-- swagger2-UI-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+        </dependency>
+
+        <!-- Mysql驱动包 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.future</groupId>
+            <artifactId>future-framework</artifactId>
+        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>com.future</groupId>-->
+<!--            <artifactId>future-log-starter</artifactId>-->
+<!--            <version>1.0.2</version>-->
+<!--        </dependency>-->
+
+        <!-- 定时任务-->
+        <dependency>
+            <groupId>com.future</groupId>
+            <artifactId>future-quartz</artifactId>
+        </dependency>
+
+        <!-- 代码生成-->
+        <dependency>
+            <groupId>com.future</groupId>
+            <artifactId>future-generator</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+            <version>2.0.7</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.codehaus.janino</groupId>
+            <artifactId>janino</artifactId>
+            <version>2.7.8</version>
+        </dependency>
+        <!-- email -->
+        <dependency>
+            <groupId>javax.mail</groupId>
+            <artifactId>mail</artifactId>
+            <version>1.4.7</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-dbcp</groupId>
+            <artifactId>commons-dbcp</artifactId>
+            <version>1.4</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.1.0</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+        <resources>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.properties</include>
+                    <include>**/*.xml</include>
+                </includes>
+                <filtering>false</filtering>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+        </resources>
+    </build>
+
+</project>

+ 32 - 0
Future/future-admin/src/main/java/com/future/FutureApplication.java

@@ -0,0 +1,32 @@
+package com.future;
+
+import com.future.framework.web.service.UserDetailsServiceImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+
+/**
+ * 启动程序
+ *
+ * @author future
+ */
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+public class FutureApplication {
+    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
+
+    public static void main(String[] args) {
+        // System.setProperty("spring.devtools.restart.enabled", "false");
+        SpringApplication.run(FutureApplication.class, args);
+        log.info("\n" +
+                "\n" +
+                "███████╗████████╗ █████╗ ██████╗ ████████╗   ██╗   ██╗██████╗ \n" +
+                "██╔════╝╚══██╔══╝██╔══██╗██╔══██╗╚══██╔══╝   ██║   ██║██╔══██╗\n" +
+                "███████╗   ██║   ███████║██████╔╝   ██║█████╗██║   ██║██████╔╝\n" +
+                "╚════██║   ██║   ██╔══██║██╔══██╗   ██║╚════╝██║   ██║██╔═══╝ \n" +
+                "███████║   ██║   ██║  ██║██║  ██║   ██║      ╚██████╔╝██║     \n" +
+                "╚══════╝   ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝       ╚═════╝ ╚═╝     \n");
+
+    }
+}

+ 18 - 0
Future/future-admin/src/main/java/com/future/FutureServletInitializer.java

@@ -0,0 +1,18 @@
+package com.future;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+/**
+ * web容器中进行部署
+ * 
+ * @author future
+ */
+public class FutureServletInitializer extends SpringBootServletInitializer
+{
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
+    {
+        return application.sources(FutureApplication.class);
+    }
+}

+ 132 - 0
Future/future-admin/src/main/java/com/future/config/SwaggerConfig.java

@@ -0,0 +1,132 @@
+package com.future.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.future.common.config.FutureConfig;
+import io.swagger.annotations.ApiOperation;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.ApiKey;
+import springfox.documentation.service.AuthorizationScope;
+import springfox.documentation.service.Contact;
+import springfox.documentation.service.SecurityReference;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * Swagger2的接口配置
+ *
+ * @author future
+ */
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig
+{
+    /** 系统基础配置 */
+    @Autowired
+    private FutureConfig futureConfig;
+
+    /** 是否开启swagger */
+    @Value("${swagger.enabled}")
+    private boolean enabled;
+
+    /** 设置请求的统一前缀 */
+    @Value("${swagger.pathMapping}")
+    private String pathMapping;
+
+    /**
+     * 创建API
+     */
+    @Bean
+    public Docket createRestApi()
+    {
+        return new Docket(DocumentationType.SWAGGER_2)
+                // 是否启用Swagger
+                .enable(enabled)
+                // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
+                .apiInfo(apiInfo())
+                // 设置哪些接口暴露给Swagger展示
+                .select()
+                // 扫描所有有注解的api,用这种方式更灵活
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                // 扫描指定包中的swagger注解
+                // .apis(RequestHandlerSelectors.basePackage("com.future.project.tool.swagger"))
+                // 扫描所有 .apis(RequestHandlerSelectors.any())
+                .paths(PathSelectors.any())
+                .build()
+                /* 设置安全模式,swagger可以设置访问token */
+                .securitySchemes(securitySchemes())
+                .securityContexts(securityContexts())
+                .pathMapping(pathMapping);
+    }
+
+    /**
+     * 安全模式,这里指定token通过Authorization头请求头传递
+     */
+    private List<ApiKey> securitySchemes()
+    {
+        List<ApiKey> apiKeyList = new ArrayList<ApiKey>();
+        apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
+        return apiKeyList;
+    }
+
+    /**
+     * 安全上下文
+     */
+    private List<SecurityContext> securityContexts()
+    {
+        List<SecurityContext> securityContexts = new ArrayList<>();
+        securityContexts.add(
+                SecurityContext.builder()
+                        .securityReferences(defaultAuth())
+                        .forPaths(PathSelectors.regex("^(?!auth).*$"))
+                        .build());
+        return securityContexts;
+    }
+
+    /**
+     * 默认的安全上引用
+     */
+    private List<SecurityReference> defaultAuth()
+    {
+        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+        authorizationScopes[0] = authorizationScope;
+        List<SecurityReference> securityReferences = new ArrayList<>();
+        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
+        return securityReferences;
+    }
+    /** 设置请求的统一前缀 */
+    @Value("${future.name}")
+    private String title;
+
+    /** 设置请求的统一前缀 */
+    @Value("${future.version}")
+    private String version;
+
+    /**
+     * 添加摘要信息
+     */
+    private ApiInfo apiInfo()
+    {
+        // 用ApiInfoBuilder进行定制
+        return new ApiInfoBuilder()
+                // 设置标题
+                .title(title+":"+version)
+                // 描述
+                .description(futureConfig.getDesc())
+                // 作者信息
+                .contact(new Contact(futureConfig.getName(), null, null))
+                // 版本
+                .version("版本号:" + futureConfig.getVersion())
+                .build();
+    }
+}

+ 68 - 0
Future/future-admin/src/main/java/com/future/filter/LogUserNameFilter.java

@@ -0,0 +1,68 @@
+package com.future.filter;
+
+import com.future.common.domain.HeaderMapRequestWrapper;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.spring.SpringUtils;
+import com.future.framework.web.service.TokenService;
+import com.future.system.domain.model.LoginUser;
+import com.future.system.utils.SecurityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.soap.MimeHeaders;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author qiubo
+ * @date 2021年05月14日 11:51
+ */
+@Component
+public class LogUserNameFilter implements Filter {
+//    Logger log  = LoggerFactory.getLogger(LogUserNameFilter.class);
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        LoginUser user = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
+        HttpServletRequest req = (HttpServletRequest) request;
+        if (user != null){
+
+            req.setAttribute("userName",user.getUsername());
+            boolean flag = false;
+            if (user.getUser() != null && user.getUser().getDept() != null){
+
+                req.setAttribute("deptName",user.getUser().getDept().getDeptName());
+                flag = true;
+            }
+
+            HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(req);
+            requestWrapper.addHeader("userName",user.getUsername());
+            if (flag){
+                requestWrapper.addHeader("deptName",user.getUser().getDept().getDeptName());
+            }
+            chain.doFilter(requestWrapper, response);
+        }else {
+            chain.doFilter(request, response);
+        }
+
+
+    }
+
+    private Map<String, String> getHeadKeyAndValue(HttpServletRequest httpRequest) {
+        Map<String, String> header = new HashMap<>();
+        Enumeration<String> headerNames = httpRequest.getHeaderNames();
+        while (headerNames.hasMoreElements()) {
+            String nextElement = headerNames.nextElement();
+            header.put(nextElement, httpRequest.getHeader(nextElement));
+        }
+        return header;
+    }
+}

+ 36 - 0
Future/future-admin/src/main/java/com/future/module/area/controller/PmsBasePositiontController.java

@@ -0,0 +1,36 @@
+package com.future.module.area.controller;
+
+
+import com.future.common.core.domain.AjaxResultVo;
+import com.future.common.validate.annotation.NullSize;
+import com.future.module.area.model.vo.AreaVo;
+import com.hwrj.cloud.portal.service.PmsBasePositiontService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@Api(tags="地址管理")
+@RequestMapping("/positiont")
+@Validated
+public class PmsBasePositiontController {
+
+    @Autowired
+    private PmsBasePositiontService pmsBasePositiontService;
+
+    @ApiOperation(value = "地址管理搜索、筛选")
+    @ApiImplicitParam(name = "parentId" , value = "父类id" , paramType = "query" , dataType = "String")
+    @GetMapping(value = "/search")
+    public AjaxResultVo<List<AreaVo>> search(@NullSize(min = 2, max = 20, message = "请检查数据长度!限制长度为[{min}-{max}]之间!")String parentId) {
+        List<AreaVo> list = pmsBasePositiontService.search(parentId);
+        return AjaxResultVo.success(list);
+    }
+
+}

+ 32 - 0
Future/future-admin/src/main/java/com/future/module/area/mapper/PmsBasePositionMapper.java

@@ -0,0 +1,32 @@
+package com.future.module.area.mapper;
+
+
+import java.util.List;
+
+import com.future.module.area.model.entity.PmsBasePosition;
+import com.future.module.area.model.entity.PmsBasePositionExample;
+import org.apache.ibatis.annotations.Param;
+
+public interface PmsBasePositionMapper {
+    long countByExample(PmsBasePositionExample example);
+
+    int deleteByExample(PmsBasePositionExample example);
+
+    int deleteByPrimaryKey(Integer id);
+
+    int insert(PmsBasePosition record);
+
+    int insertSelective(PmsBasePosition record);
+
+    List<PmsBasePosition> selectByExample(PmsBasePositionExample example);
+
+    PmsBasePosition selectByPrimaryKey(Integer id);
+
+    int updateByExampleSelective(@Param("record") PmsBasePosition record, @Param("example") PmsBasePositionExample example);
+
+    int updateByExample(@Param("record") PmsBasePosition record, @Param("example") PmsBasePositionExample example);
+
+    int updateByPrimaryKeySelective(PmsBasePosition record);
+
+    int updateByPrimaryKey(PmsBasePosition record);
+}

+ 273 - 0
Future/future-admin/src/main/java/com/future/module/area/mapper/PmsBasePositionMapper.xml

@@ -0,0 +1,273 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.future.module.area.mapper.PmsBasePositionMapper">
+  <resultMap id="BaseResultMap" type="com.future.module.area.model.entity.PmsBasePosition">
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="upCode" jdbcType="VARCHAR" property="upcode" />
+    <result column="name" jdbcType="VARCHAR" property="name" />
+    <result column="level" jdbcType="INTEGER" property="level" />
+    <result column="pinyin" jdbcType="VARCHAR" property="pinyin" />
+    <result column="acronym" jdbcType="VARCHAR" property="acronym" />
+    <result column="code" jdbcType="VARCHAR" property="code" />
+    <result column="areaCode" jdbcType="VARCHAR" property="areacode" />
+    <result column="zip" jdbcType="CHAR" property="zip" />
+  </resultMap>
+  <sql id="Example_Where_Clause">
+    <where>
+      <foreach collection="oredCriteria" item="criteria" separator="or">
+        <if test="criteria.valid">
+          <trim prefix="(" prefixOverrides="and" suffix=")">
+            <foreach collection="criteria.criteria" item="criterion">
+              <choose>
+                <when test="criterion.noValue">
+                  and ${criterion.condition}
+                </when>
+                <when test="criterion.singleValue">
+                  and ${criterion.condition} #{criterion.value}
+                </when>
+                <when test="criterion.betweenValue">
+                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+                </when>
+                <when test="criterion.listValue">
+                  and ${criterion.condition}
+                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
+                    #{listItem}
+                  </foreach>
+                </when>
+              </choose>
+            </foreach>
+          </trim>
+        </if>
+      </foreach>
+    </where>
+  </sql>
+  <sql id="Update_By_Example_Where_Clause">
+    <where>
+      <foreach collection="example.oredCriteria" item="criteria" separator="or">
+        <if test="criteria.valid">
+          <trim prefix="(" prefixOverrides="and" suffix=")">
+            <foreach collection="criteria.criteria" item="criterion">
+              <choose>
+                <when test="criterion.noValue">
+                  and ${criterion.condition}
+                </when>
+                <when test="criterion.singleValue">
+                  and ${criterion.condition} #{criterion.value}
+                </when>
+                <when test="criterion.betweenValue">
+                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+                </when>
+                <when test="criterion.listValue">
+                  and ${criterion.condition}
+                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
+                    #{listItem}
+                  </foreach>
+                </when>
+              </choose>
+            </foreach>
+          </trim>
+        </if>
+      </foreach>
+    </where>
+  </sql>
+  <sql id="Base_Column_List">
+    id, upCode, name, level, pinyin, acronym, code, areaCode, zip
+  </sql>
+  <select id="selectByExample" parameterType="com.future.module.area.model.entity.PmsBasePositionExample" resultMap="BaseResultMap">
+    select
+    <if test="distinct">
+      distinct
+    </if>
+    <include refid="Base_Column_List" />
+    from pms_base_position
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+    <if test="orderByClause != null">
+      order by ${orderByClause}
+    </if>
+  </select>
+  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
+    select 
+    <include refid="Base_Column_List" />
+    from pms_base_position
+    where id = #{id,jdbcType=INTEGER}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
+    delete from pms_base_position
+    where id = #{id,jdbcType=INTEGER}
+  </delete>
+  <delete id="deleteByExample" parameterType="com.future.module.area.model.entity.PmsBasePositionExample">
+    delete from pms_base_position
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+  </delete>
+  <insert id="insert" parameterType="com.future.module.area.model.entity.PmsBasePosition">
+    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
+      SELECT LAST_INSERT_ID()
+    </selectKey>
+    insert into pms_base_position (upCode, name, level, 
+      pinyin, acronym, code, 
+      areaCode, zip)
+    values (#{upcode,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{level,jdbcType=INTEGER}, 
+      #{pinyin,jdbcType=VARCHAR}, #{acronym,jdbcType=VARCHAR}, #{code,jdbcType=VARCHAR}, 
+      #{areacode,jdbcType=VARCHAR}, #{zip,jdbcType=CHAR})
+  </insert>
+  <insert id="insertSelective" parameterType="com.future.module.area.model.entity.PmsBasePosition">
+    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
+      SELECT LAST_INSERT_ID()
+    </selectKey>
+    insert into pms_base_position
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="upcode != null">
+        upCode,
+      </if>
+      <if test="name != null">
+        name,
+      </if>
+      <if test="level != null">
+        level,
+      </if>
+      <if test="pinyin != null">
+        pinyin,
+      </if>
+      <if test="acronym != null">
+        acronym,
+      </if>
+      <if test="code != null">
+        code,
+      </if>
+      <if test="areacode != null">
+        areaCode,
+      </if>
+      <if test="zip != null">
+        zip,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="upcode != null">
+        #{upcode,jdbcType=VARCHAR},
+      </if>
+      <if test="name != null">
+        #{name,jdbcType=VARCHAR},
+      </if>
+      <if test="level != null">
+        #{level,jdbcType=INTEGER},
+      </if>
+      <if test="pinyin != null">
+        #{pinyin,jdbcType=VARCHAR},
+      </if>
+      <if test="acronym != null">
+        #{acronym,jdbcType=VARCHAR},
+      </if>
+      <if test="code != null">
+        #{code,jdbcType=VARCHAR},
+      </if>
+      <if test="areacode != null">
+        #{areacode,jdbcType=VARCHAR},
+      </if>
+      <if test="zip != null">
+        #{zip,jdbcType=CHAR},
+      </if>
+    </trim>
+  </insert>
+  <select id="countByExample" parameterType="com.future.module.area.model.entity.PmsBasePositionExample" resultType="java.lang.Long">
+    select count(*) from pms_base_position
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+  </select>
+  <update id="updateByExampleSelective" parameterType="map">
+    update pms_base_position
+    <set>
+      <if test="record.id != null">
+        id = #{record.id,jdbcType=INTEGER},
+      </if>
+      <if test="record.upcode != null">
+        upCode = #{record.upcode,jdbcType=VARCHAR},
+      </if>
+      <if test="record.name != null">
+        name = #{record.name,jdbcType=VARCHAR},
+      </if>
+      <if test="record.level != null">
+        level = #{record.level,jdbcType=INTEGER},
+      </if>
+      <if test="record.pinyin != null">
+        pinyin = #{record.pinyin,jdbcType=VARCHAR},
+      </if>
+      <if test="record.acronym != null">
+        acronym = #{record.acronym,jdbcType=VARCHAR},
+      </if>
+      <if test="record.code != null">
+        code = #{record.code,jdbcType=VARCHAR},
+      </if>
+      <if test="record.areacode != null">
+        areaCode = #{record.areacode,jdbcType=VARCHAR},
+      </if>
+      <if test="record.zip != null">
+        zip = #{record.zip,jdbcType=CHAR},
+      </if>
+    </set>
+    <if test="_parameter != null">
+      <include refid="Update_By_Example_Where_Clause" />
+    </if>
+  </update>
+  <update id="updateByExample" parameterType="map">
+    update pms_base_position
+    set id = #{record.id,jdbcType=INTEGER},
+      upCode = #{record.upcode,jdbcType=VARCHAR},
+      name = #{record.name,jdbcType=VARCHAR},
+      level = #{record.level,jdbcType=INTEGER},
+      pinyin = #{record.pinyin,jdbcType=VARCHAR},
+      acronym = #{record.acronym,jdbcType=VARCHAR},
+      code = #{record.code,jdbcType=VARCHAR},
+      areaCode = #{record.areacode,jdbcType=VARCHAR},
+      zip = #{record.zip,jdbcType=CHAR}
+    <if test="_parameter != null">
+      <include refid="Update_By_Example_Where_Clause" />
+    </if>
+  </update>
+  <update id="updateByPrimaryKeySelective" parameterType="com.future.module.area.model.entity.PmsBasePosition">
+    update pms_base_position
+    <set>
+      <if test="upcode != null">
+        upCode = #{upcode,jdbcType=VARCHAR},
+      </if>
+      <if test="name != null">
+        name = #{name,jdbcType=VARCHAR},
+      </if>
+      <if test="level != null">
+        level = #{level,jdbcType=INTEGER},
+      </if>
+      <if test="pinyin != null">
+        pinyin = #{pinyin,jdbcType=VARCHAR},
+      </if>
+      <if test="acronym != null">
+        acronym = #{acronym,jdbcType=VARCHAR},
+      </if>
+      <if test="code != null">
+        code = #{code,jdbcType=VARCHAR},
+      </if>
+      <if test="areacode != null">
+        areaCode = #{areacode,jdbcType=VARCHAR},
+      </if>
+      <if test="zip != null">
+        zip = #{zip,jdbcType=CHAR},
+      </if>
+    </set>
+    where id = #{id,jdbcType=INTEGER}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.future.module.area.model.entity.PmsBasePosition">
+    update pms_base_position
+    set upCode = #{upcode,jdbcType=VARCHAR},
+      name = #{name,jdbcType=VARCHAR},
+      level = #{level,jdbcType=INTEGER},
+      pinyin = #{pinyin,jdbcType=VARCHAR},
+      acronym = #{acronym,jdbcType=VARCHAR},
+      code = #{code,jdbcType=VARCHAR},
+      areaCode = #{areacode,jdbcType=VARCHAR},
+      zip = #{zip,jdbcType=CHAR}
+    where id = #{id,jdbcType=INTEGER}
+  </update>
+</mapper>

+ 127 - 0
Future/future-admin/src/main/java/com/future/module/area/model/entity/PmsBasePosition.java

@@ -0,0 +1,127 @@
+package com.future.module.area.model.entity;
+
+import io.swagger.annotations.ApiModelProperty;
+import java.io.Serializable;
+
+public class PmsBasePosition implements Serializable {
+    @ApiModelProperty(value = "行政区域id")
+    private Integer id;
+
+    @ApiModelProperty(value = "上级行政区")
+    private String upcode;
+
+    @ApiModelProperty(value = "行政名称")
+    private String name;
+
+    @ApiModelProperty(value = "行政等级")
+    private Integer level;
+
+    @ApiModelProperty(value = "拼音码")
+    private String pinyin;
+
+    @ApiModelProperty(value = "首字母简码")
+    private String acronym;
+
+    @ApiModelProperty(value = "本地码")
+    private String code;
+
+    @ApiModelProperty(value = "区域码")
+    private String areacode;
+
+    @ApiModelProperty(value = "邮编")
+    private String zip;
+
+    private static final long serialVersionUID = 1L;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getUpcode() {
+        return upcode;
+    }
+
+    public void setUpcode(String upcode) {
+        this.upcode = upcode;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Integer getLevel() {
+        return level;
+    }
+
+    public void setLevel(Integer level) {
+        this.level = level;
+    }
+
+    public String getPinyin() {
+        return pinyin;
+    }
+
+    public void setPinyin(String pinyin) {
+        this.pinyin = pinyin;
+    }
+
+    public String getAcronym() {
+        return acronym;
+    }
+
+    public void setAcronym(String acronym) {
+        this.acronym = acronym;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getAreacode() {
+        return areacode;
+    }
+
+    public void setAreacode(String areacode) {
+        this.areacode = areacode;
+    }
+
+    public String getZip() {
+        return zip;
+    }
+
+    public void setZip(String zip) {
+        this.zip = zip;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", upcode=").append(upcode);
+        sb.append(", name=").append(name);
+        sb.append(", level=").append(level);
+        sb.append(", pinyin=").append(pinyin);
+        sb.append(", acronym=").append(acronym);
+        sb.append(", code=").append(code);
+        sb.append(", areacode=").append(areacode);
+        sb.append(", zip=").append(zip);
+        sb.append(", serialVersionUID=").append(serialVersionUID);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 810 - 0
Future/future-admin/src/main/java/com/future/module/area/model/entity/PmsBasePositionExample.java

@@ -0,0 +1,810 @@
+package com.future.module.area.model.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PmsBasePositionExample {
+    protected String orderByClause;
+
+    protected boolean distinct;
+
+    protected List<Criteria> oredCriteria;
+
+    public PmsBasePositionExample() {
+        oredCriteria = new ArrayList<Criteria>();
+    }
+
+    public void setOrderByClause(String orderByClause) {
+        this.orderByClause = orderByClause;
+    }
+
+    public String getOrderByClause() {
+        return orderByClause;
+    }
+
+    public void setDistinct(boolean distinct) {
+        this.distinct = distinct;
+    }
+
+    public boolean isDistinct() {
+        return distinct;
+    }
+
+    public List<Criteria> getOredCriteria() {
+        return oredCriteria;
+    }
+
+    public void or(Criteria criteria) {
+        oredCriteria.add(criteria);
+    }
+
+    public Criteria or() {
+        Criteria criteria = createCriteriaInternal();
+        oredCriteria.add(criteria);
+        return criteria;
+    }
+
+    public Criteria createCriteria() {
+        Criteria criteria = createCriteriaInternal();
+        if (oredCriteria.size() == 0) {
+            oredCriteria.add(criteria);
+        }
+        return criteria;
+    }
+
+    protected Criteria createCriteriaInternal() {
+        Criteria criteria = new Criteria();
+        return criteria;
+    }
+
+    public void clear() {
+        oredCriteria.clear();
+        orderByClause = null;
+        distinct = false;
+    }
+
+    protected abstract static class GeneratedCriteria {
+        protected List<Criterion> criteria;
+
+        protected GeneratedCriteria() {
+            super();
+            criteria = new ArrayList<Criterion>();
+        }
+
+        public boolean isValid() {
+            return criteria.size() > 0;
+        }
+
+        public List<Criterion> getAllCriteria() {
+            return criteria;
+        }
+
+        public List<Criterion> getCriteria() {
+            return criteria;
+        }
+
+        protected void addCriterion(String condition) {
+            if (condition == null) {
+                throw new RuntimeException("Value for condition cannot be null");
+            }
+            criteria.add(new Criterion(condition));
+        }
+
+        protected void addCriterion(String condition, Object value, String property) {
+            if (value == null) {
+                throw new RuntimeException("Value for " + property + " cannot be null");
+            }
+            criteria.add(new Criterion(condition, value));
+        }
+
+        protected void addCriterion(String condition, Object value1, Object value2, String property) {
+            if (value1 == null || value2 == null) {
+                throw new RuntimeException("Between values for " + property + " cannot be null");
+            }
+            criteria.add(new Criterion(condition, value1, value2));
+        }
+
+        public Criteria andIdIsNull() {
+            addCriterion("id is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdIsNotNull() {
+            addCriterion("id is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdEqualTo(Integer value) {
+            addCriterion("id =", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdNotEqualTo(Integer value) {
+            addCriterion("id <>", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdGreaterThan(Integer value) {
+            addCriterion("id >", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdGreaterThanOrEqualTo(Integer value) {
+            addCriterion("id >=", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdLessThan(Integer value) {
+            addCriterion("id <", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdLessThanOrEqualTo(Integer value) {
+            addCriterion("id <=", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdIn(List<Integer> values) {
+            addCriterion("id in", values, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdNotIn(List<Integer> values) {
+            addCriterion("id not in", values, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdBetween(Integer value1, Integer value2) {
+            addCriterion("id between", value1, value2, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdNotBetween(Integer value1, Integer value2) {
+            addCriterion("id not between", value1, value2, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeIsNull() {
+            addCriterion("upCode is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeIsNotNull() {
+            addCriterion("upCode is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeEqualTo(String value) {
+            addCriterion("upCode =", value, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeNotEqualTo(String value) {
+            addCriterion("upCode <>", value, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeGreaterThan(String value) {
+            addCriterion("upCode >", value, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeGreaterThanOrEqualTo(String value) {
+            addCriterion("upCode >=", value, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeLessThan(String value) {
+            addCriterion("upCode <", value, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeLessThanOrEqualTo(String value) {
+            addCriterion("upCode <=", value, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeLike(String value) {
+            addCriterion("upCode like", value, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeNotLike(String value) {
+            addCriterion("upCode not like", value, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeIn(List<String> values) {
+            addCriterion("upCode in", values, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeNotIn(List<String> values) {
+            addCriterion("upCode not in", values, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeBetween(String value1, String value2) {
+            addCriterion("upCode between", value1, value2, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpcodeNotBetween(String value1, String value2) {
+            addCriterion("upCode not between", value1, value2, "upcode");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameIsNull() {
+            addCriterion("name is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameIsNotNull() {
+            addCriterion("name is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameEqualTo(String value) {
+            addCriterion("name =", value, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameNotEqualTo(String value) {
+            addCriterion("name <>", value, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameGreaterThan(String value) {
+            addCriterion("name >", value, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameGreaterThanOrEqualTo(String value) {
+            addCriterion("name >=", value, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameLessThan(String value) {
+            addCriterion("name <", value, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameLessThanOrEqualTo(String value) {
+            addCriterion("name <=", value, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameLike(String value) {
+            addCriterion("name like", value, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameNotLike(String value) {
+            addCriterion("name not like", value, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameIn(List<String> values) {
+            addCriterion("name in", values, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameNotIn(List<String> values) {
+            addCriterion("name not in", values, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameBetween(String value1, String value2) {
+            addCriterion("name between", value1, value2, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andNameNotBetween(String value1, String value2) {
+            addCriterion("name not between", value1, value2, "name");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelIsNull() {
+            addCriterion("level is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelIsNotNull() {
+            addCriterion("level is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelEqualTo(Integer value) {
+            addCriterion("level =", value, "level");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelNotEqualTo(Integer value) {
+            addCriterion("level <>", value, "level");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelGreaterThan(Integer value) {
+            addCriterion("level >", value, "level");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelGreaterThanOrEqualTo(Integer value) {
+            addCriterion("level >=", value, "level");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelLessThan(Integer value) {
+            addCriterion("level <", value, "level");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelLessThanOrEqualTo(Integer value) {
+            addCriterion("level <=", value, "level");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelIn(List<Integer> values) {
+            addCriterion("level in", values, "level");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelNotIn(List<Integer> values) {
+            addCriterion("level not in", values, "level");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelBetween(Integer value1, Integer value2) {
+            addCriterion("level between", value1, value2, "level");
+            return (Criteria) this;
+        }
+
+        public Criteria andLevelNotBetween(Integer value1, Integer value2) {
+            addCriterion("level not between", value1, value2, "level");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinIsNull() {
+            addCriterion("pinyin is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinIsNotNull() {
+            addCriterion("pinyin is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinEqualTo(String value) {
+            addCriterion("pinyin =", value, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinNotEqualTo(String value) {
+            addCriterion("pinyin <>", value, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinGreaterThan(String value) {
+            addCriterion("pinyin >", value, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinGreaterThanOrEqualTo(String value) {
+            addCriterion("pinyin >=", value, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinLessThan(String value) {
+            addCriterion("pinyin <", value, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinLessThanOrEqualTo(String value) {
+            addCriterion("pinyin <=", value, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinLike(String value) {
+            addCriterion("pinyin like", value, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinNotLike(String value) {
+            addCriterion("pinyin not like", value, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinIn(List<String> values) {
+            addCriterion("pinyin in", values, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinNotIn(List<String> values) {
+            addCriterion("pinyin not in", values, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinBetween(String value1, String value2) {
+            addCriterion("pinyin between", value1, value2, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andPinyinNotBetween(String value1, String value2) {
+            addCriterion("pinyin not between", value1, value2, "pinyin");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymIsNull() {
+            addCriterion("acronym is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymIsNotNull() {
+            addCriterion("acronym is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymEqualTo(String value) {
+            addCriterion("acronym =", value, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymNotEqualTo(String value) {
+            addCriterion("acronym <>", value, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymGreaterThan(String value) {
+            addCriterion("acronym >", value, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymGreaterThanOrEqualTo(String value) {
+            addCriterion("acronym >=", value, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymLessThan(String value) {
+            addCriterion("acronym <", value, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymLessThanOrEqualTo(String value) {
+            addCriterion("acronym <=", value, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymLike(String value) {
+            addCriterion("acronym like", value, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymNotLike(String value) {
+            addCriterion("acronym not like", value, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymIn(List<String> values) {
+            addCriterion("acronym in", values, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymNotIn(List<String> values) {
+            addCriterion("acronym not in", values, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymBetween(String value1, String value2) {
+            addCriterion("acronym between", value1, value2, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andAcronymNotBetween(String value1, String value2) {
+            addCriterion("acronym not between", value1, value2, "acronym");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeIsNull() {
+            addCriterion("code is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeIsNotNull() {
+            addCriterion("code is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeEqualTo(String value) {
+            addCriterion("code =", value, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeNotEqualTo(String value) {
+            addCriterion("code <>", value, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeGreaterThan(String value) {
+            addCriterion("code >", value, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeGreaterThanOrEqualTo(String value) {
+            addCriterion("code >=", value, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeLessThan(String value) {
+            addCriterion("code <", value, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeLessThanOrEqualTo(String value) {
+            addCriterion("code <=", value, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeLike(String value) {
+            addCriterion("code like", value, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeNotLike(String value) {
+            addCriterion("code not like", value, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeIn(List<String> values) {
+            addCriterion("code in", values, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeNotIn(List<String> values) {
+            addCriterion("code not in", values, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeBetween(String value1, String value2) {
+            addCriterion("code between", value1, value2, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andCodeNotBetween(String value1, String value2) {
+            addCriterion("code not between", value1, value2, "code");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeIsNull() {
+            addCriterion("areaCode is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeIsNotNull() {
+            addCriterion("areaCode is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeEqualTo(String value) {
+            addCriterion("areaCode =", value, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeNotEqualTo(String value) {
+            addCriterion("areaCode <>", value, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeGreaterThan(String value) {
+            addCriterion("areaCode >", value, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeGreaterThanOrEqualTo(String value) {
+            addCriterion("areaCode >=", value, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeLessThan(String value) {
+            addCriterion("areaCode <", value, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeLessThanOrEqualTo(String value) {
+            addCriterion("areaCode <=", value, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeLike(String value) {
+            addCriterion("areaCode like", value, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeNotLike(String value) {
+            addCriterion("areaCode not like", value, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeIn(List<String> values) {
+            addCriterion("areaCode in", values, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeNotIn(List<String> values) {
+            addCriterion("areaCode not in", values, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeBetween(String value1, String value2) {
+            addCriterion("areaCode between", value1, value2, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andAreacodeNotBetween(String value1, String value2) {
+            addCriterion("areaCode not between", value1, value2, "areacode");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipIsNull() {
+            addCriterion("zip is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipIsNotNull() {
+            addCriterion("zip is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipEqualTo(String value) {
+            addCriterion("zip =", value, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipNotEqualTo(String value) {
+            addCriterion("zip <>", value, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipGreaterThan(String value) {
+            addCriterion("zip >", value, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipGreaterThanOrEqualTo(String value) {
+            addCriterion("zip >=", value, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipLessThan(String value) {
+            addCriterion("zip <", value, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipLessThanOrEqualTo(String value) {
+            addCriterion("zip <=", value, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipLike(String value) {
+            addCriterion("zip like", value, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipNotLike(String value) {
+            addCriterion("zip not like", value, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipIn(List<String> values) {
+            addCriterion("zip in", values, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipNotIn(List<String> values) {
+            addCriterion("zip not in", values, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipBetween(String value1, String value2) {
+            addCriterion("zip between", value1, value2, "zip");
+            return (Criteria) this;
+        }
+
+        public Criteria andZipNotBetween(String value1, String value2) {
+            addCriterion("zip not between", value1, value2, "zip");
+            return (Criteria) this;
+        }
+    }
+
+    public static class Criteria extends GeneratedCriteria {
+
+        protected Criteria() {
+            super();
+        }
+    }
+
+    public static class Criterion {
+        private String condition;
+
+        private Object value;
+
+        private Object secondValue;
+
+        private boolean noValue;
+
+        private boolean singleValue;
+
+        private boolean betweenValue;
+
+        private boolean listValue;
+
+        private String typeHandler;
+
+        public String getCondition() {
+            return condition;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+
+        public Object getSecondValue() {
+            return secondValue;
+        }
+
+        public boolean isNoValue() {
+            return noValue;
+        }
+
+        public boolean isSingleValue() {
+            return singleValue;
+        }
+
+        public boolean isBetweenValue() {
+            return betweenValue;
+        }
+
+        public boolean isListValue() {
+            return listValue;
+        }
+
+        public String getTypeHandler() {
+            return typeHandler;
+        }
+
+        protected Criterion(String condition) {
+            super();
+            this.condition = condition;
+            this.typeHandler = null;
+            this.noValue = true;
+        }
+
+        protected Criterion(String condition, Object value, String typeHandler) {
+            super();
+            this.condition = condition;
+            this.value = value;
+            this.typeHandler = typeHandler;
+            if (value instanceof List<?>) {
+                this.listValue = true;
+            } else {
+                this.singleValue = true;
+            }
+        }
+
+        protected Criterion(String condition, Object value) {
+            this(condition, value, null);
+        }
+
+        protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+            super();
+            this.condition = condition;
+            this.value = value;
+            this.secondValue = secondValue;
+            this.typeHandler = typeHandler;
+            this.betweenValue = true;
+        }
+
+        protected Criterion(String condition, Object value, Object secondValue) {
+            this(condition, value, secondValue, null);
+        }
+    }
+}

+ 19 - 0
Future/future-admin/src/main/java/com/future/module/area/model/vo/AreaVo.java

@@ -0,0 +1,19 @@
+package com.future.module.area.model.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel("地址信息")
+public class AreaVo {
+
+    @ApiModelProperty("地区编码")
+    private String areaId;
+
+    @ApiModelProperty("地区名称")
+    private String areaName;
+
+    @ApiModelProperty("地区父类编码")
+    private String parentId;
+}

+ 10 - 0
Future/future-admin/src/main/java/com/future/module/area/service/PmsBasePositiontService.java

@@ -0,0 +1,10 @@
+package com.hwrj.cloud.portal.service;
+
+
+import com.future.module.area.model.vo.AreaVo;
+
+import java.util.List;
+
+public interface PmsBasePositiontService {
+    List<AreaVo> search(String parentId);
+}

+ 43 - 0
Future/future-admin/src/main/java/com/future/module/area/service/impl/PmsBasePositiontServiceImpl.java

@@ -0,0 +1,43 @@
+package com.future.module.area.service.impl;
+
+
+import com.future.module.area.mapper.PmsBasePositionMapper;
+import com.future.module.area.model.entity.PmsBasePosition;
+import com.future.module.area.model.entity.PmsBasePositionExample;
+import com.future.module.area.model.vo.AreaVo;
+import com.hwrj.cloud.portal.service.PmsBasePositiontService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class PmsBasePositiontServiceImpl implements PmsBasePositiontService {
+    @Autowired
+    private PmsBasePositionMapper pmsBasePositionMapper;
+
+    @Override
+    public List<AreaVo> search(String parentId) {
+
+        PmsBasePositionExample example=new PmsBasePositionExample();
+        example.setOrderByClause("level");
+        PmsBasePositionExample.Criteria criteria = example.createCriteria();
+        if(!StringUtils.isEmpty(parentId)){
+            criteria.andUpcodeEqualTo(parentId);
+        }else {
+            criteria.andUpcodeEqualTo("#");
+        }
+        List<PmsBasePosition> pmsBasePositions = pmsBasePositionMapper.selectByExample(example);
+        List<AreaVo> collect = pmsBasePositions.stream().map(x -> {
+            AreaVo areaVo = new AreaVo();
+            String id = x.getCode();
+            areaVo.setAreaId(id);
+            areaVo.setAreaName(x.getName());
+            areaVo.setParentId(x.getUpcode());
+            return areaVo;
+        }).collect(Collectors.toList());
+        return collect;
+    }
+}

+ 87 - 0
Future/future-admin/src/main/java/com/future/module/common/controller/CaptchaController.java

@@ -0,0 +1,87 @@
+package com.future.module.common.controller;
+
+import com.future.common.constant.Constants;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.core.redis.RedisCache;
+import com.future.common.utils.sign.Base64;
+import com.future.common.utils.uuid.IdUtils;
+import com.google.code.kaptcha.Producer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.util.FastByteArrayOutputStream;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletResponse;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 验证码操作处理
+ * 
+ * @author future
+ */
+@RestController
+public class CaptchaController
+{
+    @Resource(name = "captchaProducer")
+    private Producer captchaProducer;
+
+    @Resource(name = "captchaProducerMath")
+    private Producer captchaProducerMath;
+
+    @Autowired
+    private RedisCache redisCache;
+    
+    // 验证码类型
+    @Value("${future.captchaType}")
+    private String captchaType;
+
+    /**
+     * 生成验证码
+     */
+    @GetMapping("/captchaImage")
+    public AjaxResult getCode(HttpServletResponse response) throws IOException
+    {
+        // 保存验证码信息
+        String uuid = IdUtils.simpleUUID();
+        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
+
+        String capStr = null, code = null;
+        BufferedImage image = null;
+
+        // 生成验证码
+        if ("math".equals(captchaType))
+        {
+            String capText = captchaProducerMath.createText();
+            capStr = capText.substring(0, capText.lastIndexOf("@"));
+            code = capText.substring(capText.lastIndexOf("@") + 1);
+            image = captchaProducerMath.createImage(capStr);
+        }
+        else if ("char".equals(captchaType))
+        {
+            capStr = code = captchaProducer.createText();
+            image = captchaProducer.createImage(capStr);
+        }
+
+        redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
+        // 转换流信息写出
+        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
+        try
+        {
+            ImageIO.write(image, "jpg", os);
+        }
+        catch (IOException e)
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("uuid", uuid);
+        ajax.put("img", Base64.encode(os.toByteArray()));
+        return ajax;
+    }
+}

+ 119 - 0
Future/future-admin/src/main/java/com/future/module/common/controller/CommonController.java

@@ -0,0 +1,119 @@
+package com.future.module.common.controller;
+
+import com.future.common.config.FutureConfig;
+import com.future.common.constant.Constants;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.utils.StringUtils;
+import com.future.common.utils.file.FileUploadUtils;
+import com.future.common.utils.file.FileUtils;
+import com.future.framework.config.ServerConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 通用请求处理
+ * 
+ * @author future
+ */
+@RestController
+public class CommonController
+{
+    private static final Logger log = LoggerFactory.getLogger(CommonController.class);
+
+    @Autowired
+    private ServerConfig serverConfig;
+
+    /**
+     * 通用下载请求
+     * 
+     * @param fileName 文件名称
+     * @param delete 是否删除
+     */
+    @GetMapping("common/download")
+    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
+    {
+        try
+        {
+            if (!FileUtils.checkAllowDownload(fileName))
+            {
+                throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
+            }
+            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
+            String filePath = FutureConfig.getDownloadPath() + fileName;
+
+            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+            FileUtils.setAttachmentResponseHeader(response, realFileName);
+            FileUtils.writeBytes(filePath, response.getOutputStream());
+            if (delete)
+            {
+                FileUtils.deleteFile(filePath);
+            }
+        }
+        catch (Exception e)
+        {
+            log.error("下载文件失败", e);
+        }
+    }
+
+    /**
+     * 通用上传请求
+     */
+    @PostMapping("/common/upload")
+    public AjaxResult uploadFile(MultipartFile file) throws Exception
+    {
+        try
+        {
+            // 上传文件路径
+            String filePath = FutureConfig.getUploadPath();
+            // 上传并返回新文件名称
+            String fileName = FileUploadUtils.upload(filePath, file);
+            String url = serverConfig.getUrl() + fileName;
+            AjaxResult ajax = AjaxResult.success();
+            ajax.put("fileName", fileName);
+            ajax.put("url", url);
+            return ajax;
+        }
+        catch (Exception e)
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
+    /**
+     * 本地资源通用下载
+     */
+    @GetMapping("/common/download/resource")
+    public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
+            throws Exception
+    {
+        try
+        {
+            if (!FileUtils.checkAllowDownload(resource))
+            {
+                throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
+            }
+            // 本地资源路径
+            String localPath = FutureConfig.getProfile();
+            // 数据库资源地址
+            String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
+            // 下载名称
+            String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
+            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+            FileUtils.setAttachmentResponseHeader(response, downloadName);
+            FileUtils.writeBytes(downloadPath, response.getOutputStream());
+        }
+        catch (Exception e)
+        {
+            log.error("下载文件失败", e);
+        }
+    }
+}

+ 286 - 0
Future/future-admin/src/main/java/com/future/module/demo/log/LogQuaController.java

@@ -0,0 +1,286 @@
+package com.future.module.demo.log;
+
+import com.future.common.annotation.Log;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.enums.BusinessType;
+import com.future.common.enums.OperatorType;
+import com.future.common.exception.BaseException;
+import com.future.module.demo.log.entity.LogUserInfo;
+import com.future.module.demo.log.entity.Symbol;
+import com.future.system.domain.demo.LogDemo;
+import com.future.system.service.DeLogDemoService;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.slf4j.MarkerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.*;
+
+
+/**
+ *通过lombok来声明和初始化Log对象
+ */
+@Slf4j
+@RestController
+@RequestMapping("/demo/log")
+public class LogQuaController {
+    //通过LoggerFactory工厂来实列化Log对象
+    private static final Logger logger =
+            LoggerFactory.getLogger(LogQuaController.class);
+    @Autowired
+    private DeLogDemoService logDemoService;
+
+    /**
+     * @description 重要地方打印日志
+     * @author qiubo
+     * @date 2021/5/20 17:08
+     * @param id
+     * @param msg
+     * @return com.future.common.core.domain.AjaxResult
+     */
+    @GetMapping("/get")
+    public AjaxResult getLogDemo(@RequestParam(value = "id",required = true) String id,@RequestParam(value = "msg",required = true)  String msg){
+        log.debug("获取logDemo中,入参参数为:id={},msg={}",id,msg);
+        LogDemo logDemo = logDemoService.getLogDemo(id, msg);
+        log.debug("获取logDemo中,返回结果为:logdemo={}",logDemo);
+        log.error("获取logDemo中,返回结果为:logdemo={}",logDemo);
+        return  AjaxResult.success(logDemo);
+    }
+
+
+    @GetMapping("/logEx")
+    public AjaxResult getLogDemoExp(@RequestParam(value = "value",required = true) String value){
+        try {
+            LogDemo failEx = logDemoService.getFailEx(value);
+            return AjaxResult.success(failEx);
+        } catch (Exception e) {
+            log.info("产生了异常{}",e);
+        }
+        return AjaxResult.error();
+    }
+
+    /**
+     * @description 产生异常日志注意事项
+     * @author qiubo
+     * @date 2021/5/24 10:03
+     * @param value
+     * @return com.future.common.core.domain.AjaxResult
+     */
+    @GetMapping("/exNote")
+    //尽量抛出异常,顶层的 main() 函数截获所有的异常或者做全局统一拦截处理,并且打印(或者记录在日志中)在屏幕上。
+    public AjaxResult exNote(@RequestParam(value = "value",required = true) String value)throws Exception{
+        LogDemo failEx = null;
+
+        //如果异常可以避免,那就不要处理
+        try {
+            //将 try/catch 区段置于循环之外。
+            for (int i = 0;i<3;i++){
+                //do something
+            }
+             failEx= logDemoService.getFailEx(value);
+            //如果异常是其他更细的异常 ,请不要用Exception e,应该细分
+        } catch (Exception e) {
+            log.info("产生了异常{}",e);
+            //不要在这里面做程序流程控制
+
+        }
+
+        // 尽量减小 try 块的体积,不要从 try 区段中返回。
+        if (failEx  != null){
+            return AjaxResult.success(failEx);
+        }
+        return AjaxResult.error();
+    }
+
+    @GetMapping("/exNote2")
+    public AjaxResult exNote2(@RequestParam(value = "value",required = true) String value){
+        LogDemo failEx = null;
+        try {
+             failEx= logDemoService.getFailEx(value);
+        } catch (Exception e) {
+            log.info("产生了异常{}",e);
+            log.info("eMessage产生了异常{}",e.getMessage());
+            log.info("e.toString产生了异常{}",e.toString());
+
+        }
+        if (failEx  != null){
+            return AjaxResult.success(failEx);
+        }
+        return AjaxResult.error();
+    }
+
+    /**
+     * @description 用户操作日志记录
+     * @author qiubo
+     * @date 2021/5/24 9:23
+     * @param value
+     * @return com.future.common.core.domain.AjaxResult
+     */
+    @GetMapping("/oper")
+    @Log(title = "日志测试之用户操作日志",businessType = BusinessType.OTHER,operatorType = OperatorType.OTHER,isSaveRequestData = true)
+    public AjaxResult userOperLog(@RequestParam(value = "value",required = true) String value){
+        try {
+            LogDemo failEx = logDemoService.getFailEx(value);
+            return AjaxResult.success(failEx);
+        } catch (Exception e) {
+            log.info("产生了异常{}",e);
+        }
+        return AjaxResult.error();
+    }
+
+    @PostMapping("/mark")
+    public AjaxResult markLog(@RequestBody LogUserInfo userInfo){
+        if (userInfo != null){
+            logger.info("收到用户id为{}的用户的相关用户标识",userInfo.getId());
+        }
+        return AjaxResult.error();
+    }
+    /**
+     * @description 实现创建多条日志
+     * @author qiubo
+     * @date 2021/5/20 17:08
+     * @return com.future.common.core.domain.AjaxResult
+     */
+    @GetMapping("/printLog")
+    public AjaxResult quikPrint100(){
+        for(int i = 0;i<1000;i++)
+        log.debug("滚动时,FixedWindowRollingPolicy根据固定窗口算法重命名文件,如下所述。`fileNamePatter`是用来计算已经回滚好的收集的日志文件的名称的。使用的时候在`pattern`里必须包含%i整型变量标志获取logDemo中,返回结果为:logdemo={}");
+        return  AjaxResult.success();
+    }
+    /**
+     * @description 实现异常日志发送邮件到邮箱
+     * @author qiubo
+     * @date 2021/5/20 17:07
+     * @return com.future.common.core.domain.AjaxResult
+     */
+    @GetMapping("/exception")
+    public AjaxResult ex(){
+//        for(int i = 0;i<1000;i++)
+        logger.error(MarkerFactory.getMarker("sendmail"),"预警发送:");
+        log.error("滚动时,FixedWindowRollingPolicy根据固定窗口算法重命名文件,如下所述。`fileNamePatter`是用来计算已经回滚好的收集的日志文件的名称的。使用的时候在`pattern`里必须包含%i整型变量标志获取logDemo中,返回结果为:logdemo={}");
+        log.debug("滚动时,FixedWindowRollingPolicy根据固定窗口算法重命名文件,如下所述。`fileNamePatter`是用来计算已经回滚好的收集的日志文件的名称的。使用的时候在`pattern`里必须包含%i整型变量标志获取logDemo中,返回结果为:logdemo={}");
+        throw new BaseException("不是我们的");
+//        return  AjaxResult.success();
+    }
+    /**
+     * @description SiftingAppender实现对日志进行不同的分类
+     * @author qiubo
+     * @date 2021/5/20 17:11
+     * @param userId 
+     * @return com.future.common.core.domain.AjaxResult
+     */
+    @GetMapping("/shift")
+    public AjaxResult shift(@RequestParam(value = "userId",required = true) String userId){
+//        for(int i = 0;i<1000;i++)
+        logger.error(MarkerFactory.getMarker("sendmail"),"预警发送:");
+        MDC.put("userid",userId);
+        log.error("滚动时,FixedWindowRollingPolicy根据固定窗口算法重命名文件,如下所述。`fileNamePatter`是用来计算已经回滚好的收集的日志文件的名称的。使用的时候在`pattern`里必须包含%i整型变量标志获取logDemo中,返回结果为:logdemo={}");
+        log.debug("滚动时,FixedWindowRollingPolicy根据固定窗口算法重命名文件,如下所述。`fileNamePatter`是用来计算已经回滚好的收集的日志文件的名称的。使用的时候在`pattern`里必须包含%i整型变量标志获取logDemo中,返回结果为:logdemo={}");
+        throw new BaseException("不是我们的");
+//        return  AjaxResult.success();
+    }
+
+
+
+    public AjaxResult logQua(String param){
+        log.info(">>>传入参数是多少{}",param);
+        logger.info(">>>传入参数是多少{}",param);
+        return new AjaxResult();
+    }
+    public AjaxResult traceDebugInfo4(String id, Symbol symbol){
+        //正确列子
+        logger.debug(">>>传入参数的id:{} symbol{}",id,symbol);
+        //正确例子
+        if (logger.isDebugEnabled()){
+            logger.debug(">>>传入参数的id:"+id+"symbol"+symbol);
+        }
+
+        return new AjaxResult();
+    }
+
+
+    public void exceptionLog6(String id, Symbol symbol)  {
+        File file = new File("D:\\log\\base\\sys-info.log");
+        try {
+            InputStream in = new FileInputStream(file);
+            byte[] data =new byte[100];
+
+            int len =in.read(data);///返回实际读取的字节数
+
+            String str =new String(data,0,len,"UTF-8");//将实际读取的字节数转换为字符串
+
+            in.close();
+        } catch (FileNotFoundException e) {
+            logger.warn (e.toString() + "_" +
+                    e.getMessage(), e);
+            //do something
+        } catch (IOException e) {
+            logger.warn (e.toString() + "_" +
+                    e.getMessage(), e);
+            //do something
+        }
+    }
+    public void notePrintlnLog(String param){
+        //生产环境不能使用debug  下面是反列
+        logger.debug("传入参数是{}",param);
+        //弄清楚为什么需要打印日志  别无时无刻都在打印日志
+        logger.info("传入参数是{}",param);
+        logger.info("传入参数是{}",param);
+
+    }
+    public void warnAndError(String id, Symbol symbol)  {
+        //当我们规定id不能为空,并且它的长度只能等于25时,如果传入的id不能满足这个要求 我们可以用warn级别输出 ,但是不能用error输出
+        if(StringUtils.isEmpty(id)||id.length()!= 25){
+            logger.warn("id的值不能为空或者id的值的长度必须等于25,id={}",id);
+        }
+
+    }
+    /**
+     * @description 
+     * @author qiubo
+     * @date 2021/5/19 17:12
+ * @param id
+ * @param symbol
+     */
+    public void logPrintln(String id, Symbol symbol)  {
+        //错误例子
+        System.out.println("输入参数为id="+id);
+        System.err.println("输入参数symbol为空"+symbol);
+        File file = new File("D:\\log\\base\\sys-info.log");
+        try {
+            InputStream in = new FileInputStream(file);
+            byte[] data =new byte[100];
+            int len =in.read(data);///返回实际读取的字节数
+            String str =new String(data,0,len,"UTF-8");//将实际读取的字节数转换为字符串
+            in.close();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+    }
+    /**
+     * @description 记录日志时不能抛出异常
+     * @author qiubo
+     * @date 2021/5/19 17:06
+     * @param id
+     * @param symbol
+     */
+    public void exceptionLog(String id, Symbol symbol)  {
+        Symbol sy = null;
+        logger.debug("刚才实列化Symbol类的id是{}",sy.getId());
+
+    }
+    public void excptionPrintln(String id)  {
+        Symbol sy = null;
+        //不能输出类似于这样的日志
+        logger.debug("########刚才实列化Symbol类的id是{}",id);
+        logger.debug("!@#$%刚才实列化Symbol类的id是{}",id);
+
+    }
+}

+ 272 - 0
Future/future-admin/src/main/java/com/future/module/demo/log/MaskingPatternLayout.java

@@ -0,0 +1,272 @@
+package com.future.module.demo.log;
+
+
+
+import ch.qos.logback.classic.PatternLayout;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import com.future.common.utils.StringUtils;
+import org.springframework.util.CollectionUtils;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 对敏感信息进行掩盖。
+ * 1.实现原理
+ * 对产生的日志信息,进行正则匹配和替换。
+ * <p>
+ * 2.目前包括如下类型的信息:银行卡号、电话、身份证和邮箱。
+ * <p>
+ * 3.如何进行扩展新的正则类型
+ * (1)在PatternType枚举中新增一个正则
+ * (2)extractMatchesByType对新增的正则做处理
+ * (3)maskByType对新增的正则做处理
+ * <p>
+ */
+public class MaskingPatternLayout extends PatternLayout {
+
+    /**
+     * 匹配的所有正则
+     */
+    private Map<PatternType, Pattern> patternsMap = new HashMap<PatternType, Pattern>();
+    private static final String KEY = "GepqwLZYdk";
+
+
+    public MaskingPatternLayout() {
+        loadPatterns();
+    }
+
+
+    @Override
+    public String doLayout(ILoggingEvent event) {
+        String message = super.doLayout(event);
+        if (CollectionUtils.isEmpty(patternsMap)) {
+            return message;
+        }
+        // 处理日志信息
+        try {
+            return process(message);
+        } catch (Exception e) {
+            // 这里不做任何操作,直接返回原来message
+            return message;
+        }
+    }
+
+
+    /**
+     * 加载正则表达式,生成相应的Pattern对象。
+     */
+    private void loadPatterns() {
+        for (PatternType patternType : PatternType.values()) {
+            Pattern pattern = Pattern.compile(patternType.getRegex());
+            patternsMap.put(patternType, pattern);
+        }
+    }
+
+    /**
+     * 替换信息
+     *
+     * @param message
+     * @return
+     */
+    public String process(String message) {
+        for (PatternType key : patternsMap.keySet()) {
+            // 1.生成matcher
+            Pattern pattern = patternsMap.get(key);
+            Matcher matcher = pattern.matcher(message);
+
+            // 2.获取匹配的信息
+            Set<String> matches = extractMatchesByType(matcher);
+
+            // 3.掩盖匹配的信息
+            if (!CollectionUtils.isEmpty(matches)) {
+                message = maskByType(key, message, matches);
+            }
+        }
+
+        return message;
+    }
+
+
+    /**
+     * 根据正则类型来做相应的提取
+     *
+     * @param matcher
+     * @return
+     */
+    private Set<String> extractMatchesByType(Matcher matcher) {
+        // 邮箱、电话、银行卡、身份证都是通过如下方法进行提取匹配的字符串
+        return extractDefault(matcher);
+
+    }
+
+    /**
+     * 1.提取匹配的所有字符串中某一个分组
+     * group(0):表示不分组,整个表达式的值
+     * group(i),i>0:表示某一个分组的值
+     * <p>
+     * 2.使用Set进行去重
+     *
+     * @param matcher
+     * @return
+     */
+    private Set<String> extractDefault(Matcher matcher) {
+        Set<String> matches = new HashSet<String>();
+        int count = matcher.groupCount();
+
+        while (matcher.find()) {
+            if (count == 0) {
+                matches.add(matcher.group());
+                continue;
+            }
+            for (int i = 1; i <= count; i++) {
+                String match = matcher.group(i);
+                if (null != match) {
+                    matches.add(match);
+                }
+            }
+
+        }
+
+        return matches;
+    }
+
+
+    /**
+     * 根据不同类型敏感信息做相应的处理
+     *
+     * @param key
+     * @param message
+     * @return
+     */
+    private String maskByType(PatternType key, String message, Set<String> matchs) {
+        if (key == PatternType.ID_CARD) {
+            return maskIdCard(message, matchs);
+        } else if(key == PatternType.BANK_CARD){
+            return maskBankcard(message, matchs);
+        } else if(key == PatternType.PHONE_NUMBER){
+            return maskPhone(message, matchs);
+        }  else{
+            return message;
+        }
+
+
+    }
+
+    /**
+     * 掩盖数字类型信息
+     *
+     * @param message
+     * @param matches
+     * @return
+     */
+    private String maskIdCard(String message, Set<String> matches) {
+
+        for (String match : matches) {
+            // 1.处理获取的字符
+            String matchProcess = baseSensitive(match, 4, 4);
+            // 2.String的替换
+            message = message.replace(match, matchProcess);
+        }
+        return message;
+    }
+
+    private String maskBankcard(String message, Set<String> matches) {
+        for (String match : matches) {
+            // 1.处理获取的字符
+            String matchProcess = baseSensitive(match, 3, 3);
+            // 2.String的替换
+            message = message.replace(match, matchProcess);
+        }
+        return message;
+    }
+
+    private String maskPhone(String message, Set<String> matches) {
+        for (String match : matches) {
+            // 1.处理获取的字符
+            String matchProcess = baseSensitive(match, 2, 2);
+            // 2.String的替换
+            message = message.replace(match, matchProcess);
+        }
+        return message;
+    }
+
+    private static String baseSensitive(String str, int startLength, int endLength) {
+        if (StringUtils.isBlank(str)) {
+            return "";
+        }
+        String replacement = str.substring(startLength,str.length()-endLength);
+        StringBuffer sb = new StringBuffer();
+        for(int i=0;i<replacement.length();i++) {
+            char ch;
+            if(replacement.charAt(i)>='0' && replacement.charAt(i)<='9') {
+                ch = KEY.charAt((int)(replacement.charAt(i) - '0'));
+            }else {
+                ch = replacement.charAt(i);
+            }
+            sb.append(ch);
+        }
+        return StringUtils.left(str, startLength).concat(StringUtils.leftPad(StringUtils.right(str, endLength), str.length() - startLength, sb.toString()));
+    }
+
+    private static String decrypt(String str, int startLength, int endLength) {
+        if (StringUtils.isBlank(str)) {
+            return "";
+        }
+        String replacement = str.substring(startLength,str.length()-endLength);
+        StringBuffer sb = new StringBuffer();
+        for(int i=0;i<replacement.length();i++) {
+            int index = KEY.indexOf(replacement.charAt(i));
+            if(index != -1) {
+                sb.append(index);
+            }else {
+                sb.append(replacement.charAt(i));
+            }
+        }
+        return StringUtils.left(str, startLength).concat(StringUtils.leftPad(StringUtils.right(str, endLength), str.length() - startLength, sb.toString()));
+    }
+
+
+    /**
+     * 定义敏感信息类型
+     */
+    private enum PatternType {
+        // 1.手机号共11位,模式为: 13xxx,,14xxx,15xxx,17xxx,18xx
+        PHONE_NUMBER("手机号", "[^\\d](1[34578]\\d{9})[^\\d]"),
+        // 2.银行卡号,包含16位和19位
+        BANK_CARD("银行卡", "[^\\d](\\d{16})[^\\d]|[^\\d](\\d{19})[^\\d]"),
+        // 3.邮箱
+        EMAIL("邮箱", "[A-Za-z_0-9]{1,64}@[A-Za-z1-9_-]+.[A-Za-z]{2,10}"),
+        // 4. 15位(全为数字位)或者18位身份证(17位位数字位,最后一位位校验位)
+        ID_CARD("身份证", "[^\\d](\\d{15})[^\\d]|[^\\d](\\d{18})[^\\d]|[^\\d](\\d{17}X)");
+
+        private String description;
+        private String regex;
+
+        private PatternType(String description, String regex) {
+            this.description = description;
+            this.regex = regex;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public void setDescription(String description) {
+            this.description = description;
+        }
+
+        public String getRegex() {
+            return regex;
+        }
+
+        public void setRegex(String regex) {
+            this.regex = regex;
+        }
+    }
+
+}

+ 28 - 0
Future/future-admin/src/main/java/com/future/module/demo/log/entity/DesensitizationTestEntity.java

@@ -0,0 +1,28 @@
+package com.future.module.demo.log.entity;
+
+import lombok.Data;
+
+/**
+ * @author qiubo
+ * @date 2021年05月24日 15:33
+ */
+@Data
+public class DesensitizationTestEntity {
+
+    private String cardNo;
+
+    private String name;
+
+    private String mobileNo;
+
+    private String email;
+
+    private String idNo;
+
+    private String address;
+
+    private String fileName;
+
+    private String password;
+
+}

+ 89 - 0
Future/future-admin/src/main/java/com/future/module/demo/log/entity/ErrorLogDemo.java

@@ -0,0 +1,89 @@
+package com.future.module.demo.log.entity;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ErrorLogDemo {
+    //错误
+    private static final Logger STDOUT = LoggerFactory.getLogger(ErrorLogDemo.class);
+    private static final Logger STDERR = LoggerFactory.getLogger(ErrorLogDemo.class);
+    //正确
+    private static final Logger LOGGER = LoggerFactory.getLogger(ErrorLogDemo.class);
+    public static void main(String[] args) {
+        //错误
+        System.out.println("do something ...");
+        System.err.println("do something ...");
+
+        //错误
+        STDOUT.info("do something ...");
+        STDERR.info("do something ...");
+
+        //正确
+        LOGGER.info("do something ...");
+        LOGGER.error("do something ...");
+
+        if (true){
+            // do something
+        }else {
+            LOGGER.error("it is impossible ...");
+        }
+        String id = "id";
+        String msg = "msg";
+        //错误
+        LOGGER.error("Consume message failed !!!!");
+
+        //正确
+        LOGGER.error("Consume message failed ,msgId={},",id);
+
+        if (LOGGER.isInfoEnabled()){
+            LOGGER.info("Push message success,id ="+id+",msg="+msg);
+        }
+
+    //        //错误
+    //        LOGGER.info("Push message success,id ="+id+",msg="+msg+"reason="+response.getReason());
+    //        //正确
+    //        LOGGER.info("Push message success,id ={},msg={},}reason={}",id,msg,response.getReason());
+        for (int i = 0;i<100;i++){
+            LOGGER.info("Message sends successfully ,msgId={}",i);
+        }
+
+//        LOGGER.error("Processing request with id: {}", request.getId());
+        try{
+            // do something
+        }catch (Exception e){
+            //正确
+            LOGGER.error("something wrong",e);
+            //错误
+            e.printStackTrace();
+        }
+
+        try{
+            // do something
+        }catch (Exception e){
+            LOGGER.error("something wrong",e);
+            throw  e;
+        }
+
+        try{
+            // do something
+        }catch (Exception e){
+            //错误
+            LOGGER.error("something wrong",e.getMessage());
+            throw  e;
+        }
+    }
+
+//    public AjaxResult login(@RequestBody LoginBody loginBody)
+//
+//    {
+//        String traceId = MDC.get("traceId");
+//        LOGGER.debug("Prepare to consume a message,userName={}",loginBody.getUsername());
+//        AjaxResult ajax = AjaxResult.success();
+//        // 生成令牌
+//        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
+//                loginBody.getUuid());
+//        LOGGER.debug("Cionsume result,token={}",token);
+//        ajax.put(Constants.TOKEN, token);
+//        return ajax;
+//    }
+}

+ 70 - 0
Future/future-admin/src/main/java/com/future/module/demo/log/entity/LogEntityRealiztion.java

@@ -0,0 +1,70 @@
+package com.future.module.demo.log.entity;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+
+/**
+ * @author qiubo
+ * @date 2021年05月19日 17:12
+ */
+//通过lombok注解的方式来实例化logger对象
+@Slf4j
+@Data
+public class LogEntityRealiztion {
+    //推荐通过下面方式阿里实列话Logger对象
+    private static final Logger logger = LoggerFactory.getLogger(LogEntityRealiztion.class);
+//    private final Logger logger = LoggerFactory.getLogger(getClass());
+//    private static Logger logger = LoggerFactory.getLogger(LogEntityRealiztion.class);
+//    protected final Logger logger =LoggerFactory.getLogger(getClass());
+//    private Logger logger = LoggerFactory.getLogger(getClass());
+//    protected Logger logger = LoggerFactory.getLogger(getClass());
+//    private static final Logger logger =LoggerFactory.getLogger("com.future.module.demo.log.entity.LogEntityRealiztion");
+    public void getHelloWord(){
+        File file = new File("D:\\log\\base\\sys-info.log");
+        try {
+            InputStream in = new FileInputStream(file);
+            byte[] data =new byte[100];
+
+            int len =in.read(data);///返回实际读取的字节数
+
+            String str =new String(data,0,len,"UTF-8");//将实际读取的字节数转换为字符串
+
+            in.close();
+        } catch (FileNotFoundException e) {
+            logger.warn (e.toString() + "_" +
+                    e.getMessage(), e);
+            //do something
+        } catch (IOException e) {
+            logger.warn (e.toString() + "_" +
+                    e.getMessage(), e);
+            //do something
+        }
+    }
+    public void toDo(){
+        File file = new File("D:\\log\\base\\sys-info.log");
+        try {
+            InputStream in = new FileInputStream(file);
+            byte[] data =new byte[100];
+
+            int len =in.read(data);///返回实际读取的字节数
+
+            String str =new String(data,0,len,"UTF-8");//将实际读取的字节数转换为字符串
+
+            in.close();
+        } catch (FileNotFoundException e) {
+            logger.error (e.toString() + "_" +
+                    e.getMessage(), e);
+
+        } catch (IOException e) {
+            logger.error (e.toString() + "_" +
+                    e.getMessage(), e);
+
+        }
+    }
+
+
+}

+ 19 - 0
Future/future-admin/src/main/java/com/future/module/demo/log/entity/LogUserInfo.java

@@ -0,0 +1,19 @@
+package com.future.module.demo.log.entity;
+
+import lombok.Data;
+
+/**
+ * @author qiubo
+ * @date 2021年05月21日 15:51
+ */
+@Data
+public class LogUserInfo {
+
+    private String id;
+
+    private String userName;
+
+    private String address;
+
+    private String companyName;
+}

+ 15 - 0
Future/future-admin/src/main/java/com/future/module/demo/log/entity/Symbol.java

@@ -0,0 +1,15 @@
+package com.future.module.demo.log.entity;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author qiubo
+ * @date 2021年05月19日 13:50
+ */
+@Slf4j
+@Data
+public class Symbol {
+    private String id ;
+    private String syName;
+}

+ 53 - 0
Future/future-admin/src/main/java/com/future/module/monitor/controller/CacheController.java

@@ -0,0 +1,53 @@
+package com.future.module.monitor.controller;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.utils.StringUtils;
+
+/**
+ * 缓存监控
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/monitor/cache")
+public class CacheController
+{
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping()
+    public AjaxResult getInfo() throws Exception
+    {
+        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
+        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
+        Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
+
+        Map<String, Object> result = new HashMap<>(3);
+        result.put("info", info);
+        result.put("dbSize", dbSize);
+
+        List<Map<String, String>> pieList = new ArrayList<>();
+        commandStats.stringPropertyNames().forEach(key -> {
+            Map<String, String> data = new HashMap<>(2);
+            String property = commandStats.getProperty(key);
+            data.put("name", StringUtils.removeStart(key, "cmdstat_"));
+            data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
+            pieList.add(data);
+        });
+        result.put("commandStats", pieList);
+        return AjaxResult.success(result);
+    }
+}

+ 27 - 0
Future/future-admin/src/main/java/com/future/module/monitor/controller/ServerController.java

@@ -0,0 +1,27 @@
+package com.future.module.monitor.controller;
+
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.framework.web.domain.Server;
+
+/**
+ * 服务器监控
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/monitor/server")
+public class ServerController
+{
+    @PreAuthorize("@ss.hasPermi('monitor:server:list')")
+    @GetMapping()
+    public AjaxResult getInfo() throws Exception
+    {
+        Server server = new Server();
+        server.copyTo();
+        return AjaxResult.success(server);
+    }
+}

+ 67 - 0
Future/future-admin/src/main/java/com/future/module/monitor/controller/SysLogininforController.java

@@ -0,0 +1,67 @@
+package com.future.module.monitor.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.core.page.TableDataInfo;
+import com.future.common.enums.BusinessType;
+import com.future.common.utils.poi.ExcelUtil;
+import com.future.system.domain.SysLogininfor;
+import com.future.system.service.ISysLogininforService;
+
+/**
+ * 系统访问记录
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/monitor/logininfor")
+public class SysLogininforController extends BaseController
+{
+    @Autowired
+    private ISysLogininforService logininforService;
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysLogininfor logininfor)
+    {
+        startPage();
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        return TableDataInfo.getDataTable(list);
+    }
+
+    @Log(title = "登录日志", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysLogininfor logininfor)
+    {
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
+        return util.exportExcel(list, "登录日志");
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "登录日志", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{infoIds}")
+    public AjaxResult remove(@PathVariable Long[] infoIds)
+    {
+        return toAjax(logininforService.deleteLogininforByIds(infoIds));
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "登录日志", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        logininforService.cleanLogininfor();
+        return AjaxResult.success();
+    }
+}

+ 66 - 0
Future/future-admin/src/main/java/com/future/module/monitor/controller/SysOperlogController.java

@@ -0,0 +1,66 @@
+package com.future.module.monitor.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.core.page.TableDataInfo;
+import com.future.common.enums.BusinessType;
+import com.future.common.utils.poi.ExcelUtil;
+import com.future.system.domain.SysOperLog;
+import com.future.system.service.ISysOperLogService;
+
+/**
+ * 操作日志记录
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/monitor/operlog")
+public class SysOperlogController extends BaseController
+{
+    @Autowired
+    private ISysOperLogService operLogService;
+
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysOperLog operLog)
+    {
+        startPage();
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+        return TableDataInfo.getDataTable(list);
+    }
+
+    @Log(title = "操作日志", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysOperLog operLog)
+    {
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+        ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
+        return util.exportExcel(list, "操作日志");
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/{operIds}")
+    public AjaxResult remove(@PathVariable Long[] operIds)
+    {
+        return toAjax(operLogService.deleteOperLogByIds(operIds));
+    }
+
+    @Log(title = "操作日志", businessType = BusinessType.CLEAN)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        operLogService.cleanOperLog();
+        return AjaxResult.success();
+    }
+}

+ 92 - 0
Future/future-admin/src/main/java/com/future/module/monitor/controller/SysUserOnlineController.java

@@ -0,0 +1,92 @@
+package com.future.module.monitor.controller;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.constant.Constants;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.core.page.TableDataInfo;
+import com.future.common.core.redis.RedisCache;
+import com.future.common.enums.BusinessType;
+import com.future.common.utils.StringUtils;
+import com.future.system.domain.SysUserOnline;
+import com.future.system.service.ISysUserOnlineService;
+
+/**
+ * 在线用户监控
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/monitor/online")
+public class SysUserOnlineController extends BaseController
+{
+    @Autowired
+    private ISysUserOnlineService userOnlineService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @PreAuthorize("@ss.hasPermi('monitor:online:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(String ipaddr, String userName)
+    {
+        Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*");
+        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
+        for (String key : keys)
+        {
+            LoginUser user = redisCache.getCacheObject(key);
+            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
+            {
+                if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
+                {
+                    userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
+                }
+            }
+            else if (StringUtils.isNotEmpty(ipaddr))
+            {
+                if (StringUtils.equals(ipaddr, user.getIpaddr()))
+                {
+                    userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
+                }
+            }
+            else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
+            {
+                if (StringUtils.equals(userName, user.getUsername()))
+                {
+                    userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
+                }
+            }
+            else
+            {
+                userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
+            }
+        }
+        Collections.reverse(userOnlineList);
+        userOnlineList.removeAll(Collections.singleton(null));
+        return TableDataInfo.getDataTable(userOnlineList);
+    }
+
+    /**
+     * 强退用户
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
+    @Log(title = "在线用户", businessType = BusinessType.FORCE)
+    @DeleteMapping("/{tokenId}")
+    public AjaxResult forceLogout(@PathVariable String tokenId)
+    {
+        redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId);
+        return AjaxResult.success();
+    }
+}

+ 135 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysConfigController.java

@@ -0,0 +1,135 @@
+package com.future.module.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.annotation.RepeatSubmit;
+import com.future.common.constant.UserConstants;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.core.page.TableDataInfo;
+import com.future.common.enums.BusinessType;
+import com.future.system.utils.SecurityUtils;
+import com.future.common.utils.poi.ExcelUtil;
+import com.future.system.domain.SysConfig;
+import com.future.system.service.ISysConfigService;
+
+/**
+ * 参数配置 信息操作处理
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/system/config")
+public class SysConfigController extends BaseController
+{
+    @Autowired
+    private ISysConfigService configService;
+
+    /**
+     * 获取参数配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysConfig config)
+    {
+        startPage();
+        List<SysConfig> list = configService.selectConfigList(config);
+        return TableDataInfo.getDataTable(list);
+    }
+
+    @Log(title = "参数管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:config:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysConfig config)
+    {
+        List<SysConfig> list = configService.selectConfigList(config);
+        ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
+        return util.exportExcel(list, "参数数据");
+    }
+
+    /**
+     * 根据参数编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:query')")
+    @GetMapping(value = "/{configId}")
+    public AjaxResult getInfo(@PathVariable Long configId)
+    {
+        return AjaxResult.success(configService.selectConfigById(configId));
+    }
+
+    /**
+     * 根据参数键名查询参数值
+     */
+    @GetMapping(value = "/configKey/{configKey}")
+    public AjaxResult getConfigKey(@PathVariable String configKey)
+    {
+        return AjaxResult.success(configService.selectConfigByKey(configKey));
+    }
+
+    /**
+     * 新增参数配置
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:add')")
+    @Log(title = "参数管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    @RepeatSubmit
+    public AjaxResult add(@Validated @RequestBody SysConfig config)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
+        {
+            return AjaxResult.error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
+        }
+        config.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(configService.insertConfig(config));
+    }
+
+    /**
+     * 修改参数配置
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:edit')")
+    @Log(title = "参数管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysConfig config)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
+        {
+            return AjaxResult.error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
+        }
+        config.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(configService.updateConfig(config));
+    }
+
+    /**
+     * 删除参数配置
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:remove')")
+    @Log(title = "参数管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{configIds}")
+    public AjaxResult remove(@PathVariable Long[] configIds)
+    {
+        return toAjax(configService.deleteConfigByIds(configIds));
+    }
+
+    /**
+     * 清空缓存
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:remove')")
+    @Log(title = "参数管理", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clearCache")
+    public AjaxResult clearCache()
+    {
+        configService.clearCache();
+        return AjaxResult.success();
+    }
+}

+ 163 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysDeptController.java

@@ -0,0 +1,163 @@
+package com.future.module.system.controller;
+
+import java.util.Iterator;
+import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.constant.UserConstants;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.system.domain.entity.SysDept;
+import com.future.common.enums.BusinessType;
+import com.future.system.utils.SecurityUtils;
+import com.future.common.utils.StringUtils;
+import com.future.system.service.ISysDeptService;
+
+/**
+ * 部门信息
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/system/dept")
+public class SysDeptController extends BaseController
+{
+    @Autowired
+    private ISysDeptService deptService;
+
+    /**
+     * 获取部门列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:list')")
+    @GetMapping("/list")
+    public AjaxResult list(SysDept dept)
+    {
+        List<SysDept> depts = deptService.selectDeptList(dept);
+        return AjaxResult.success(depts);
+    }
+
+    /**
+     * 查询部门列表(排除节点)
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:list')")
+    @GetMapping("/list/exclude/{deptId}")
+    public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
+    {
+        List<SysDept> depts = deptService.selectDeptList(new SysDept());
+        Iterator<SysDept> it = depts.iterator();
+        while (it.hasNext())
+        {
+            SysDept d = (SysDept) it.next();
+            if (d.getDeptId().intValue() == deptId
+                    || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""))
+            {
+                it.remove();
+            }
+        }
+        return AjaxResult.success(depts);
+    }
+
+    /**
+     * 根据部门编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:query')")
+    @GetMapping(value = "/{deptId}")
+    public AjaxResult getInfo(@PathVariable Long deptId)
+    {
+        return AjaxResult.success(deptService.selectDeptById(deptId));
+    }
+
+    /**
+     * 获取部门下拉树列表
+     */
+    @GetMapping("/treeselect")
+    public AjaxResult treeselect(SysDept dept)
+    {
+        List<SysDept> depts = deptService.selectDeptList(dept);
+        return AjaxResult.success(deptService.buildDeptTreeSelect(depts));
+    }
+
+    /**
+     * 加载对应角色部门列表树
+     */
+    @GetMapping(value = "/roleDeptTreeselect/{roleId}")
+    public AjaxResult roleDeptTreeselect(@PathVariable("roleId") Long roleId)
+    {
+        List<SysDept> depts = deptService.selectDeptList(new SysDept());
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
+        ajax.put("depts", deptService.buildDeptTreeSelect(depts));
+        return ajax;
+    }
+
+    /**
+     * 新增部门
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:add')")
+    @Log(title = "部门管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDept dept)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
+        {
+            return AjaxResult.error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
+        }
+        dept.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(deptService.insertDept(dept));
+    }
+
+    /**
+     * 修改部门
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:edit')")
+    @Log(title = "部门管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDept dept)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
+        {
+            return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
+        }
+        else if (dept.getParentId().equals(dept.getDeptId()))
+        {
+            return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
+        }
+        else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())
+                && deptService.selectNormalChildrenDeptById(dept.getDeptId()) > 0)
+        {
+            return AjaxResult.error("该部门包含未停用的子部门!");
+        }
+        dept.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(deptService.updateDept(dept));
+    }
+
+    /**
+     * 删除部门
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:remove')")
+    @Log(title = "部门管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{deptId}")
+    public AjaxResult remove(@PathVariable Long deptId)
+    {
+        if (deptService.hasChildByDeptId(deptId))
+        {
+            return AjaxResult.error("存在下级部门,不允许删除");
+        }
+        if (deptService.checkDeptExistUser(deptId))
+        {
+            return AjaxResult.error("部门存在用户,不允许删除");
+        }
+        return toAjax(deptService.deleteDeptById(deptId));
+    }
+}

+ 120 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysDictDataController.java

@@ -0,0 +1,120 @@
+package com.future.module.system.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.system.domain.entity.SysDictData;
+import com.future.common.core.page.TableDataInfo;
+import com.future.common.enums.BusinessType;
+import com.future.system.utils.SecurityUtils;
+import com.future.common.utils.StringUtils;
+import com.future.common.utils.poi.ExcelUtil;
+import com.future.system.service.ISysDictDataService;
+import com.future.system.service.ISysDictTypeService;
+
+/**
+ * 数据字典信息
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/system/dict/data")
+public class SysDictDataController extends BaseController
+{
+    @Autowired
+    private ISysDictDataService dictDataService;
+
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
+    @PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysDictData dictData)
+    {
+        startPage();
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        return TableDataInfo.getDataTable(list);
+    }
+
+    @Log(title = "字典数据", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:dict:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysDictData dictData)
+    {
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
+        return util.exportExcel(list, "字典数据");
+    }
+
+    /**
+     * 查询字典数据详细
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/{dictCode}")
+    public AjaxResult getInfo(@PathVariable Long dictCode)
+    {
+        return AjaxResult.success(dictDataService.selectDictDataById(dictCode));
+    }
+
+    /**
+     * 根据字典类型查询字典数据信息
+     */
+    @GetMapping(value = "/type/{dictType}")
+    public AjaxResult dictType(@PathVariable String dictType)
+    {
+        List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
+        if (StringUtils.isNull(data))
+        {
+            data = new ArrayList<SysDictData>();
+        }
+        return AjaxResult.success(data);
+    }
+
+    /**
+     * 新增字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:add')")
+    @Log(title = "字典数据", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDictData dict)
+    {
+        dict.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(dictDataService.insertDictData(dict));
+    }
+
+    /**
+     * 修改保存字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
+    @Log(title = "字典数据", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDictData dict)
+    {
+        dict.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(dictDataService.updateDictData(dict));
+    }
+
+    /**
+     * 删除字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "字典类型", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictCodes}")
+    public AjaxResult remove(@PathVariable Long[] dictCodes)
+    {
+        return toAjax(dictDataService.deleteDictDataByIds(dictCodes));
+    }
+}

+ 131 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysDictTypeController.java

@@ -0,0 +1,131 @@
+package com.future.module.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.constant.UserConstants;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.system.domain.entity.SysDictType;
+import com.future.common.core.page.TableDataInfo;
+import com.future.common.enums.BusinessType;
+import com.future.system.utils.SecurityUtils;
+import com.future.common.utils.poi.ExcelUtil;
+import com.future.system.service.ISysDictTypeService;
+
+/**
+ * 数据字典信息
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/system/dict/type")
+public class SysDictTypeController extends BaseController
+{
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
+    @PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysDictType dictType)
+    {
+        startPage();
+        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
+        return TableDataInfo.getDataTable(list);
+    }
+
+    @Log(title = "字典类型", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:dict:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysDictType dictType)
+    {
+        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
+        ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
+        return util.exportExcel(list, "字典类型");
+    }
+
+    /**
+     * 查询字典类型详细
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/{dictId}")
+    public AjaxResult getInfo(@PathVariable Long dictId)
+    {
+        return AjaxResult.success(dictTypeService.selectDictTypeById(dictId));
+    }
+
+    /**
+     * 新增字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:add')")
+    @Log(title = "字典类型", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDictType dict)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
+        {
+            return AjaxResult.error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
+        }
+        dict.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(dictTypeService.insertDictType(dict));
+    }
+
+    /**
+     * 修改字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
+    @Log(title = "字典类型", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDictType dict)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
+        {
+            return AjaxResult.error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
+        }
+        dict.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(dictTypeService.updateDictType(dict));
+    }
+
+    /**
+     * 删除字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "字典类型", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictIds}")
+    public AjaxResult remove(@PathVariable Long[] dictIds)
+    {
+        return toAjax(dictTypeService.deleteDictTypeByIds(dictIds));
+    }
+
+    /**
+     * 清空缓存
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "字典类型", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clearCache")
+    public AjaxResult clearCache()
+    {
+        dictTypeService.clearCache();
+        return AjaxResult.success();
+    }
+
+    /**
+     * 获取字典选择框列表
+     */
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
+        return AjaxResult.success(dictTypes);
+    }
+}

+ 101 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysLoginController.java

@@ -0,0 +1,101 @@
+package com.future.module.system.controller;
+
+import java.util.List;
+import java.util.Set;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.constant.Constants;
+import com.future.common.core.domain.AjaxResult;
+import com.future.system.domain.entity.SysMenu;
+import com.future.system.domain.entity.SysUser;
+import com.future.system.domain.model.LoginBody;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.utils.ServletUtils;
+import com.future.framework.web.service.SysLoginService;
+import com.future.framework.web.service.SysPermissionService;
+import com.future.framework.web.service.TokenService;
+import com.future.system.service.ISysMenuService;
+
+/**
+ * 登录验证
+ * 
+ * @author future
+ */
+@RestController
+@Slf4j
+public class SysLoginController
+{
+    @Autowired
+    private SysLoginService loginService;
+
+    @Autowired
+    private ISysMenuService menuService;
+
+    @Autowired
+    private SysPermissionService permissionService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 登录方法
+     * 
+     * @param loginBody 登录信息
+     * @return 结果
+     */
+    @PostMapping("/login")
+    public AjaxResult login(@RequestBody LoginBody loginBody)
+
+    {
+        log.info("天天在吃饭+1{}",loginBody);
+        AjaxResult ajax = AjaxResult.success();
+
+        // 生成令牌
+        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
+                loginBody.getUuid());
+        ajax.put(Constants.TOKEN, token);
+        return ajax;
+    }
+
+    /**
+     * 获取用户信息
+     * 
+     * @return 用户信息
+     */
+    @GetMapping("getInfo")
+    public AjaxResult getInfo()
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        SysUser user = loginUser.getUser();
+        // 角色集合
+        Set<String> roles = permissionService.getRolePermission(user);
+        // 权限集合
+        Set<String> permissions = permissionService.getMenuPermission(user);
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("user", user);
+        ajax.put("roles", roles);
+        ajax.put("permissions", permissions);
+        return ajax;
+    }
+
+    /**
+     * 获取路由信息
+     * 
+     * @return 路由信息
+     */
+    @GetMapping("getRouters")
+    public AjaxResult getRouters()
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        // 用户信息
+        SysUser user = loginUser.getUser();
+        List<SysMenu> menus = menuService.selectMenuTreeByUserId(user.getUserId());
+        return AjaxResult.success(menuService.buildMenus(menus));
+    }
+}

+ 157 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysMenuController.java

@@ -0,0 +1,157 @@
+package com.future.module.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.constant.Constants;
+import com.future.common.constant.UserConstants;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.system.domain.entity.SysMenu;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.enums.BusinessType;
+import com.future.system.utils.SecurityUtils;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.StringUtils;
+import com.future.framework.web.service.TokenService;
+import com.future.system.service.ISysMenuService;
+
+/**
+ * 菜单信息
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/system/menu")
+public class SysMenuController extends BaseController
+{
+    @Autowired
+    private ISysMenuService menuService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 获取菜单列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:list')")
+    @GetMapping("/list")
+    public AjaxResult list(SysMenu menu)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        List<SysMenu> menus = menuService.selectMenuList(menu, userId);
+        return AjaxResult.success(menus);
+    }
+
+    /**
+     * 根据菜单编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:query')")
+    @GetMapping(value = "/{menuId}")
+    public AjaxResult getInfo(@PathVariable Long menuId)
+    {
+        return AjaxResult.success(menuService.selectMenuById(menuId));
+    }
+
+    /**
+     * 获取菜单下拉树列表
+     */
+    @GetMapping("/treeselect")
+    public AjaxResult treeselect(SysMenu menu)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        List<SysMenu> menus = menuService.selectMenuList(menu, userId);
+        return AjaxResult.success(menuService.buildMenuTreeSelect(menus));
+    }
+
+    /**
+     * 加载对应角色菜单列表树
+     */
+    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
+    public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        List<SysMenu> menus = menuService.selectMenuList(loginUser.getUser().getUserId());
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
+        ajax.put("menus", menuService.buildMenuTreeSelect(menus));
+        return ajax;
+    }
+
+    /**
+     * 新增菜单
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:add')")
+    @Log(title = "菜单管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysMenu menu)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
+        {
+            return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
+        }
+        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame())
+                && !StringUtils.startsWithAny(menu.getPath(), Constants.HTTP, Constants.HTTPS))
+        {
+            return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
+        }
+        menu.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(menuService.insertMenu(menu));
+    }
+
+    /**
+     * 修改菜单
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:edit')")
+    @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysMenu menu)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
+        {
+            return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
+        }
+        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame())
+                && !StringUtils.startsWithAny(menu.getPath(), Constants.HTTP, Constants.HTTPS))
+        {
+            return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
+        }
+        else if (menu.getMenuId().equals(menu.getParentId()))
+        {
+            return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
+        }
+        menu.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(menuService.updateMenu(menu));
+    }
+
+    /**
+     * 删除菜单
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:remove')")
+    @Log(title = "菜单管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{menuId}")
+    public AjaxResult remove(@PathVariable("menuId") Long menuId)
+    {
+        if (menuService.hasChildByMenuId(menuId))
+        {
+            return AjaxResult.error("存在子菜单,不允许删除");
+        }
+        if (menuService.checkMenuExistRole(menuId))
+        {
+            return AjaxResult.error("菜单已分配,不允许删除");
+        }
+        return toAjax(menuService.deleteMenuById(menuId));
+    }
+}

+ 92 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysNoticeController.java

@@ -0,0 +1,92 @@
+package com.future.module.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.core.page.TableDataInfo;
+import com.future.common.enums.BusinessType;
+import com.future.system.utils.SecurityUtils;
+import com.future.system.domain.SysNotice;
+import com.future.system.service.ISysNoticeService;
+
+/**
+ * 公告 信息操作处理
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/system/notice")
+public class SysNoticeController extends BaseController
+{
+    @Autowired
+    private ISysNoticeService noticeService;
+
+    /**
+     * 获取通知公告列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysNotice notice)
+    {
+        startPage();
+        List<SysNotice> list = noticeService.selectNoticeList(notice);
+        return TableDataInfo.getDataTable(list);
+    }
+
+    /**
+     * 根据通知公告编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:query')")
+    @GetMapping(value = "/{noticeId}")
+    public AjaxResult getInfo(@PathVariable Long noticeId)
+    {
+        return AjaxResult.success(noticeService.selectNoticeById(noticeId));
+    }
+
+    /**
+     * 新增通知公告
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:add')")
+    @Log(title = "通知公告", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysNotice notice)
+    {
+        notice.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(noticeService.insertNotice(notice));
+    }
+
+    /**
+     * 修改通知公告
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:edit')")
+    @Log(title = "通知公告", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysNotice notice)
+    {
+        notice.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(noticeService.updateNotice(notice));
+    }
+
+    /**
+     * 删除通知公告
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:remove')")
+    @Log(title = "通知公告", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{noticeIds}")
+    public AjaxResult remove(@PathVariable Long[] noticeIds)
+    {
+        return toAjax(noticeService.deleteNoticeByIds(noticeIds));
+    }
+}

+ 130 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysPostController.java

@@ -0,0 +1,130 @@
+package com.future.module.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.constant.UserConstants;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.core.page.TableDataInfo;
+import com.future.common.enums.BusinessType;
+import com.future.system.utils.SecurityUtils;
+import com.future.common.utils.poi.ExcelUtil;
+import com.future.system.domain.SysPost;
+import com.future.system.service.ISysPostService;
+
+/**
+ * 岗位信息操作处理
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/system/post")
+public class SysPostController extends BaseController
+{
+    @Autowired
+    private ISysPostService postService;
+
+    /**
+     * 获取岗位列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysPost post)
+    {
+        startPage();
+        List<SysPost> list = postService.selectPostList(post);
+        return TableDataInfo.getDataTable(list);
+    }
+    
+    @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:post:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysPost post)
+    {
+        List<SysPost> list = postService.selectPostList(post);
+        ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
+        return util.exportExcel(list, "岗位数据");
+    }
+
+    /**
+     * 根据岗位编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:query')")
+    @GetMapping(value = "/{postId}")
+    public AjaxResult getInfo(@PathVariable Long postId)
+    {
+        return AjaxResult.success(postService.selectPostById(postId));
+    }
+
+    /**
+     * 新增岗位
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:add')")
+    @Log(title = "岗位管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysPost post)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
+        {
+            return AjaxResult.error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
+        {
+            return AjaxResult.error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
+        }
+        post.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(postService.insertPost(post));
+    }
+
+    /**
+     * 修改岗位
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:edit')")
+    @Log(title = "岗位管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysPost post)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
+        {
+            return AjaxResult.error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
+        {
+            return AjaxResult.error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
+        }
+        post.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(postService.updatePost(post));
+    }
+
+    /**
+     * 删除岗位
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:remove')")
+    @Log(title = "岗位管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{postIds}")
+    public AjaxResult remove(@PathVariable Long[] postIds)
+    {
+        return toAjax(postService.deletePostByIds(postIds));
+    }
+
+    /**
+     * 获取岗位选择框列表
+     */
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        List<SysPost> posts = postService.selectPostAll();
+        return AjaxResult.success(posts);
+    }
+}

+ 139 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysProfileController.java

@@ -0,0 +1,139 @@
+package com.future.module.system.controller;
+
+import java.io.IOException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.future.common.annotation.Log;
+import com.future.common.config.FutureConfig;
+import com.future.common.constant.UserConstants;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.system.domain.entity.SysUser;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.enums.BusinessType;
+import com.future.system.utils.SecurityUtils;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.StringUtils;
+import com.future.common.utils.file.FileUploadUtils;
+import com.future.framework.web.service.TokenService;
+import com.future.system.service.ISysUserService;
+
+/**
+ * 个人信息 业务处理
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/system/user/profile")
+public class SysProfileController extends BaseController
+{
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 个人信息
+     */
+    @GetMapping
+    public AjaxResult profile()
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        SysUser user = loginUser.getUser();
+        AjaxResult ajax = AjaxResult.success(user);
+        ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
+        ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
+        return ajax;
+    }
+
+    /**
+     * 修改用户
+     */
+    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult updateProfile(@RequestBody SysUser user)
+    {
+        if (StringUtils.isNotEmpty(user.getPhonenumber())
+                && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
+        {
+            return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
+        }
+        if (StringUtils.isNotEmpty(user.getEmail())
+                && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
+        {
+            return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
+        }
+        if (userService.updateUserProfile(user) > 0)
+        {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+            // 更新缓存用户信息
+            loginUser.getUser().setNickName(user.getNickName());
+            loginUser.getUser().setPhonenumber(user.getPhonenumber());
+            loginUser.getUser().setEmail(user.getEmail());
+            loginUser.getUser().setSex(user.getSex());
+            tokenService.setLoginUser(loginUser);
+            return AjaxResult.success();
+        }
+        return AjaxResult.error("修改个人信息异常,请联系管理员");
+    }
+
+    /**
+     * 重置密码
+     */
+    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
+    @PutMapping("/updatePwd")
+    public AjaxResult updatePwd(String oldPassword, String newPassword)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String userName = loginUser.getUsername();
+        String password = loginUser.getPassword();
+        if (!SecurityUtils.matchesPassword(oldPassword, password))
+        {
+            return AjaxResult.error("修改密码失败,旧密码错误");
+        }
+        if (SecurityUtils.matchesPassword(newPassword, password))
+        {
+            return AjaxResult.error("新密码不能与旧密码相同");
+        }
+        if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0)
+        {
+            // 更新缓存用户密码
+            loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
+            tokenService.setLoginUser(loginUser);
+            return AjaxResult.success();
+        }
+        return AjaxResult.error("修改密码异常,请联系管理员");
+    }
+
+    /**
+     * 头像上传
+     */
+    @Log(title = "用户头像", businessType = BusinessType.UPDATE)
+    @PostMapping("/avatar")
+    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws IOException
+    {
+        if (!file.isEmpty())
+        {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+            String avatar = FileUploadUtils.upload(FutureConfig.getAvatarPath(), file);
+            if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
+            {
+                AjaxResult ajax = AjaxResult.success();
+                ajax.put("imgUrl", avatar);
+                // 更新缓存用户头像
+                loginUser.getUser().setAvatar(avatar);
+                tokenService.setLoginUser(loginUser);
+                return ajax;
+            }
+        }
+        return AjaxResult.error("上传图片异常,请联系管理员");
+    }
+}

+ 182 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysRoleController.java

@@ -0,0 +1,182 @@
+package com.future.module.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.future.common.annotation.Log;
+import com.future.common.constant.UserConstants;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.system.domain.entity.SysRole;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.core.page.TableDataInfo;
+import com.future.common.enums.BusinessType;
+import com.future.system.utils.SecurityUtils;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.StringUtils;
+import com.future.common.utils.poi.ExcelUtil;
+import com.future.framework.web.service.SysPermissionService;
+import com.future.framework.web.service.TokenService;
+import com.future.system.service.ISysRoleService;
+import com.future.system.service.ISysUserService;
+
+/**
+ * 角色信息
+ * 
+ * @author future
+ */
+@RestController
+@RequestMapping("/system/role")
+public class SysRoleController extends BaseController
+{
+    @Autowired
+    private ISysRoleService roleService;
+
+    @Autowired
+    private TokenService tokenService;
+    
+    @Autowired
+    private SysPermissionService permissionService;
+    
+    @Autowired
+    private ISysUserService userService;
+
+    @PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysRole role)
+    {
+        startPage();
+        List<SysRole> list = roleService.selectRoleList(role);
+        return TableDataInfo.getDataTable(list);
+    }
+
+    @Log(title = "角色管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:role:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysRole role)
+    {
+        List<SysRole> list = roleService.selectRoleList(role);
+        ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
+        return util.exportExcel(list, "角色数据");
+    }
+
+    /**
+     * 根据角色编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping(value = "/{roleId}")
+    public AjaxResult getInfo(@PathVariable Long roleId)
+    {
+        return AjaxResult.success(roleService.selectRoleById(roleId));
+    }
+
+    /**
+     * 新增角色
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:add')")
+    @Log(title = "角色管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysRole role)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
+        {
+            return AjaxResult.error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
+        {
+            return AjaxResult.error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
+        }
+        role.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(roleService.insertRole(role));
+
+    }
+
+    /**
+     * 修改保存角色
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
+        {
+            return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
+        {
+            return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
+        }
+        role.setUpdateBy(SecurityUtils.getUsername());
+        
+        if (roleService.updateRole(role) > 0)
+        {
+            // 更新缓存用户权限
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+            if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
+            {
+                loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
+                loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
+                tokenService.setLoginUser(loginUser);
+            }
+            return AjaxResult.success();
+        }
+        return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
+    }
+
+    /**
+     * 修改保存数据权限
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/dataScope")
+    public AjaxResult dataScope(@RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        return toAjax(roleService.authDataScope(role));
+    }
+
+    /**
+     * 状态修改
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        role.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(roleService.updateRoleStatus(role));
+    }
+
+    /**
+     * 删除角色
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:remove')")
+    @Log(title = "角色管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{roleIds}")
+    public AjaxResult remove(@PathVariable Long[] roleIds)
+    {
+        return toAjax(roleService.deleteRoleByIds(roleIds));
+    }
+
+    /**
+     * 获取角色选择框列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        return AjaxResult.success(roleService.selectRoleAll());
+    }
+}

+ 210 - 0
Future/future-admin/src/main/java/com/future/module/system/controller/SysUserController.java

@@ -0,0 +1,210 @@
+package com.future.module.system.controller;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.future.common.annotation.Log;
+import com.future.common.constant.UserConstants;
+import com.future.common.core.controller.BaseController;
+import com.future.common.core.domain.AjaxResult;
+import com.future.system.domain.entity.SysRole;
+import com.future.system.domain.entity.SysUser;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.core.page.TableDataInfo;
+import com.future.common.enums.BusinessType;
+import com.future.system.utils.SecurityUtils;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.StringUtils;
+import com.future.common.utils.poi.ExcelUtil;
+import com.future.framework.web.service.TokenService;
+import com.future.system.service.ISysPostService;
+import com.future.system.service.ISysRoleService;
+import com.future.system.service.ISysUserService;
+
+/**
+ * 用户信息
+ * 
+ * @author future
+ */
+@Api(tags="用户管理")
+@RestController
+@RequestMapping("/system/user")
+public class SysUserController extends BaseController
+{
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private ISysRoleService roleService;
+
+    @Autowired
+    private ISysPostService postService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 获取用户列表
+     */
+    @ApiOperation(value = "获取用户列表")
+    @PreAuthorize("@ss.hasPermi('system:user:list')")
+    @GetMapping("/list")
+    public TableDataInfo<SysUser> list(SysUser user)
+    {
+        startPage();
+        List<SysUser> list = userService.selectUserList(user);
+        return TableDataInfo.getDataTable(list);
+    }
+
+    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:user:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysUser user)
+    {
+        List<SysUser> list = userService.selectUserList(user);
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        return util.exportExcel(list, "用户数据");
+    }
+
+    @Log(title = "用户管理", businessType = BusinessType.IMPORT)
+    @PreAuthorize("@ss.hasPermi('system:user:import')")
+    @PostMapping("/importData")
+    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
+    {
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        List<SysUser> userList = util.importExcel(file.getInputStream());
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String operName = loginUser.getUsername();
+        String message = userService.importUser(userList, updateSupport, operName);
+        return AjaxResult.success(message);
+    }
+
+    @GetMapping("/importTemplate")
+    public AjaxResult importTemplate()
+    {
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        return util.importTemplateExcel("用户数据");
+    }
+
+    /**
+     * 根据用户编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:query')")
+    @GetMapping(value = { "/", "/{userId}" })
+    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        List<SysRole> roles = roleService.selectRoleAll();
+        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
+        ajax.put("posts", postService.selectPostAll());
+        if (StringUtils.isNotNull(userId))
+        {
+            ajax.put(AjaxResult.DATA_TAG, userService.selectUserById(userId));
+            ajax.put("postIds", postService.selectPostListByUserId(userId));
+            ajax.put("roleIds", roleService.selectRoleListByUserId(userId));
+        }
+        return ajax;
+    }
+
+    /**
+     * 新增用户
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:add')")
+    @Log(title = "用户管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysUser user)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName())))
+        {
+            return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
+        }
+        else if (StringUtils.isNotEmpty(user.getPhonenumber())
+                && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
+        {
+            return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
+        }
+        else if (StringUtils.isNotEmpty(user.getEmail())
+                && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
+        {
+            return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
+        }
+        user.setCreateBy(SecurityUtils.getUsername());
+        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        return toAjax(userService.insertUser(user));
+    }
+
+    /**
+     * 修改用户
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:edit')")
+    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        if (StringUtils.isNotEmpty(user.getPhonenumber())
+                && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
+        {
+            return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
+        }
+        else if (StringUtils.isNotEmpty(user.getEmail())
+                && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
+        {
+            return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
+        }
+        user.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(userService.updateUser(user));
+    }
+
+    /**
+     * 删除用户
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:remove')")
+    @Log(title = "用户管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{userIds}")
+    public AjaxResult remove(@PathVariable Long[] userIds)
+    {
+        return toAjax(userService.deleteUserByIds(userIds));
+    }
+
+    /**
+     * 重置密码
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
+    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/resetPwd")
+    public AjaxResult resetPwd(@RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        user.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(userService.resetPwd(user));
+    }
+
+    /**
+     * 状态修改
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:edit')")
+    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        user.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(userService.updateUserStatus(user));
+    }
+}

+ 31 - 0
Future/future-admin/src/main/java/com/future/module/tool/controller/SwaggerController.java

@@ -0,0 +1,31 @@
+package com.future.module.tool.controller;
+
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import com.future.common.core.controller.BaseController;
+
+/**
+ * swagger 接口
+ * 
+ * @author future
+ */
+@Controller
+@RequestMapping("/tool/swagger")
+public class SwaggerController extends BaseController
+{
+    @PreAuthorize("@ss.hasPermi('tool:swagger:view')")
+    @GetMapping()
+    public String index()
+    {
+        return redirect("/doc.html");
+    }
+
+    @PreAuthorize("@ss.hasPermi('tool:swagger:view')")
+    @GetMapping("/doc")
+    public String doc()
+    {
+        return redirect("/doc.html");
+    }
+}

+ 1 - 0
Future/future-admin/src/main/resources/META-INF/spring-devtools.properties

@@ -0,0 +1 @@
+restart.include.json=/com.alibaba.fastjson.*.jar

+ 57 - 0
Future/future-admin/src/main/resources/application-druid.yml

@@ -0,0 +1,57 @@
+   # 数据源配置
+spring:
+    datasource:
+        type: com.alibaba.druid.pool.DruidDataSource
+        driverClassName: com.mysql.cj.jdbc.Driver
+        druid:
+            # 主库数据源
+            master:
+                url: jdbc:mysql://127.0.0.1:3306/future?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                username: root
+                password: 123456
+            # 从库数据源
+            slave:
+                # 从数据源开关/默认关闭
+                enabled: false
+                url: 
+                username: 
+                password: 
+            # 初始连接数
+            initialSize: 5
+            # 最小连接池数量
+            minIdle: 10
+            # 最大连接池数量
+            maxActive: 20
+            # 配置获取连接等待超时的时间
+            maxWait: 60000
+            # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+            timeBetweenEvictionRunsMillis: 60000
+            # 配置一个连接在池中最小生存的时间,单位是毫秒
+            minEvictableIdleTimeMillis: 300000
+            # 配置一个连接在池中最大生存的时间,单位是毫秒
+            maxEvictableIdleTimeMillis: 900000
+            # 配置检测连接是否有效
+            validationQuery: SELECT 1 FROM DUAL
+            testWhileIdle: true
+            testOnBorrow: false
+            testOnReturn: false
+            webStatFilter: 
+                enabled: true
+            statViewServlet:
+                enabled: true
+                # 设置白名单,不填则允许所有访问
+                allow:
+                url-pattern: /druid/*
+                # 控制台管理用户名和密码
+                login-username: admin
+                login-password: 123456
+            filter:
+                stat:
+                    enabled: true
+                    # 慢SQL记录
+                    log-slow-sql: true
+                    slow-sql-millis: 1000
+                    merge-sql: true
+                wall:
+                    config:
+                        multi-statement-allow: true

+ 141 - 0
Future/future-admin/src/main/resources/application.yml

@@ -0,0 +1,141 @@
+# 项目相关配置
+future:
+  # 名称
+  name: future
+  # 版本
+  version: 3.4.0
+  # 版权年份
+  copyrightYear: 2021
+  # 项目描述
+  desc: 该项目用于用于公司内部基础版本使用
+  # 实例演示开关
+  demoEnabled: true
+  # 文件路径 示例( Windows配置D:/future/uploadPath,Linux配置 /home/future/uploadPath)
+  profile: D:/future/uploadPath
+  # 获取ip地址开关
+  addressEnabled: false
+  # 验证码类型 math 数组计算 char 字符验证
+  captchaType: math
+
+# 开发环境配置
+server:
+  # 服务器的HTTP端口,默认为8080
+  port: 8080
+  servlet:
+    # 应用的访问路径
+    context-path: /
+  tomcat:
+    # tomcat的URI编码
+    uri-encoding: UTF-8
+    # tomcat最大线程数,默认为200
+    max-threads: 800
+    # Tomcat启动初始化的线程数,默认值25
+    min-spare-threads: 30
+#配置脱敏策略
+log:
+  desensitize:
+    config:
+      closeSwitch: false
+# 日志配置
+logging:
+
+  level:
+    com.future: debug
+    org.springframework: warn
+  #快速实现log配置
+  config: classpath:logback.xml
+#  #把日志添加到文件
+#  config: classpath:logConfig/logBackFileAppender.xml
+#  #根据相应的滚动算法重命名文件
+#  config: classpath:logConfig/logBackFixedWindowRollingPolicy.xml
+#  #日志通过邮件发送到邮箱
+#  config: classpath:logConfig/logBackSMTPAppender.xml
+#  #日志保存到数据库
+#  config: classpath:logConfig/logBackDBAppender.xml
+
+#  #日志同个特定符号进行分类
+#  config: classpath:logConfig/logBackSiftingAppender.xml
+
+# Spring配置
+spring:
+  # 资源信息
+  messages:
+    # 国际化资源文件路径
+    basename: i18n/messages
+  profiles: 
+    active: druid
+  # 文件上传
+  servlet:
+     multipart:
+       # 单个文件大小
+       max-file-size:  10MB
+       # 设置总上传的文件大小
+       max-request-size:  20MB
+  # 服务模块
+  devtools:
+    restart:
+      # 热部署开关
+      enabled: true
+  # redis 配置
+  redis:
+    # 地址
+    host: 49.235.127.212
+    # 端口,默认为6379
+    port: 6379
+    # 数据库索引
+    database: 0
+    # 密码
+    password: zdd755
+    # 连接超时时间
+    timeout: 10s
+    lettuce:
+      pool:
+        # 连接池中的最小空闲连接
+        min-idle: 0
+        # 连接池中的最大空闲连接
+        max-idle: 8
+        # 连接池的最大数据库连接数
+        max-active: 8
+        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: -1ms
+
+# token配置
+token:
+    # 令牌自定义标识
+    header: Authorization
+    # 令牌密钥
+    secret: abcdefghijklmnopqrstuvwxyz
+    # 令牌有效期(默认30分钟)
+    expireTime: 30
+  
+# MyBatis配置
+mybatis:
+    # 搜索指定包别名
+    typeAliasesPackage: com.future.**.domain
+    # 配置mapper的扫描,找到所有的mapper.xml映射文件
+    mapperLocations: classpath*:mapper/**/*Mapper.xml
+    # 加载全局的配置文件
+    configLocation: classpath:mybatis/mybatis-config.xml
+
+# PageHelper分页插件
+pagehelper: 
+  helperDialect: mysql
+  reasonable: true
+  supportMethodsArguments: true
+  params: count=countSql 
+
+# Swagger配置
+swagger:
+  # 是否开启swagger
+  enabled: true
+  # 请求前缀
+  pathMapping: /dev-api
+
+# 防止XSS攻击
+xss: 
+  # 过滤开关
+  enabled: true
+  # 排除链接(多个用逗号分隔)
+  excludes: /system/notice/*
+  # 匹配链接
+  urlPatterns: /system/*,/monitor/*,/tool/*

+ 11 - 0
Future/future-admin/src/main/resources/banner.txt

@@ -0,0 +1,11 @@
+Application Version: ${future.version}
+Spring Boot Version: ${spring-boot.version}
+
+
+███████╗██╗   ██╗████████╗██╗   ██╗██████╗ ███████╗
+██╔════╝██║   ██║╚══██╔══╝██║   ██║██╔══██╗██╔════╝
+█████╗  ██║   ██║   ██║   ██║   ██║██████╔╝█████╗
+██╔══╝  ██║   ██║   ██║   ██║   ██║██╔══██╗██╔══╝
+██║     ╚██████╔╝   ██║   ╚██████╔╝██║  ██║███████╗
+╚═╝      ╚═════╝    ╚═╝    ╚═════╝ ╚═╝  ╚═╝╚══════╝
+

+ 36 - 0
Future/future-admin/src/main/resources/i18n/messages.properties

@@ -0,0 +1,36 @@
+#错误消息
+not.null=* 必须填写
+user.jcaptcha.error=验证码错误
+user.jcaptcha.expire=验证码已失效
+user.not.exists=用户不存在/密码错误
+user.password.not.match=用户不存在/密码错误
+user.password.retry.limit.count=密码输入错误{0}次
+user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟
+user.password.delete=对不起,您的账号已被删除
+user.blocked=用户已封禁,请联系管理员
+role.blocked=角色已封禁,请联系管理员
+user.logout.success=退出成功
+
+length.not.valid=长度必须在{min}到{max}个字符之间
+
+user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
+user.password.not.valid=* 5-50个字符
+ 
+user.email.not.valid=邮箱格式错误
+user.mobile.phone.number.not.valid=手机号格式错误
+user.login.success=登录成功
+user.notfound=请重新登录
+user.forcelogout=管理员强制退出,请重新登录
+user.unknown.error=未知错误,请重新登录
+
+##文件上传消息
+upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
+upload.filename.exceed.length=上传的文件名最长{0}个字符
+
+##权限
+no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
+no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
+no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
+no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
+no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
+no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]

+ 40 - 0
Future/future-admin/src/main/resources/logConfig/logBackDBAppender.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+    <property name="log.path" value="logs" />
+    <!-- 日志输出格式 -->
+    <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="DB" class="ch.qos.logback.classic.db.DBAppender">
+            <connectionSource
+                    class="ch.qos.logback.core.db.DriverManagerConnectionSource">
+                ​    <driverClass>com.mysql.cj.jdbc.Driver</driverClass>
+                ​    <url>jdbc:mysql://127.0.0.1:3306/log-server?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC</url>
+                ​    <user>root</user>
+                ​    <password>123456</password>
+        </connectionSource>
+    </appender>
+    <root level="DEBUG">
+        <appender-ref ref="DB" />
+    </root>
+
+
+
+
+
+
+    <!-- 系统模块日志级别控制  -->
+    <logger name="com.future" level="info" />
+
+
+    <root level="info">
+        <appender-ref ref="console" />
+    </root>
+</configuration>

+ 97 - 0
Future/future-admin/src/main/resources/logConfig/logBackDemo1.xml

@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+    <property name="log.path" value="logs" />
+    <!-- 日志输出格式 -->
+    <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}/sys-info.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/sys-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}/sys-error.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/sys-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>
+
+    <!-- 用户访问日志输出  -->
+    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/sys-user.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 按天回滚 daily -->
+            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 60天 -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="plumelog"/>
+    </root>
+
+    <!-- 系统模块日志级别控制  -->
+    <logger name="com.future" 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>
+
+    <!--系统用户操作日志-->
+    <logger name="sys-user" level="info">
+        <appender-ref ref="sys-user"/>
+    </logger>
+</configuration>

+ 38 - 0
Future/future-admin/src/main/resources/logConfig/logBackFileAppender.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+    <property name="log.path" value="logs" />
+    <!-- 日志输出格式 -->
+    <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" class="ch.qos.logback.core.FileAppender">
+        <file>${log.path}/testFile.log</file>
+        <append>true</append>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <!-- 系统模块日志级别控制  -->
+    <logger name="com.future" level="info" />
+    <logger name="FILE" level="info" >
+        <appender-ref ref="FILE"/>
+    </logger>
+
+    <!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="FILE" />
+<!--        <appender-ref ref="file_error" />-->
+    </root>
+
+    <root level="info">
+        <appender-ref ref="console" />
+    </root>
+</configuration>

+ 45 - 0
Future/future-admin/src/main/resources/logConfig/logBackFixedWindowRollingPolicy.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+    <property name="log.path" value="logs" />
+    <!-- 日志输出格式 -->
+    <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" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/logDemo.test.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+            <fileNamePattern>${log.path}/logDemo.tests.%i.log.zip</fileNamePattern>
+            <minIndex>1</minIndex>
+            <maxIndex>10</maxIndex>
+        </rollingPolicy>
+        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+            <maxFileSize>100kb</maxFileSize>
+        </triggeringPolicy>
+        <encoder>
+            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <!-- 系统模块日志级别控制  -->
+    <logger name="com.future" level="info" />
+    <logger name="FILE" level="info" >
+        <appender-ref ref="FILE"/>
+    </logger>
+
+    <!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="FILE" />
+<!--        <appender-ref ref="file_error" />-->
+    </root>
+
+    <root level="info">
+        <appender-ref ref="console" />
+    </root>
+</configuration>

+ 45 - 0
Future/future-admin/src/main/resources/logConfig/logBackSMTPAppender.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+    <property name="log.path" value="logs" />
+    <!-- 日志输出格式 -->
+    <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="EMAIL_Q" class="ch.qos.logback.classic.net.SMTPAppender">
+        <smtpHost>smtp.qq.com</smtpHost>
+        <smtpPort>465</smtpPort>
+        <STARTTLS>true</STARTTLS>
+        <username>1537157089@qq.com</username>
+        <password>chzhbtylzqydbaae</password>
+        <to>2123214553@qq.com</to>
+        <to>haitianbocai@163.com</to> <!-- additional destinations are possible -->
+        <from>1537157089@qq.com</from>
+        <subject>TESTING: %logger{20} - %m</subject>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%date %-5level %logger - %message%n</pattern>
+        </layout>
+    </appender>
+    <root level="DEBUG">
+        <appender-ref ref="EMAIL_Q" />
+    </root>
+
+
+
+
+
+
+    <!-- 系统模块日志级别控制  -->
+    <logger name="com.future" level="info" />
+
+
+    <root level="info">
+        <appender-ref ref="console" />
+    </root>
+</configuration>

+ 49 - 0
Future/future-admin/src/main/resources/logConfig/logBackSiftingAppender.xml

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+    <property name="log.path" value="logs" />
+    <!-- 日志输出格式 -->
+    <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="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
+        <!-- in the absence of the class attribute, it is assumed that the
+      ​    desired discriminator type is
+      ​    ch.qos.logback.classic.sift.MDCBasedDiscriminator -->
+        <discriminator>
+            <key>userid</key>
+            <defaultValue>unknown</defaultValue>
+        </discriminator>
+        <sift>
+            <appender name="FILE-${userid}" class="ch.qos.logback.core.FileAppender">
+                ​    <file>${log.path}/shift.${userid}.log</file>
+                ​    <append>false</append>
+                ​    <layout class="ch.qos.logback.classic.PatternLayout">
+                ​     <pattern>%d [%thread] %level %mdc %logger{35} - %msg%n</pattern>
+                ​    </layout>
+            </appender>
+        </sift>
+    </appender>
+    <root level="DEBUG">
+        <appender-ref ref="SIFT" />
+    </root>
+
+
+
+
+
+
+    <!-- 系统模块日志级别控制  -->
+    <logger name="com.future" level="info" />
+
+
+    <root level="info">
+        <appender-ref ref="console" />
+    </root>
+</configuration>

+ 110 - 0
Future/future-admin/src/main/resources/logConfig/logbackDemo2.xml

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+	<property name="log.path" value="logs" />
+    <!-- 日志输出格式 -->
+	<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}/sys-info.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+			<fileNamePattern>${log.path}/%d{yyyyMM}/sys-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}/sys-error.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/sys-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>
+	
+	<!-- 用户访问日志输出  -->
+    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-user.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 按天回滚 daily -->
+            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 60天 -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="plumelog" class="com.plumelog.logback.appender.RedisAppender">
+        <appName>future</appName>
+        <!--        <appName>${plumelog.appName}</appName>-->
+        <redisHost>127.0.0.1:6379</redisHost>
+        <!--        <redisHost>${plumelog.redisHost}</redisHost>-->
+        <!-- 如果使用redis有密码,启用下面配置 -->
+        <!--        <redisAuth>${plumelog.redisAuth}</redisAuth>-->
+        <!-- redis端口号,不配置默认6379-->
+        <!-- runModel 1,2  1表示最高性能模式,2表示低性能模式 但是2可以获取更多信息 不配置默认为1-->
+        <!-- 整合其他链路插件,启用下面配置 sleuth表示整合springcloud.sleuth-->
+        <!--<expand>sleuth</expand>-->
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="plumelog"/>
+    </root>
+	
+	<!-- 系统模块日志级别控制  -->
+	<logger name="com.future" level="info" additivity="false"/>
+	<!-- 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>
+	
+	<!--系统用户操作日志-->
+    <logger name="sys-user" level="info" >
+        <appender-ref ref="sys-user"/>
+    </logger>
+</configuration> 

+ 112 - 0
Future/future-admin/src/main/resources/logback.xml

@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+    <conversionRule conversionWord="m" converterClass="com.future.log.logback.SensitiveDataConverter"/>
+    <!-- 日志存放路径 -->
+	<property name="log.path" value="logs" />
+    <!-- 日志输出格式 -->
+	<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}/sys-info.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+			<fileNamePattern>${log.path}/sys-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}/sys-error.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/sys-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>
+	
+	<!-- 用户访问日志输出  -->
+    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-user.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 按天回滚 daily -->
+            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 60天 -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="plumelog" class="com.plumelog.logback.appender.RedisAppender">
+        <appName>future</appName>
+        <!--        <appName>${plumelog.appName}</appName>-->
+        <redisHost>127.0.0.1:6379</redisHost>
+        <!--        <redisHost>${plumelog.redisHost}</redisHost>-->
+        <!-- 如果使用redis有密码,启用下面配置 -->
+        <!--        <redisAuth>${plumelog.redisAuth}</redisAuth>-->
+        <!-- redis端口号,不配置默认6379-->
+        <!-- runModel 1,2  1表示最高性能模式,2表示低性能模式 但是2可以获取更多信息 不配置默认为1-->
+        <!-- 整合其他链路插件,启用下面配置 sleuth表示整合springcloud.sleuth-->
+        <!--<expand>sleuth</expand>-->
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="plumelog"/>
+    </root>
+	
+	<!-- 系统模块日志级别控制  -->
+	<logger name="com.future" level="info" additivity="false"/>
+	<!-- 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>
+	
+	<!--系统用户操作日志-->
+    <logger name="sys-user" level="info" >
+        <appender-ref ref="sys-user"/>
+    </logger>
+</configuration> 

+ 15 - 0
Future/future-admin/src/main/resources/mybatis/mybatis-config.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE configuration
+PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-config.dtd">
+<configuration>
+	
+	<settings>
+		<setting name="cacheEnabled"             value="true" />  <!-- 全局映射器启用缓存 -->
+		<setting name="useGeneratedKeys"         value="true" />  <!-- 允许 JDBC 支持自动生成主键 -->
+		<setting name="defaultExecutorType"      value="REUSE" /> <!-- 配置默认的执行器 -->
+		<setting name="logImpl"                  value="SLF4J" /> <!-- 指定 MyBatis 所用日志的具体实现 -->
+		<!-- <setting name="mapUnderscoreToCamelCase" value="true"/>  驼峰式命名 -->
+	</settings>
+	
+</configuration>

+ 70 - 0
Future/future-framework/pom.xml

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>future</artifactId>
+        <groupId>com.future</groupId>
+        <version>3.4.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>future-framework</artifactId>
+
+    <description>
+        framework框架核心
+    </description>
+
+    <dependencies>
+
+        <!-- SpringBoot Web容器 -->
+         <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- SpringBoot 拦截器 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <!-- 阿里数据库连接池 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 验证码 -->
+        <dependency>
+            <groupId>com.github.penggle</groupId>
+            <artifactId>kaptcha</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>javax.servlet-api</artifactId>
+                    <groupId>javax.servlet</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- 获取系统信息 -->
+        <dependency>
+            <groupId>com.github.oshi</groupId>
+            <artifactId>oshi-core</artifactId>
+        </dependency>
+
+        <!-- 通用工具-->
+        <dependency>
+            <groupId>com.future</groupId>
+            <artifactId>future-common</artifactId>
+        </dependency>
+
+        <!-- 系统模块-->
+        <dependency>
+            <groupId>com.future</groupId>
+            <artifactId>future-system</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 169 - 0
Future/future-framework/src/main/java/com/future/framework/aspectj/DataScopeAspect.java

@@ -0,0 +1,169 @@
+package com.future.framework.aspectj;
+
+import java.lang.reflect.Method;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+import com.future.common.annotation.DataScope;
+import com.future.common.core.domain.BaseEntity;
+import com.future.system.domain.entity.SysRole;
+import com.future.system.domain.entity.SysUser;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.StringUtils;
+import com.future.common.utils.spring.SpringUtils;
+import com.future.framework.web.service.TokenService;
+
+/**
+ * 数据过滤处理
+ *
+ * @author future
+ */
+@Aspect
+@Component
+public class DataScopeAspect
+{
+    /**
+     * 全部数据权限
+     */
+    public static final String DATA_SCOPE_ALL = "1";
+
+    /**
+     * 自定数据权限
+     */
+    public static final String DATA_SCOPE_CUSTOM = "2";
+
+    /**
+     * 部门数据权限
+     */
+    public static final String DATA_SCOPE_DEPT = "3";
+
+    /**
+     * 部门及以下数据权限
+     */
+    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
+
+    /**
+     * 仅本人数据权限
+     */
+    public static final String DATA_SCOPE_SELF = "5";
+
+    /**
+     * 数据权限过滤关键字
+     */
+    public static final String DATA_SCOPE = "dataScope";
+
+    // 配置织入点
+    @Pointcut("@annotation(com.future.common.annotation.DataScope)")
+    public void dataScopePointCut()
+    {
+    }
+
+    @Before("dataScopePointCut()")
+    public void doBefore(JoinPoint point) throws Throwable
+    {
+        handleDataScope(point);
+    }
+
+    protected void handleDataScope(final JoinPoint joinPoint)
+    {
+        // 获得注解
+        DataScope controllerDataScope = getAnnotationLog(joinPoint);
+        if (controllerDataScope == null)
+        {
+            return;
+        }
+        // 获取当前的用户
+        LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
+        if (StringUtils.isNotNull(loginUser))
+        {
+            SysUser currentUser = loginUser.getUser();
+            // 如果是超级管理员,则不过滤数据
+            if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
+            {
+                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
+                        controllerDataScope.userAlias());
+            }
+        }
+    }
+
+    /**
+     * 数据范围过滤
+     *
+     * @param joinPoint 切点
+     * @param user 用户
+     * @param userAlias 别名
+     */
+    public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
+    {
+        StringBuilder sqlString = new StringBuilder();
+
+        for (SysRole role : user.getRoles())
+        {
+            String dataScope = role.getDataScope();
+            if (DATA_SCOPE_ALL.equals(dataScope))
+            {
+                sqlString = new StringBuilder();
+                break;
+            }
+            else if (DATA_SCOPE_CUSTOM.equals(dataScope))
+            {
+                sqlString.append(StringUtils.format(
+                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
+                        role.getRoleId()));
+            }
+            else if (DATA_SCOPE_DEPT.equals(dataScope))
+            {
+                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
+            }
+            else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
+            {
+                sqlString.append(StringUtils.format(
+                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
+                        deptAlias, user.getDeptId(), user.getDeptId()));
+            }
+            else if (DATA_SCOPE_SELF.equals(dataScope))
+            {
+                if (StringUtils.isNotBlank(userAlias))
+                {
+                    sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
+                }
+                else
+                {
+                    // 数据权限为仅本人且没有userAlias别名不查询任何数据
+                    sqlString.append(" OR 1=0 ");
+                }
+            }
+        }
+
+        if (StringUtils.isNotBlank(sqlString.toString()))
+        {
+            Object params = joinPoint.getArgs()[0];
+            if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
+            {
+                BaseEntity baseEntity = (BaseEntity) params;
+                baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
+            }
+        }
+    }
+
+    /**
+     * 是否存在注解,如果存在就获取
+     */
+    private DataScope getAnnotationLog(JoinPoint joinPoint)
+    {
+        Signature signature = joinPoint.getSignature();
+        MethodSignature methodSignature = (MethodSignature) signature;
+        Method method = methodSignature.getMethod();
+
+        if (method != null)
+        {
+            return method.getAnnotation(DataScope.class);
+        }
+        return null;
+    }
+}

+ 72 - 0
Future/future-framework/src/main/java/com/future/framework/aspectj/DataSourceAspect.java

@@ -0,0 +1,72 @@
+package com.future.framework.aspectj;
+
+import java.util.Objects;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import com.future.common.annotation.DataSource;
+import com.future.common.utils.StringUtils;
+import com.future.framework.datasource.DynamicDataSourceContextHolder;
+
+/**
+ * 多数据源处理
+ * 
+ * @author future
+ */
+@Aspect
+@Order(1)
+@Component
+public class DataSourceAspect
+{
+    protected Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Pointcut("@annotation(com.future.common.annotation.DataSource)"
+            + "|| @within(com.future.common.annotation.DataSource)")
+    public void dsPointCut()
+    {
+
+    }
+
+    @Around("dsPointCut()")
+    public Object around(ProceedingJoinPoint point) throws Throwable
+    {
+        DataSource dataSource = getDataSource(point);
+
+        if (StringUtils.isNotNull(dataSource))
+        {
+            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
+        }
+
+        try
+        {
+            return point.proceed();
+        }
+        finally
+        {
+            // 销毁数据源 在执行方法之后
+            DynamicDataSourceContextHolder.clearDataSourceType();
+        }
+    }
+
+    /**
+     * 获取需要切换的数据源
+     */
+    public DataSource getDataSource(ProceedingJoinPoint point)
+    {
+        MethodSignature signature = (MethodSignature) point.getSignature();
+        DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
+        if (Objects.nonNull(dataSource))
+        {
+            return dataSource;
+        }
+
+        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
+    }
+}

+ 246 - 0
Future/future-framework/src/main/java/com/future/framework/aspectj/LogAspect.java

@@ -0,0 +1,246 @@
+package com.future.framework.aspectj;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.future.common.constant.Constants;
+import com.future.system.domain.SysOperLog;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.HandlerMapping;
+import com.alibaba.fastjson.JSON;
+import com.future.common.annotation.Log;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.enums.BusinessStatus;
+import com.future.common.enums.HttpMethod;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.StringUtils;
+import com.future.common.utils.ip.IpUtils;
+import com.future.common.utils.spring.SpringUtils;
+import com.future.framework.manager.AsyncManager;
+import com.future.framework.manager.factory.AsyncFactory;
+import com.future.framework.web.service.TokenService;
+
+/**
+ * 操作日志记录处理
+ * 
+ * @author future
+ */
+//@Aspect
+//@Component
+public class LogAspect
+{
+    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
+
+    // 配置织入点
+    @Pointcut("@annotation(com.future.common.annotation.Log)")
+    public void logPointCut()
+    {
+    }
+
+    /**
+     * 处理完请求后执行
+     *
+     * @param joinPoint 切点
+     */
+    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
+    {
+        handleLog(joinPoint, null, jsonResult);
+    }
+
+    /**
+     * 拦截异常操作
+     * 
+     * @param joinPoint 切点
+     * @param e 异常
+     */
+    @AfterThrowing(value = "logPointCut()", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, Exception e)
+    {
+        handleLog(joinPoint, e, null);
+    }
+
+    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
+    {
+        try
+        {
+            // 获得注解
+            Log controllerLog = getAnnotationLog(joinPoint);
+            if (controllerLog == null)
+            {
+                return;
+            }
+
+            // 获取当前的用户
+            LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
+
+            // *========数据库日志=========*//
+            SysOperLog operLog = new SysOperLog();
+            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
+            // 请求的地址
+            String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
+            operLog.setOperIp(ip);
+            // 返回参数
+            operLog.setJsonResult(JSON.toJSONString(jsonResult));
+
+            operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
+            if (loginUser != null)
+            {
+                operLog.setOperName(loginUser.getUsername());
+            }
+
+            if (e != null)
+            {
+                operLog.setStatus(BusinessStatus.FAIL.ordinal());
+                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
+            }
+            // 设置方法名称
+            String className = joinPoint.getTarget().getClass().getName();
+            String methodName = joinPoint.getSignature().getName();
+            operLog.setMethod(className + "." + methodName + "()");
+            // 设置请求方式
+            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
+            // 处理设置注解上的参数
+            getControllerMethodDescription(joinPoint, controllerLog, operLog);
+            // 保存数据库
+            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
+        }
+        catch (Exception exp)
+        {
+            // 记录本地异常日志
+            log.error("==前置通知异常==");
+            log.error("异常信息:{}", exp.getMessage());
+            exp.printStackTrace();
+        }
+    }
+
+    /**
+     * 获取注解中对方法的描述信息 用于Controller层注解
+     * 
+     * @param log 日志
+     * @param operLog 操作日志
+     * @throws Exception
+     */
+    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception
+    {
+        // 设置action动作
+        operLog.setBusinessType(log.businessType().ordinal());
+        // 设置标题
+        operLog.setTitle(log.title());
+        // 设置操作人类别
+        operLog.setOperatorType(log.operatorType().ordinal());
+        // 是否需要保存request,参数和值
+        if (log.isSaveRequestData())
+        {
+            // 获取参数的信息,传入到数据库中。
+            setRequestValue(joinPoint, operLog);
+        }
+    }
+
+    /**
+     * 获取请求的参数,放到log中
+     * 
+     * @param operLog 操作日志
+     * @throws Exception 异常
+     */
+    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception
+    {
+        String requestMethod = operLog.getRequestMethod();
+        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))
+        {
+            String params = argsArrayToString(joinPoint.getArgs());
+            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
+        }
+        else
+        {
+            Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
+            operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
+        }
+    }
+
+    /**
+     * 是否存在注解,如果存在就获取
+     */
+    private Log getAnnotationLog(JoinPoint joinPoint) throws Exception
+    {
+        Signature signature = joinPoint.getSignature();
+        MethodSignature methodSignature = (MethodSignature) signature;
+        Method method = methodSignature.getMethod();
+
+        if (method != null)
+        {
+            return method.getAnnotation(Log.class);
+        }
+        return null;
+    }
+
+    /**
+     * 参数拼装
+     */
+    private String argsArrayToString(Object[] paramsArray)
+    {
+        String params = "";
+        if (paramsArray != null && paramsArray.length > 0)
+        {
+            for (int i = 0; i < paramsArray.length; i++)
+            {
+                if (!isFilterObject(paramsArray[i]))
+                {
+                    Object jsonObj = JSON.toJSON(paramsArray[i]);
+                    params += jsonObj.toString() + " ";
+                }
+            }
+        }
+        return params.trim();
+    }
+
+    /**
+     * 判断是否需要过滤的对象。
+     * 
+     * @param o 对象信息。
+     * @return 如果是需要过滤的对象,则返回true;否则返回false。
+     */
+    @SuppressWarnings("rawtypes")
+    public boolean isFilterObject(final Object o)
+    {
+        Class<?> clazz = o.getClass();
+        if (clazz.isArray())
+        {
+            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
+        }
+        else if (Collection.class.isAssignableFrom(clazz))
+        {
+            Collection collection = (Collection) o;
+            for (Iterator iter = collection.iterator(); iter.hasNext();)
+            {
+                return iter.next() instanceof MultipartFile;
+            }
+        }
+        else if (Map.class.isAssignableFrom(clazz))
+        {
+            Map map = (Map) o;
+            for (Iterator iter = map.entrySet().iterator(); iter.hasNext();)
+            {
+                Map.Entry entry = (Map.Entry) iter.next();
+                return entry.getValue() instanceof MultipartFile;
+            }
+        }
+        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
+    }
+
+
+}

+ 30 - 0
Future/future-framework/src/main/java/com/future/framework/config/ApplicationConfig.java

@@ -0,0 +1,30 @@
+package com.future.framework.config;
+
+import java.util.TimeZone;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+/**
+ * 程序注解配置
+ *
+ * @author future
+ */
+@Configuration
+// 表示通过aop框架暴露该代理对象,AopContext能够访问
+@EnableAspectJAutoProxy(exposeProxy = true)
+// 指定要扫描的Mapper类的包的路径
+@MapperScan("com.future.**.mapper")
+public class ApplicationConfig
+{
+    /**
+     * 时区配置
+     */
+    @Bean
+    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
+    {
+        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
+    }
+}

+ 83 - 0
Future/future-framework/src/main/java/com/future/framework/config/CaptchaConfig.java

@@ -0,0 +1,83 @@
+package com.future.framework.config;
+
+import java.util.Properties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.google.code.kaptcha.impl.DefaultKaptcha;
+import com.google.code.kaptcha.util.Config;
+import static com.google.code.kaptcha.Constants.*;
+
+/**
+ * 验证码配置
+ * 
+ * @author future
+ */
+@Configuration
+public class CaptchaConfig
+{
+    @Bean(name = "captchaProducer")
+    public DefaultKaptcha getKaptchaBean()
+    {
+        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
+        Properties properties = new Properties();
+        // 是否有边框 默认为true 我们可以自己设置yes,no
+        properties.setProperty(KAPTCHA_BORDER, "yes");
+        // 验证码文本字符颜色 默认为Color.BLACK
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
+        // 验证码图片宽度 默认为200
+        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
+        // 验证码图片高度 默认为50
+        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
+        // 验证码文本字符大小 默认为40
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
+        // KAPTCHA_SESSION_KEY
+        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
+        // 验证码文本字符长度 默认为5
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
+        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
+        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
+        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
+        Config config = new Config(properties);
+        defaultKaptcha.setConfig(config);
+        return defaultKaptcha;
+    }
+
+    @Bean(name = "captchaProducerMath")
+    public DefaultKaptcha getKaptchaBeanMath()
+    {
+        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
+        Properties properties = new Properties();
+        // 是否有边框 默认为true 我们可以自己设置yes,no
+        properties.setProperty(KAPTCHA_BORDER, "yes");
+        // 边框颜色 默认为Color.BLACK
+        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
+        // 验证码文本字符颜色 默认为Color.BLACK
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
+        // 验证码图片宽度 默认为200
+        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
+        // 验证码图片高度 默认为50
+        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
+        // 验证码文本字符大小 默认为40
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
+        // KAPTCHA_SESSION_KEY
+        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
+        // 验证码文本生成器
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.future.framework.config.KaptchaTextCreator");
+        // 验证码文本字符间距 默认为2
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
+        // 验证码文本字符长度 默认为5
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
+        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
+        // 验证码噪点颜色 默认为Color.BLACK
+        properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
+        // 干扰实现类
+        properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
+        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
+        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
+        Config config = new Config(properties);
+        defaultKaptcha.setConfig(config);
+        return defaultKaptcha;
+    }
+}

+ 126 - 0
Future/future-framework/src/main/java/com/future/framework/config/DruidConfig.java

@@ -0,0 +1,126 @@
+package com.future.framework.config;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.sql.DataSource;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
+import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
+import com.alibaba.druid.util.Utils;
+import com.future.common.enums.DataSourceType;
+import com.future.common.utils.spring.SpringUtils;
+import com.future.framework.config.properties.DruidProperties;
+import com.future.framework.datasource.DynamicDataSource;
+
+/**
+ * druid 配置多数据源
+ * 
+ * @author future
+ */
+@Configuration
+public class DruidConfig
+{
+    @Bean
+    @ConfigurationProperties("spring.datasource.druid.master")
+    public DataSource masterDataSource(DruidProperties druidProperties)
+    {
+        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
+        return druidProperties.dataSource(dataSource);
+    }
+
+    @Bean
+    @ConfigurationProperties("spring.datasource.druid.slave")
+    @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
+    public DataSource slaveDataSource(DruidProperties druidProperties)
+    {
+        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
+        return druidProperties.dataSource(dataSource);
+    }
+
+    @Bean(name = "dynamicDataSource")
+    @Primary
+    public DynamicDataSource dataSource(DataSource masterDataSource)
+    {
+        Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
+        setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
+        return new DynamicDataSource(masterDataSource, targetDataSources);
+    }
+    
+    /**
+     * 设置数据源
+     * 
+     * @param targetDataSources 备选数据源集合
+     * @param sourceName 数据源名称
+     * @param beanName bean名称
+     */
+    public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
+    {
+        try
+        {
+            DataSource dataSource = SpringUtils.getBean(beanName);
+            targetDataSources.put(sourceName, dataSource);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+    /**
+     * 去除监控页面底部的广告
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Bean
+    @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
+    public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
+    {
+        // 获取web监控页面的参数
+        DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
+        // 提取common.js的配置路径
+        String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
+        String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
+        final String filePath = "support/http/resources/js/common.js";
+        // 创建filter进行过滤
+        Filter filter = new Filter()
+        {
+            @Override
+            public void init(javax.servlet.FilterConfig filterConfig) throws ServletException
+            {
+            }
+            @Override
+            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+                    throws IOException, ServletException
+            {
+                chain.doFilter(request, response);
+                // 重置缓冲区,响应头不会被重置
+                response.resetBuffer();
+                // 获取common.js
+                String text = Utils.readFromResource(filePath);
+                // 正则替换banner, 除去底部的广告信息
+                text = text.replaceAll("<a.*?banner\"></a><br/>", "");
+                text = text.replaceAll("powered.*?shrek.wang</a>", "");
+                response.getWriter().write(text);
+            }
+            @Override
+            public void destroy()
+            {
+            }
+        };
+        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
+        registrationBean.setFilter(filter);
+        registrationBean.addUrlPatterns(commonJsPattern);
+        return registrationBean;
+    }
+}

+ 71 - 0
Future/future-framework/src/main/java/com/future/framework/config/FastJson2JsonRedisSerializer.java

@@ -0,0 +1,71 @@
+package com.future.framework.config;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+import com.alibaba.fastjson.parser.ParserConfig;
+import org.springframework.util.Assert;
+import java.nio.charset.Charset;
+
+/**
+ * Redis使用FastJson序列化
+ * 
+ * @author future
+ */
+public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
+{
+    @SuppressWarnings("unused")
+    private ObjectMapper objectMapper = new ObjectMapper();
+
+    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
+
+    private Class<T> clazz;
+
+    static
+    {
+        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
+    }
+
+    public FastJson2JsonRedisSerializer(Class<T> clazz)
+    {
+        super();
+        this.clazz = clazz;
+    }
+
+    @Override
+    public byte[] serialize(T t) throws SerializationException
+    {
+        if (t == null)
+        {
+            return new byte[0];
+        }
+        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
+    }
+
+    @Override
+    public T deserialize(byte[] bytes) throws SerializationException
+    {
+        if (bytes == null || bytes.length <= 0)
+        {
+            return null;
+        }
+        String str = new String(bytes, DEFAULT_CHARSET);
+
+        return JSON.parseObject(str, clazz);
+    }
+
+    public void setObjectMapper(ObjectMapper objectMapper)
+    {
+        Assert.notNull(objectMapper, "'objectMapper' must not be null");
+        this.objectMapper = objectMapper;
+    }
+
+    protected JavaType getJavaType(Class<?> clazz)
+    {
+        return TypeFactory.defaultInstance().constructType(clazz);
+    }
+}

+ 60 - 0
Future/future-framework/src/main/java/com/future/framework/config/FilterConfig.java

@@ -0,0 +1,60 @@
+package com.future.framework.config;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.DispatcherType;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.future.common.filter.RepeatableFilter;
+import com.future.common.filter.XssFilter;
+import com.future.common.utils.StringUtils;
+
+/**
+ * Filter配置
+ *
+ * @author future
+ */
+@Configuration
+public class FilterConfig
+{
+    @Value("${xss.enabled}")
+    private String enabled;
+
+    @Value("${xss.excludes}")
+    private String excludes;
+
+    @Value("${xss.urlPatterns}")
+    private String urlPatterns;
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Bean
+    public FilterRegistrationBean xssFilterRegistration()
+    {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setDispatcherTypes(DispatcherType.REQUEST);
+        registration.setFilter(new XssFilter());
+        registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
+        registration.setName("xssFilter");
+        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
+        Map<String, String> initParameters = new HashMap<String, String>();
+        initParameters.put("excludes", excludes);
+        initParameters.put("enabled", enabled);
+        registration.setInitParameters(initParameters);
+        return registration;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Bean
+    public FilterRegistrationBean someFilterRegistration()
+    {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setFilter(new RepeatableFilter());
+        registration.addUrlPatterns("/*");
+        registration.setName("repeatableFilter");
+        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
+        return registration;
+    }
+
+}

+ 75 - 0
Future/future-framework/src/main/java/com/future/framework/config/KaptchaTextCreator.java

@@ -0,0 +1,75 @@
+package com.future.framework.config;
+
+import java.util.Random;
+import com.google.code.kaptcha.text.impl.DefaultTextCreator;
+
+/**
+ * 验证码文本生成器
+ * 
+ * @author future
+ */
+public class KaptchaTextCreator extends DefaultTextCreator
+{
+    private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
+
+    @Override
+    public String getText()
+    {
+        Integer result = 0;
+        Random random = new Random();
+        int x = random.nextInt(10);
+        int y = random.nextInt(10);
+        StringBuilder suChinese = new StringBuilder();
+        int randomoperands = (int) Math.round(Math.random() * 2);
+        if (randomoperands == 0)
+        {
+            result = x * y;
+            suChinese.append(CNUMBERS[x]);
+            suChinese.append("*");
+            suChinese.append(CNUMBERS[y]);
+        }
+        else if (randomoperands == 1)
+        {
+            if (!(x == 0) && y % x == 0)
+            {
+                result = y / x;
+                suChinese.append(CNUMBERS[y]);
+                suChinese.append("/");
+                suChinese.append(CNUMBERS[x]);
+            }
+            else
+            {
+                result = x + y;
+                suChinese.append(CNUMBERS[x]);
+                suChinese.append("+");
+                suChinese.append(CNUMBERS[y]);
+            }
+        }
+        else if (randomoperands == 2)
+        {
+            if (x >= y)
+            {
+                result = x - y;
+                suChinese.append(CNUMBERS[x]);
+                suChinese.append("-");
+                suChinese.append(CNUMBERS[y]);
+            }
+            else
+            {
+                result = y - x;
+                suChinese.append(CNUMBERS[y]);
+                suChinese.append("-");
+                suChinese.append(CNUMBERS[x]);
+            }
+        }
+        else
+        {
+            result = x + y;
+            suChinese.append(CNUMBERS[x]);
+            suChinese.append("+");
+            suChinese.append(CNUMBERS[y]);
+        }
+        suChinese.append("=?@" + result);
+        return suChinese.toString();
+    }
+}

+ 132 - 0
Future/future-framework/src/main/java/com/future/framework/config/MyBatisConfig.java

@@ -0,0 +1,132 @@
+package com.future.framework.config;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import javax.sql.DataSource;
+import org.apache.ibatis.io.VFS;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.util.ClassUtils;
+import com.future.common.utils.StringUtils;
+
+/**
+ * Mybatis支持*匹配扫描包
+ * 
+ * @author future
+ */
+@Configuration
+public class MyBatisConfig
+{
+    @Autowired
+    private Environment env;
+
+    static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
+
+    public static String setTypeAliasesPackage(String typeAliasesPackage)
+    {
+        ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
+        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
+        List<String> allResult = new ArrayList<String>();
+        try
+        {
+            for (String aliasesPackage : typeAliasesPackage.split(","))
+            {
+                List<String> result = new ArrayList<String>();
+                aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+                        + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
+                Resource[] resources = resolver.getResources(aliasesPackage);
+                if (resources != null && resources.length > 0)
+                {
+                    MetadataReader metadataReader = null;
+                    for (Resource resource : resources)
+                    {
+                        if (resource.isReadable())
+                        {
+                            metadataReader = metadataReaderFactory.getMetadataReader(resource);
+                            try
+                            {
+                                result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
+                            }
+                            catch (ClassNotFoundException e)
+                            {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                }
+                if (result.size() > 0)
+                {
+                    HashSet<String> hashResult = new HashSet<String>(result);
+                    allResult.addAll(hashResult);
+                }
+            }
+            if (allResult.size() > 0)
+            {
+                typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
+            }
+            else
+            {
+                throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
+            }
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+        return typeAliasesPackage;
+    }
+
+    public Resource[] resolveMapperLocations(String[] mapperLocations)
+    {
+        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
+        List<Resource> resources = new ArrayList<Resource>();
+        if (mapperLocations != null)
+        {
+            for (String mapperLocation : mapperLocations)
+            {
+                try
+                {
+                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
+                    resources.addAll(Arrays.asList(mappers));
+                }
+                catch (IOException e)
+                {
+                    // ignore
+                }
+            }
+        }
+        return resources.toArray(new Resource[resources.size()]);
+    }
+
+    @Bean
+    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
+    {
+        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
+        String mapperLocations = env.getProperty("mybatis.mapperLocations");
+        String configLocation = env.getProperty("mybatis.configLocation");
+        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
+        VFS.addImplClass(SpringBootVFS.class);
+
+        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
+        sessionFactory.setDataSource(dataSource);
+        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
+        sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
+        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
+        return sessionFactory.getObject();
+    }
+}

+ 45 - 0
Future/future-framework/src/main/java/com/future/framework/config/RedisConfig.java

@@ -0,0 +1,45 @@
+package com.future.framework.config;
+
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+
+/**
+ * redis配置
+ * 
+ * @author future
+ */
+@Configuration
+@EnableCaching
+public class RedisConfig extends CachingConfigurerSupport
+{
+    @Bean
+    @SuppressWarnings(value = { "unchecked", "rawtypes" })
+    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
+    {
+        RedisTemplate<Object, Object> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
+
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
+        serializer.setObjectMapper(mapper);
+
+        template.setValueSerializer(serializer);
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+        template.afterPropertiesSet();
+        return template;
+    }
+}

+ 66 - 0
Future/future-framework/src/main/java/com/future/framework/config/ResourcesConfig.java

@@ -0,0 +1,66 @@
+package com.future.framework.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import com.future.common.config.FutureConfig;
+import com.future.common.constant.Constants;
+import com.future.framework.interceptor.RepeatSubmitInterceptor;
+
+/**
+ * 通用配置
+ * 
+ * @author future
+ */
+@Configuration
+public class ResourcesConfig implements WebMvcConfigurer
+{
+    @Autowired
+    private RepeatSubmitInterceptor repeatSubmitInterceptor;
+
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry)
+    {
+        /** 本地文件上传路径 */
+        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + FutureConfig.getProfile() + "/");
+
+        /** swagger配置 */
+        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
+        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
+    }
+
+    /**
+     * 自定义拦截规则
+     */
+    @Override
+    public void addInterceptors(InterceptorRegistry registry)
+    {
+        registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
+    }
+
+    /**
+     * 跨域配置
+     */
+    @Bean
+    public CorsFilter corsFilter()
+    {
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        CorsConfiguration config = new CorsConfiguration();
+        config.setAllowCredentials(true);
+        // 设置访问源地址
+        config.addAllowedOrigin("*");
+        // 设置访问源请求头
+        config.addAllowedHeader("*");
+        // 设置访问源请求方法
+        config.addAllowedMethod("*");
+        // 对接口配置跨域设置
+        source.registerCorsConfiguration("/**", config);
+        return new CorsFilter(source);
+    }
+}

+ 148 - 0
Future/future-framework/src/main/java/com/future/framework/config/SecurityConfig.java

@@ -0,0 +1,148 @@
+package com.future.framework.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.security.web.authentication.logout.LogoutFilter;
+import org.springframework.web.filter.CorsFilter;
+import com.future.framework.security.filter.JwtAuthenticationTokenFilter;
+import com.future.framework.security.handle.AuthenticationEntryPointImpl;
+import com.future.framework.security.handle.LogoutSuccessHandlerImpl;
+
+/**
+ * spring security配置
+ * 
+ * @author future
+ */
+@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
+public class SecurityConfig extends WebSecurityConfigurerAdapter
+{
+    /**
+     * 自定义用户认证逻辑
+     */
+    @Autowired
+    private UserDetailsService userDetailsService;
+    
+    /**
+     * 认证失败处理类
+     */
+    @Autowired
+    private AuthenticationEntryPointImpl unauthorizedHandler;
+
+    /**
+     * 退出处理类
+     */
+    @Autowired
+    private LogoutSuccessHandlerImpl logoutSuccessHandler;
+
+    /**
+     * token认证过滤器
+     */
+    @Autowired
+    private JwtAuthenticationTokenFilter authenticationTokenFilter;
+
+    /**
+     * 跨域过滤器
+     */
+    @Autowired
+    private CorsFilter corsFilter;
+    
+    /**
+     * 解决 无法直接注入 AuthenticationManager
+     *
+     * @return
+     * @throws Exception
+     */
+    @Bean
+    @Override
+    public AuthenticationManager authenticationManagerBean() throws Exception
+    {
+        return super.authenticationManagerBean();
+    }
+
+    /**
+     * anyRequest          |   匹配所有请求路径
+     * access              |   SpringEl表达式结果为true时可以访问
+     * anonymous           |   匿名可以访问
+     * denyAll             |   用户不能访问
+     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
+     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
+     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
+     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
+     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
+     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
+     * permitAll           |   用户可以任意访问
+     * rememberMe          |   允许通过remember-me登录的用户访问
+     * authenticated       |   用户登录后可访问
+     */
+    @Override
+    protected void configure(HttpSecurity httpSecurity) throws Exception
+    {
+        httpSecurity
+                // CSRF禁用,因为不使用session
+                .csrf().disable()
+                // 认证失败处理类
+                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
+                // 基于token,所以不需要session
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
+                // 过滤请求
+                .authorizeRequests()
+                // 对于登录login 验证码captchaImage 允许匿名访问
+                .antMatchers("/login", "/captchaImage").anonymous()
+                .antMatchers(
+                        HttpMethod.GET,
+                        "/*.html",
+                        "/**/*.html",
+                        "/**/*.css",
+                        "/**/*.js"
+                ).permitAll()
+                .antMatchers("/profile/**").anonymous()
+                .antMatchers("/common/download**").anonymous()
+                .antMatchers("/common/download/resource**").anonymous()
+                .antMatchers("/swagger-ui.html").anonymous()
+                .antMatchers("/doc.html").anonymous()
+                .antMatchers("/swagger-resources/**").anonymous()
+                .antMatchers("/webjars/**").anonymous()
+                .antMatchers("/*/api-docs").anonymous()
+                .antMatchers("/druid/**").anonymous()
+                .antMatchers("/demo/**").anonymous()
+                // 除上面外的所有请求全部需要鉴权认证
+                .anyRequest().authenticated()
+                .and()
+                .headers().frameOptions().disable();
+        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
+        // 添加JWT filter
+        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
+        // 添加CORS filter
+        httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
+        httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
+    }
+
+    
+    /**
+     * 强散列哈希加密实现
+     */
+    @Bean
+    public BCryptPasswordEncoder bCryptPasswordEncoder()
+    {
+        return new BCryptPasswordEncoder();
+    }
+
+    /**
+     * 身份认证接口
+     */
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception
+    {
+        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
+    }
+}

+ 32 - 0
Future/future-framework/src/main/java/com/future/framework/config/ServerConfig.java

@@ -0,0 +1,32 @@
+package com.future.framework.config;
+
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.stereotype.Component;
+import com.future.common.utils.ServletUtils;
+
+/**
+ * 服务相关配置
+ * 
+ * @author future
+ */
+@Component
+public class ServerConfig
+{
+    /**
+     * 获取完整的请求路径,包括:域名,端口,上下文访问路径
+     * 
+     * @return 服务地址
+     */
+    public String getUrl()
+    {
+        HttpServletRequest request = ServletUtils.getRequest();
+        return getDomain(request);
+    }
+
+    public static String getDomain(HttpServletRequest request)
+    {
+        StringBuffer url = request.getRequestURL();
+        String contextPath = request.getServletContext().getContextPath();
+        return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
+    }
+}

+ 62 - 0
Future/future-framework/src/main/java/com/future/framework/config/ThreadPoolConfig.java

@@ -0,0 +1,62 @@
+package com.future.framework.config;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import com.future.common.utils.Threads;
+
+/**
+ * 线程池配置
+ *
+ * @author future
+ **/
+@Configuration
+public class ThreadPoolConfig
+{
+    // 核心线程池大小
+    private int corePoolSize = 50;
+
+    // 最大可创建的线程数
+    private int maxPoolSize = 200;
+
+    // 队列最大长度
+    private int queueCapacity = 1000;
+
+    // 线程池维护线程所允许的空闲时间
+    private int keepAliveSeconds = 300;
+
+    @Bean(name = "threadPoolTaskExecutor")
+    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
+    {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setMaxPoolSize(maxPoolSize);
+        executor.setCorePoolSize(corePoolSize);
+        executor.setQueueCapacity(queueCapacity);
+        executor.setKeepAliveSeconds(keepAliveSeconds);
+        // 线程池对拒绝任务(无线程可用)的处理策略
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        return executor;
+    }
+
+    /**
+     * 执行周期性或定时任务
+     */
+    @Bean(name = "scheduledExecutorService")
+    protected ScheduledExecutorService scheduledExecutorService()
+    {
+        return new ScheduledThreadPoolExecutor(corePoolSize,
+                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build())
+        {
+            @Override
+            protected void afterExecute(Runnable r, Throwable t)
+            {
+                super.afterExecute(r, t);
+                Threads.printException(r, t);
+            }
+        };
+    }
+}

+ 77 - 0
Future/future-framework/src/main/java/com/future/framework/config/properties/DruidProperties.java

@@ -0,0 +1,77 @@
+package com.future.framework.config.properties;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import com.alibaba.druid.pool.DruidDataSource;
+
+/**
+ * druid 配置属性
+ * 
+ * @author future
+ */
+@Configuration
+public class DruidProperties
+{
+    @Value("${spring.datasource.druid.initialSize}")
+    private int initialSize;
+
+    @Value("${spring.datasource.druid.minIdle}")
+    private int minIdle;
+
+    @Value("${spring.datasource.druid.maxActive}")
+    private int maxActive;
+
+    @Value("${spring.datasource.druid.maxWait}")
+    private int maxWait;
+
+    @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
+    private int timeBetweenEvictionRunsMillis;
+
+    @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
+    private int minEvictableIdleTimeMillis;
+
+    @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
+    private int maxEvictableIdleTimeMillis;
+
+    @Value("${spring.datasource.druid.validationQuery}")
+    private String validationQuery;
+
+    @Value("${spring.datasource.druid.testWhileIdle}")
+    private boolean testWhileIdle;
+
+    @Value("${spring.datasource.druid.testOnBorrow}")
+    private boolean testOnBorrow;
+
+    @Value("${spring.datasource.druid.testOnReturn}")
+    private boolean testOnReturn;
+
+    public DruidDataSource dataSource(DruidDataSource datasource)
+    {
+        /** 配置初始化大小、最小、最大 */
+        datasource.setInitialSize(initialSize);
+        datasource.setMaxActive(maxActive);
+        datasource.setMinIdle(minIdle);
+
+        /** 配置获取连接等待超时的时间 */
+        datasource.setMaxWait(maxWait);
+
+        /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
+        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+
+        /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
+        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
+
+        /**
+         * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
+         */
+        datasource.setValidationQuery(validationQuery);
+        /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
+        datasource.setTestWhileIdle(testWhileIdle);
+        /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
+        datasource.setTestOnBorrow(testOnBorrow);
+        /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
+        datasource.setTestOnReturn(testOnReturn);
+        return datasource;
+    }
+}

+ 26 - 0
Future/future-framework/src/main/java/com/future/framework/datasource/DynamicDataSource.java

@@ -0,0 +1,26 @@
+package com.future.framework.datasource;
+
+import java.util.Map;
+import javax.sql.DataSource;
+import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+
+/**
+ * 动态数据源
+ * 
+ * @author future
+ */
+public class DynamicDataSource extends AbstractRoutingDataSource
+{
+    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
+    {
+        super.setDefaultTargetDataSource(defaultTargetDataSource);
+        super.setTargetDataSources(targetDataSources);
+        super.afterPropertiesSet();
+    }
+
+    @Override
+    protected Object determineCurrentLookupKey()
+    {
+        return DynamicDataSourceContextHolder.getDataSourceType();
+    }
+}

+ 45 - 0
Future/future-framework/src/main/java/com/future/framework/datasource/DynamicDataSourceContextHolder.java

@@ -0,0 +1,45 @@
+package com.future.framework.datasource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 数据源切换处理
+ * 
+ * @author future
+ */
+public class DynamicDataSourceContextHolder
+{
+    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
+
+    /**
+     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
+     *  所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
+     */
+    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
+
+    /**
+     * 设置数据源的变量
+     */
+    public static void setDataSourceType(String dsType)
+    {
+        log.info("切换到{}数据源", dsType);
+        CONTEXT_HOLDER.set(dsType);
+    }
+
+    /**
+     * 获得数据源的变量
+     */
+    public static String getDataSourceType()
+    {
+        return CONTEXT_HOLDER.get();
+    }
+
+    /**
+     * 清空数据源变量
+     */
+    public static void clearDataSourceType()
+    {
+        CONTEXT_HOLDER.remove();
+    }
+}

+ 55 - 0
Future/future-framework/src/main/java/com/future/framework/interceptor/RepeatSubmitInterceptor.java

@@ -0,0 +1,55 @@
+package com.future.framework.interceptor;
+
+import java.lang.reflect.Method;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+import com.alibaba.fastjson.JSONObject;
+import com.future.common.annotation.RepeatSubmit;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.utils.ServletUtils;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author future
+ */
+@Component
+public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
+{
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
+    {
+        if (handler instanceof HandlerMethod)
+        {
+            HandlerMethod handlerMethod = (HandlerMethod) handler;
+            Method method = handlerMethod.getMethod();
+            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
+            if (annotation != null)
+            {
+                if (this.isRepeatSubmit(request))
+                {
+                    AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试");
+                    ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
+                    return false;
+                }
+            }
+            return true;
+        }
+        else
+        {
+            return super.preHandle(request, response, handler);
+        }
+    }
+
+    /**
+     * 验证是否重复提交由子类实现具体的防重复提交的规则
+     *
+     * @param request
+     * @return
+     * @throws Exception
+     */
+    public abstract boolean isRepeatSubmit(HttpServletRequest request);
+}

+ 125 - 0
Future/future-framework/src/main/java/com/future/framework/interceptor/impl/SameUrlDataInterceptor.java

@@ -0,0 +1,125 @@
+package com.future.framework.interceptor.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import com.alibaba.fastjson.JSONObject;
+import com.future.common.constant.Constants;
+import com.future.common.core.redis.RedisCache;
+import com.future.common.filter.RepeatedlyRequestWrapper;
+import com.future.common.utils.StringUtils;
+import com.future.common.utils.http.HttpHelper;
+import com.future.framework.interceptor.RepeatSubmitInterceptor;
+
+/**
+ * 判断请求url和数据是否和上一次相同,
+ * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
+ * 
+ * @author future
+ */
+@Component
+public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
+{
+    public final String REPEAT_PARAMS = "repeatParams";
+
+    public final String REPEAT_TIME = "repeatTime";
+
+    // 令牌自定义标识
+    @Value("${token.header}")
+    private String header;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 间隔时间,单位:秒 默认10秒
+     * 
+     * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
+     */
+    private int intervalTime = 10;
+
+    public void setIntervalTime(int intervalTime)
+    {
+        this.intervalTime = intervalTime;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean isRepeatSubmit(HttpServletRequest request)
+    {
+        String nowParams = "";
+        if (request instanceof RepeatedlyRequestWrapper)
+        {
+            RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+            nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+        }
+
+        // body参数为空,获取Parameter的数据
+        if (StringUtils.isEmpty(nowParams))
+        {
+            nowParams = JSONObject.toJSONString(request.getParameterMap());
+        }
+        Map<String, Object> nowDataMap = new HashMap<String, Object>();
+        nowDataMap.put(REPEAT_PARAMS, nowParams);
+        nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
+
+        // 请求地址(作为存放cache的key值)
+        String url = request.getRequestURI();
+
+        // 唯一值(没有消息头则使用请求地址)
+        String submitKey = request.getHeader(header);
+        if (StringUtils.isEmpty(submitKey))
+        {
+            submitKey = url;
+        }
+
+        // 唯一标识(指定key + 消息头)
+        String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey;
+
+        Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
+        if (sessionObj != null)
+        {
+            Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
+            if (sessionMap.containsKey(url))
+            {
+                Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
+                if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap))
+                {
+                    return true;
+                }
+            }
+        }
+        Map<String, Object> cacheMap = new HashMap<String, Object>();
+        cacheMap.put(url, nowDataMap);
+        redisCache.setCacheObject(cacheRepeatKey, cacheMap, intervalTime, TimeUnit.SECONDS);
+        return false;
+    }
+
+    /**
+     * 判断参数是否相同
+     */
+    private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+    {
+        String nowParams = (String) nowMap.get(REPEAT_PARAMS);
+        String preParams = (String) preMap.get(REPEAT_PARAMS);
+        return nowParams.equals(preParams);
+    }
+
+    /**
+     * 判断两次间隔时间
+     */
+    private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+    {
+        long time1 = (Long) nowMap.get(REPEAT_TIME);
+        long time2 = (Long) preMap.get(REPEAT_TIME);
+        if ((time1 - time2) < (this.intervalTime * 1000))
+        {
+            return true;
+        }
+        return false;
+    }
+}

+ 55 - 0
Future/future-framework/src/main/java/com/future/framework/manager/AsyncManager.java

@@ -0,0 +1,55 @@
+package com.future.framework.manager;
+
+import java.util.TimerTask;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import com.future.common.utils.Threads;
+import com.future.common.utils.spring.SpringUtils;
+
+/**
+ * 异步任务管理器
+ * 
+ * @author future
+ */
+public class AsyncManager
+{
+    /**
+     * 操作延迟10毫秒
+     */
+    private final int OPERATE_DELAY_TIME = 10;
+
+    /**
+     * 异步操作任务调度线程池
+     */
+    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
+
+    /**
+     * 单例模式
+     */
+    private AsyncManager(){}
+
+    private static AsyncManager me = new AsyncManager();
+
+    public static AsyncManager me()
+    {
+        return me;
+    }
+
+    /**
+     * 执行任务
+     * 
+     * @param task 任务
+     */
+    public void execute(TimerTask task)
+    {
+        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 停止任务线程池
+     */
+    public void shutdown()
+    {
+        Threads.shutdownAndAwaitTermination(executor);
+    }
+}

+ 39 - 0
Future/future-framework/src/main/java/com/future/framework/manager/ShutdownManager.java

@@ -0,0 +1,39 @@
+package com.future.framework.manager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import javax.annotation.PreDestroy;
+
+/**
+ * 确保应用退出时能关闭后台线程
+ *
+ * @author future
+ */
+@Component
+public class ShutdownManager
+{
+    private static final Logger logger = LoggerFactory.getLogger("sys-user");
+
+    @PreDestroy
+    public void destroy()
+    {
+        shutdownAsyncManager();
+    }
+
+    /**
+     * 停止异步执行任务
+     */
+    private void shutdownAsyncManager()
+    {
+        try
+        {
+            logger.info("====关闭后台任务任务线程池====");
+            AsyncManager.me().shutdown();
+        }
+        catch (Exception e)
+        {
+            logger.error(e.getMessage(), e);
+        }
+    }
+}

+ 101 - 0
Future/future-framework/src/main/java/com/future/framework/manager/factory/AsyncFactory.java

@@ -0,0 +1,101 @@
+package com.future.framework.manager.factory;
+
+import java.util.TimerTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.future.common.constant.Constants;
+import com.future.common.utils.LogUtils;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.ip.AddressUtils;
+import com.future.common.utils.ip.IpUtils;
+import com.future.common.utils.spring.SpringUtils;
+import com.future.system.domain.SysLogininfor;
+import com.future.system.domain.SysOperLog;
+import com.future.system.service.ISysLogininforService;
+import com.future.system.service.ISysOperLogService;
+import eu.bitwalker.useragentutils.UserAgent;
+
+/**
+ * 异步工厂(产生任务用)
+ * 
+ * @author future
+ */
+public class AsyncFactory
+{
+    private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
+
+    /**
+     * 记录登录信息
+     * 
+     * @param username 用户名
+     * @param status 状态
+     * @param message 消息
+     * @param args 列表
+     * @return 任务task
+     */
+    public static TimerTask recordLogininfor(final String username, final String status, final String message,
+            final Object... args)
+    {
+        final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
+        final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
+        return new TimerTask()
+        {
+            @Override
+            public void run()
+            {
+                String address = AddressUtils.getRealAddressByIP(ip);
+                StringBuilder s = new StringBuilder();
+                s.append(LogUtils.getBlock(ip));
+                s.append(address);
+                s.append(LogUtils.getBlock(username));
+                s.append(LogUtils.getBlock(status));
+                s.append(LogUtils.getBlock(message));
+                // 打印信息到日志
+                sys_user_logger.info(s.toString(), args);
+                // 获取客户端操作系统
+                String os = userAgent.getOperatingSystem().getName();
+                // 获取客户端浏览器
+                String browser = userAgent.getBrowser().getName();
+                // 封装对象
+                SysLogininfor logininfor = new SysLogininfor();
+                logininfor.setUserName(username);
+                logininfor.setIpaddr(ip);
+                logininfor.setLoginLocation(address);
+                logininfor.setBrowser(browser);
+                logininfor.setOs(os);
+                logininfor.setMsg(message);
+                // 日志状态
+                if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status))
+                {
+                    logininfor.setStatus(Constants.SUCCESS);
+                }
+                else if (Constants.LOGIN_FAIL.equals(status))
+                {
+                    logininfor.setStatus(Constants.FAIL);
+                }
+                // 插入数据
+                SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
+            }
+        };
+    }
+
+    /**
+     * 操作日志记录
+     * 
+     * @param operLog 操作日志信息
+     * @return 任务task
+     */
+    public static TimerTask recordOper(final SysOperLog operLog)
+    {
+        return new TimerTask()
+        {
+            @Override
+            public void run()
+            {
+                // 远程查询操作地点
+                operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
+                SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
+            }
+        };
+    }
+}

+ 44 - 0
Future/future-framework/src/main/java/com/future/framework/security/filter/JwtAuthenticationTokenFilter.java

@@ -0,0 +1,44 @@
+package com.future.framework.security.filter;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+import com.future.system.domain.model.LoginUser;
+import com.future.system.utils.SecurityUtils;
+import com.future.common.utils.StringUtils;
+import com.future.framework.web.service.TokenService;
+
+/**
+ * token过滤器 验证token有效性
+ * 
+ * @author future
+ */
+@Component
+public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
+{
+    @Autowired
+    private TokenService tokenService;
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
+            throws ServletException, IOException
+    {
+        LoginUser loginUser = tokenService.getLoginUser(request);
+        if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
+        {
+            tokenService.verifyToken(loginUser);
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
+            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        }
+        chain.doFilter(request, response);
+    }
+}

+ 34 - 0
Future/future-framework/src/main/java/com/future/framework/security/handle/AuthenticationEntryPointImpl.java

@@ -0,0 +1,34 @@
+package com.future.framework.security.handle;
+
+import java.io.IOException;
+import java.io.Serializable;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+import com.alibaba.fastjson.JSON;
+import com.future.common.constant.HttpStatus;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.StringUtils;
+
+/**
+ * 认证失败处理类 返回未授权
+ * 
+ * @author future
+ */
+@Component
+public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable
+{
+    private static final long serialVersionUID = -8970718410437077606L;
+
+    @Override
+    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
+            throws IOException
+    {
+        int code = HttpStatus.UNAUTHORIZED;
+        String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
+        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
+    }
+}

+ 53 - 0
Future/future-framework/src/main/java/com/future/framework/security/handle/LogoutSuccessHandlerImpl.java

@@ -0,0 +1,53 @@
+package com.future.framework.security.handle;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
+import com.alibaba.fastjson.JSON;
+import com.future.common.constant.Constants;
+import com.future.common.constant.HttpStatus;
+import com.future.common.core.domain.AjaxResult;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.StringUtils;
+import com.future.framework.manager.AsyncManager;
+import com.future.framework.manager.factory.AsyncFactory;
+import com.future.framework.web.service.TokenService;
+
+/**
+ * 自定义退出处理类 返回成功
+ * 
+ * @author future
+ */
+@Configuration
+public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
+{
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 退出处理
+     * 
+     * @return
+     */
+    @Override
+    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
+            throws IOException, ServletException
+    {
+        LoginUser loginUser = tokenService.getLoginUser(request);
+        if (StringUtils.isNotNull(loginUser))
+        {
+            String userName = loginUser.getUsername();
+            // 删除用户缓存记录
+            tokenService.delLoginUser(loginUser.getToken());
+            // 记录用户退出日志
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
+        }
+        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.SUCCESS, "退出成功")));
+    }
+}

+ 240 - 0
Future/future-framework/src/main/java/com/future/framework/web/domain/Server.java

@@ -0,0 +1,240 @@
+package com.future.framework.web.domain;
+
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import com.future.common.utils.Arith;
+import com.future.common.utils.ip.IpUtils;
+import com.future.framework.web.domain.server.Cpu;
+import com.future.framework.web.domain.server.Jvm;
+import com.future.framework.web.domain.server.Mem;
+import com.future.framework.web.domain.server.Sys;
+import com.future.framework.web.domain.server.SysFile;
+import oshi.SystemInfo;
+import oshi.hardware.CentralProcessor;
+import oshi.hardware.CentralProcessor.TickType;
+import oshi.hardware.GlobalMemory;
+import oshi.hardware.HardwareAbstractionLayer;
+import oshi.software.os.FileSystem;
+import oshi.software.os.OSFileStore;
+import oshi.software.os.OperatingSystem;
+import oshi.util.Util;
+
+/**
+ * 服务器相关信息
+ * 
+ * @author future
+ */
+public class Server
+{
+    private static final int OSHI_WAIT_SECOND = 1000;
+    
+    /**
+     * CPU相关信息
+     */
+    private Cpu cpu = new Cpu();
+
+    /**
+     * 內存相关信息
+     */
+    private Mem mem = new Mem();
+
+    /**
+     * JVM相关信息
+     */
+    private Jvm jvm = new Jvm();
+
+    /**
+     * 服务器相关信息
+     */
+    private Sys sys = new Sys();
+
+    /**
+     * 磁盘相关信息
+     */
+    private List<SysFile> sysFiles = new LinkedList<SysFile>();
+
+    public Cpu getCpu()
+    {
+        return cpu;
+    }
+
+    public void setCpu(Cpu cpu)
+    {
+        this.cpu = cpu;
+    }
+
+    public Mem getMem()
+    {
+        return mem;
+    }
+
+    public void setMem(Mem mem)
+    {
+        this.mem = mem;
+    }
+
+    public Jvm getJvm()
+    {
+        return jvm;
+    }
+
+    public void setJvm(Jvm jvm)
+    {
+        this.jvm = jvm;
+    }
+
+    public Sys getSys()
+    {
+        return sys;
+    }
+
+    public void setSys(Sys sys)
+    {
+        this.sys = sys;
+    }
+
+    public List<SysFile> getSysFiles()
+    {
+        return sysFiles;
+    }
+
+    public void setSysFiles(List<SysFile> sysFiles)
+    {
+        this.sysFiles = sysFiles;
+    }
+
+    public void copyTo() throws Exception
+    {
+        SystemInfo si = new SystemInfo();
+        HardwareAbstractionLayer hal = si.getHardware();
+
+        setCpuInfo(hal.getProcessor());
+
+        setMemInfo(hal.getMemory());
+
+        setSysInfo();
+
+        setJvmInfo();
+
+        setSysFiles(si.getOperatingSystem());
+    }
+
+    /**
+     * 设置CPU信息
+     */
+    private void setCpuInfo(CentralProcessor processor)
+    {
+        // CPU信息
+        long[] prevTicks = processor.getSystemCpuLoadTicks();
+        Util.sleep(OSHI_WAIT_SECOND);
+        long[] ticks = processor.getSystemCpuLoadTicks();
+        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
+        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
+        long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
+        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
+        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
+        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
+        long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
+        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
+        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
+        cpu.setCpuNum(processor.getLogicalProcessorCount());
+        cpu.setTotal(totalCpu);
+        cpu.setSys(cSys);
+        cpu.setUsed(user);
+        cpu.setWait(iowait);
+        cpu.setFree(idle);
+    }
+
+    /**
+     * 设置内存信息
+     */
+    private void setMemInfo(GlobalMemory memory)
+    {
+        mem.setTotal(memory.getTotal());
+        mem.setUsed(memory.getTotal() - memory.getAvailable());
+        mem.setFree(memory.getAvailable());
+    }
+
+    /**
+     * 设置服务器信息
+     */
+    private void setSysInfo()
+    {
+        Properties props = System.getProperties();
+        sys.setComputerName(IpUtils.getHostName());
+        sys.setComputerIp(IpUtils.getHostIp());
+        sys.setOsName(props.getProperty("os.name"));
+        sys.setOsArch(props.getProperty("os.arch"));
+        sys.setUserDir(props.getProperty("user.dir"));
+    }
+
+    /**
+     * 设置Java虚拟机
+     */
+    private void setJvmInfo() throws UnknownHostException
+    {
+        Properties props = System.getProperties();
+        jvm.setTotal(Runtime.getRuntime().totalMemory());
+        jvm.setMax(Runtime.getRuntime().maxMemory());
+        jvm.setFree(Runtime.getRuntime().freeMemory());
+        jvm.setVersion(props.getProperty("java.version"));
+        jvm.setHome(props.getProperty("java.home"));
+    }
+
+    /**
+     * 设置磁盘信息
+     */
+    private void setSysFiles(OperatingSystem os)
+    {
+        FileSystem fileSystem = os.getFileSystem();
+        List<OSFileStore> fsArray = fileSystem.getFileStores();
+        for (OSFileStore fs : fsArray)
+        {
+            long free = fs.getUsableSpace();
+            long total = fs.getTotalSpace();
+            long used = total - free;
+            SysFile sysFile = new SysFile();
+            sysFile.setDirName(fs.getMount());
+            sysFile.setSysTypeName(fs.getType());
+            sysFile.setTypeName(fs.getName());
+            sysFile.setTotal(convertFileSize(total));
+            sysFile.setFree(convertFileSize(free));
+            sysFile.setUsed(convertFileSize(used));
+            sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100));
+            sysFiles.add(sysFile);
+        }
+    }
+
+    /**
+     * 字节转换
+     * 
+     * @param size 字节大小
+     * @return 转换后值
+     */
+    public String convertFileSize(long size)
+    {
+        long kb = 1024;
+        long mb = kb * 1024;
+        long gb = mb * 1024;
+        if (size >= gb)
+        {
+            return String.format("%.1f GB", (float) size / gb);
+        }
+        else if (size >= mb)
+        {
+            float f = (float) size / mb;
+            return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
+        }
+        else if (size >= kb)
+        {
+            float f = (float) size / kb;
+            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
+        }
+        else
+        {
+            return String.format("%d B", size);
+        }
+    }
+}

+ 101 - 0
Future/future-framework/src/main/java/com/future/framework/web/domain/server/Cpu.java

@@ -0,0 +1,101 @@
+package com.future.framework.web.domain.server;
+
+import com.future.common.utils.Arith;
+
+/**
+ * CPU相关信息
+ * 
+ * @author future
+ */
+public class Cpu
+{
+    /**
+     * 核心数
+     */
+    private int cpuNum;
+
+    /**
+     * CPU总的使用率
+     */
+    private double total;
+
+    /**
+     * CPU系统使用率
+     */
+    private double sys;
+
+    /**
+     * CPU用户使用率
+     */
+    private double used;
+
+    /**
+     * CPU当前等待率
+     */
+    private double wait;
+
+    /**
+     * CPU当前空闲率
+     */
+    private double free;
+
+    public int getCpuNum()
+    {
+        return cpuNum;
+    }
+
+    public void setCpuNum(int cpuNum)
+    {
+        this.cpuNum = cpuNum;
+    }
+
+    public double getTotal()
+    {
+        return Arith.round(Arith.mul(total, 100), 2);
+    }
+
+    public void setTotal(double total)
+    {
+        this.total = total;
+    }
+
+    public double getSys()
+    {
+        return Arith.round(Arith.mul(sys / total, 100), 2);
+    }
+
+    public void setSys(double sys)
+    {
+        this.sys = sys;
+    }
+
+    public double getUsed()
+    {
+        return Arith.round(Arith.mul(used / total, 100), 2);
+    }
+
+    public void setUsed(double used)
+    {
+        this.used = used;
+    }
+
+    public double getWait()
+    {
+        return Arith.round(Arith.mul(wait / total, 100), 2);
+    }
+
+    public void setWait(double wait)
+    {
+        this.wait = wait;
+    }
+
+    public double getFree()
+    {
+        return Arith.round(Arith.mul(free / total, 100), 2);
+    }
+
+    public void setFree(double free)
+    {
+        this.free = free;
+    }
+}

+ 122 - 0
Future/future-framework/src/main/java/com/future/framework/web/domain/server/Jvm.java

@@ -0,0 +1,122 @@
+package com.future.framework.web.domain.server;
+
+import java.lang.management.ManagementFactory;
+import com.future.common.utils.Arith;
+import com.future.common.utils.DateUtils;
+
+/**
+ * JVM相关信息
+ * 
+ * @author future
+ */
+public class Jvm
+{
+    /**
+     * 当前JVM占用的内存总数(M)
+     */
+    private double total;
+
+    /**
+     * JVM最大可用内存总数(M)
+     */
+    private double max;
+
+    /**
+     * JVM空闲内存(M)
+     */
+    private double free;
+
+    /**
+     * JDK版本
+     */
+    private String version;
+
+    /**
+     * JDK路径
+     */
+    private String home;
+
+    public double getTotal()
+    {
+        return Arith.div(total, (1024 * 1024), 2);
+    }
+
+    public void setTotal(double total)
+    {
+        this.total = total;
+    }
+
+    public double getMax()
+    {
+        return Arith.div(max, (1024 * 1024), 2);
+    }
+
+    public void setMax(double max)
+    {
+        this.max = max;
+    }
+
+    public double getFree()
+    {
+        return Arith.div(free, (1024 * 1024), 2);
+    }
+
+    public void setFree(double free)
+    {
+        this.free = free;
+    }
+
+    public double getUsed()
+    {
+        return Arith.div(total - free, (1024 * 1024), 2);
+    }
+
+    public double getUsage()
+    {
+        return Arith.mul(Arith.div(total - free, total, 4), 100);
+    }
+
+    /**
+     * 获取JDK名称
+     */
+    public String getName()
+    {
+        return ManagementFactory.getRuntimeMXBean().getVmName();
+    }
+
+    public String getVersion()
+    {
+        return version;
+    }
+
+    public void setVersion(String version)
+    {
+        this.version = version;
+    }
+
+    public String getHome()
+    {
+        return home;
+    }
+
+    public void setHome(String home)
+    {
+        this.home = home;
+    }
+
+    /**
+     * JDK启动时间
+     */
+    public String getStartTime()
+    {
+        return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate());
+    }
+
+    /**
+     * JDK运行时间
+     */
+    public String getRunTime()
+    {
+        return DateUtils.getDatePoor(DateUtils.getNowDate(), DateUtils.getServerStartDate());
+    }
+}

+ 61 - 0
Future/future-framework/src/main/java/com/future/framework/web/domain/server/Mem.java

@@ -0,0 +1,61 @@
+package com.future.framework.web.domain.server;
+
+import com.future.common.utils.Arith;
+
+/**
+ * 內存相关信息
+ * 
+ * @author future
+ */
+public class Mem
+{
+    /**
+     * 内存总量
+     */
+    private double total;
+
+    /**
+     * 已用内存
+     */
+    private double used;
+
+    /**
+     * 剩余内存
+     */
+    private double free;
+
+    public double getTotal()
+    {
+        return Arith.div(total, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setTotal(long total)
+    {
+        this.total = total;
+    }
+
+    public double getUsed()
+    {
+        return Arith.div(used, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setUsed(long used)
+    {
+        this.used = used;
+    }
+
+    public double getFree()
+    {
+        return Arith.div(free, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setFree(long free)
+    {
+        this.free = free;
+    }
+
+    public double getUsage()
+    {
+        return Arith.mul(Arith.div(used, total, 4), 100);
+    }
+}

+ 84 - 0
Future/future-framework/src/main/java/com/future/framework/web/domain/server/Sys.java

@@ -0,0 +1,84 @@
+package com.future.framework.web.domain.server;
+
+/**
+ * 系统相关信息
+ * 
+ * @author future
+ */
+public class Sys
+{
+    /**
+     * 服务器名称
+     */
+    private String computerName;
+
+    /**
+     * 服务器Ip
+     */
+    private String computerIp;
+
+    /**
+     * 项目路径
+     */
+    private String userDir;
+
+    /**
+     * 操作系统
+     */
+    private String osName;
+
+    /**
+     * 系统架构
+     */
+    private String osArch;
+
+    public String getComputerName()
+    {
+        return computerName;
+    }
+
+    public void setComputerName(String computerName)
+    {
+        this.computerName = computerName;
+    }
+
+    public String getComputerIp()
+    {
+        return computerIp;
+    }
+
+    public void setComputerIp(String computerIp)
+    {
+        this.computerIp = computerIp;
+    }
+
+    public String getUserDir()
+    {
+        return userDir;
+    }
+
+    public void setUserDir(String userDir)
+    {
+        this.userDir = userDir;
+    }
+
+    public String getOsName()
+    {
+        return osName;
+    }
+
+    public void setOsName(String osName)
+    {
+        this.osName = osName;
+    }
+
+    public String getOsArch()
+    {
+        return osArch;
+    }
+
+    public void setOsArch(String osArch)
+    {
+        this.osArch = osArch;
+    }
+}

+ 114 - 0
Future/future-framework/src/main/java/com/future/framework/web/domain/server/SysFile.java

@@ -0,0 +1,114 @@
+package com.future.framework.web.domain.server;
+
+/**
+ * 系统文件相关信息
+ * 
+ * @author future
+ */
+public class SysFile
+{
+    /**
+     * 盘符路径
+     */
+    private String dirName;
+
+    /**
+     * 盘符类型
+     */
+    private String sysTypeName;
+
+    /**
+     * 文件类型
+     */
+    private String typeName;
+
+    /**
+     * 总大小
+     */
+    private String total;
+
+    /**
+     * 剩余大小
+     */
+    private String free;
+
+    /**
+     * 已经使用量
+     */
+    private String used;
+
+    /**
+     * 资源的使用率
+     */
+    private double usage;
+
+    public String getDirName()
+    {
+        return dirName;
+    }
+
+    public void setDirName(String dirName)
+    {
+        this.dirName = dirName;
+    }
+
+    public String getSysTypeName()
+    {
+        return sysTypeName;
+    }
+
+    public void setSysTypeName(String sysTypeName)
+    {
+        this.sysTypeName = sysTypeName;
+    }
+
+    public String getTypeName()
+    {
+        return typeName;
+    }
+
+    public void setTypeName(String typeName)
+    {
+        this.typeName = typeName;
+    }
+
+    public String getTotal()
+    {
+        return total;
+    }
+
+    public void setTotal(String total)
+    {
+        this.total = total;
+    }
+
+    public String getFree()
+    {
+        return free;
+    }
+
+    public void setFree(String free)
+    {
+        this.free = free;
+    }
+
+    public String getUsed()
+    {
+        return used;
+    }
+
+    public void setUsed(String used)
+    {
+        this.used = used;
+    }
+
+    public double getUsage()
+    {
+        return usage;
+    }
+
+    public void setUsage(double usage)
+    {
+        this.usage = usage;
+    }
+}

+ 126 - 0
Future/future-framework/src/main/java/com/future/framework/web/exception/GlobalExceptionHandler.java

@@ -0,0 +1,126 @@
+package com.future.framework.web.exception;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.authentication.AccountExpiredException;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.NoHandlerFoundException;
+import com.future.common.constant.HttpStatus;
+import com.future.common.core.domain.AjaxResult;
+import com.future.common.exception.BaseException;
+import com.future.common.exception.CustomException;
+import com.future.common.exception.DemoModeException;
+import com.future.common.utils.StringUtils;
+
+import javax.validation.ConstraintViolationException;
+
+/**
+ * 全局异常处理器
+ * 
+ * @author future
+ */
+@RestControllerAdvice
+public class GlobalExceptionHandler
+{
+    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+    /**
+     * 基础异常
+     */
+    @ExceptionHandler(BaseException.class)
+    public AjaxResult baseException(BaseException e)
+    {
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 业务异常
+     */
+    @ExceptionHandler(CustomException.class)
+    public AjaxResult businessException(CustomException e)
+    {
+        if (StringUtils.isNull(e.getCode()))
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+        return AjaxResult.error(e.getCode(), e.getMessage());
+    }
+
+    @ExceptionHandler(NoHandlerFoundException.class)
+    public AjaxResult handlerNoFoundException(Exception e)
+    {
+        log.error(e.getMessage(), e);
+        return AjaxResult.error(HttpStatus.NOT_FOUND, "路径不存在,请检查路径是否正确");
+    }
+
+    @ExceptionHandler(AccessDeniedException.class)
+    public AjaxResult handleAuthorizationException(AccessDeniedException e)
+    {
+        log.error(e.getMessage());
+        return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权");
+    }
+
+    @ExceptionHandler(AccountExpiredException.class)
+    public AjaxResult handleAccountExpiredException(AccountExpiredException e)
+    {
+        log.error(e.getMessage(), e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    @ExceptionHandler(UsernameNotFoundException.class)
+    public AjaxResult handleUsernameNotFoundException(UsernameNotFoundException e)
+    {
+        log.error(e.getMessage(), e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    @ExceptionHandler(Exception.class)
+    public AjaxResult handleException(Exception e)
+    {
+        log.error(e.getMessage(), e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    @ExceptionHandler(ConstraintViolationException.class)
+    public AjaxResult violationException(ConstraintViolationException e)
+    {
+        //log.error(e.getMessage(), e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(BindException.class)
+    public AjaxResult validatedBindException(BindException e)
+    {
+        log.error(e.getMessage(), e);
+        String message = e.getAllErrors().get(0).getDefaultMessage();
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public Object validExceptionHandler(MethodArgumentNotValidException e)
+    {
+        log.error(e.getMessage(), e);
+        String message = e.getBindingResult().getFieldError().getDefaultMessage();
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 演示模式异常
+     */
+    @ExceptionHandler(DemoModeException.class)
+    public AjaxResult demoModeException(DemoModeException e)
+    {
+        return AjaxResult.error("演示模式,不允许操作");
+    }
+}

+ 170 - 0
Future/future-framework/src/main/java/com/future/framework/web/service/PermissionService.java

@@ -0,0 +1,170 @@
+package com.future.framework.web.service;
+
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import com.future.system.domain.entity.SysRole;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.StringUtils;
+
+/**
+ * RuoYi首创 自定义权限实现,ss取自SpringSecurity首字母
+ * 
+ * @author future
+ */
+@Service("ss")
+public class PermissionService
+{
+    /** 所有权限标识 */
+    private static final String ALL_PERMISSION = "*:*:*";
+
+    /** 管理员角色权限标识 */
+    private static final String SUPER_ADMIN = "admin";
+
+    private static final String ROLE_DELIMETER = ",";
+
+    private static final String PERMISSION_DELIMETER = ",";
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 验证用户是否具备某权限
+     * 
+     * @param permission 权限字符串
+     * @return 用户是否具备某权限
+     */
+    public boolean hasPermi(String permission)
+    {
+        if (StringUtils.isEmpty(permission))
+        {
+            return false;
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
+        {
+            return false;
+        }
+        return hasPermissions(loginUser.getPermissions(), permission);
+    }
+
+    /**
+     * 验证用户是否不具备某权限,与 hasPermi逻辑相反
+     *
+     * @param permission 权限字符串
+     * @return 用户是否不具备某权限
+     */
+    public boolean lacksPermi(String permission)
+    {
+        return hasPermi(permission) != true;
+    }
+
+    /**
+     * 验证用户是否具有以下任意一个权限
+     *
+     * @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表
+     * @return 用户是否具有以下任意一个权限
+     */
+    public boolean hasAnyPermi(String permissions)
+    {
+        if (StringUtils.isEmpty(permissions))
+        {
+            return false;
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
+        {
+            return false;
+        }
+        Set<String> authorities = loginUser.getPermissions();
+        for (String permission : permissions.split(PERMISSION_DELIMETER))
+        {
+            if (permission != null && hasPermissions(authorities, permission))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断用户是否拥有某个角色
+     * 
+     * @param role 角色字符串
+     * @return 用户是否具备某角色
+     */
+    public boolean hasRole(String role)
+    {
+        if (StringUtils.isEmpty(role))
+        {
+            return false;
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
+        {
+            return false;
+        }
+        for (SysRole sysRole : loginUser.getUser().getRoles())
+        {
+            String roleKey = sysRole.getRoleKey();
+            if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role)))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 验证用户是否不具备某角色,与 isRole逻辑相反。
+     *
+     * @param role 角色名称
+     * @return 用户是否不具备某角色
+     */
+    public boolean lacksRole(String role)
+    {
+        return hasRole(role) != true;
+    }
+
+    /**
+     * 验证用户是否具有以下任意一个角色
+     *
+     * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
+     * @return 用户是否具有以下任意一个角色
+     */
+    public boolean hasAnyRoles(String roles)
+    {
+        if (StringUtils.isEmpty(roles))
+        {
+            return false;
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
+        {
+            return false;
+        }
+        for (String role : roles.split(ROLE_DELIMETER))
+        {
+            if (hasRole(role))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断是否包含权限
+     * 
+     * @param permissions 权限列表
+     * @param permission 权限字符串
+     * @return 用户是否具备某权限
+     */
+    private boolean hasPermissions(Set<String> permissions, String permission)
+    {
+        return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
+    }
+}

+ 92 - 0
Future/future-framework/src/main/java/com/future/framework/web/service/SysLoginService.java

@@ -0,0 +1,92 @@
+package com.future.framework.web.service;
+
+import javax.annotation.Resource;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.stereotype.Component;
+import com.future.common.constant.Constants;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.core.redis.RedisCache;
+import com.future.common.exception.CustomException;
+import com.future.common.exception.user.CaptchaException;
+import com.future.common.exception.user.CaptchaExpireException;
+import com.future.common.exception.user.UserPasswordNotMatchException;
+import com.future.common.utils.MessageUtils;
+import com.future.framework.manager.AsyncManager;
+import com.future.framework.manager.factory.AsyncFactory;
+
+/**
+ * 登录校验方法
+ * 
+ * @author future
+ */
+@Component
+@Slf4j
+public class SysLoginService
+{
+    @Autowired
+    private TokenService tokenService;
+
+    @Resource
+    private AuthenticationManager authenticationManager;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 登录验证
+     * 
+     * @param username 用户名
+     * @param password 密码
+     * @param code 验证码
+     * @param uuid 唯一标识
+     * @return 结果
+     */
+    public String login(String username, String password, String code, String uuid)
+    {
+        log.info("吃饭都吃什么饭呢?{}",username);
+        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
+        String captcha = redisCache.getCacheObject(verifyKey);
+        redisCache.deleteObject(verifyKey);
+        if (captcha == null)
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
+            throw new CaptchaExpireException();
+        }
+        if (!code.equalsIgnoreCase(captcha))
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
+            throw new CaptchaException();
+        }
+        // 用户验证
+        Authentication authentication = null;
+        try
+        {
+            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
+            authentication = authenticationManager
+                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
+        }
+        catch (Exception e)
+        {
+            if (e instanceof BadCredentialsException)
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+                throw new UserPasswordNotMatchException();
+            }
+            else
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
+                throw new CustomException(e.getMessage());
+            }
+        }
+        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
+        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
+        // 生成token
+        return tokenService.createToken(loginUser);
+    }
+}

+ 68 - 0
Future/future-framework/src/main/java/com/future/framework/web/service/SysPermissionService.java

@@ -0,0 +1,68 @@
+package com.future.framework.web.service;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.future.system.service.ISysMenuService;
+import com.future.system.service.ISysRoleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import com.future.system.domain.entity.SysUser;
+
+
+/**
+ * 用户权限处理
+ * 
+ * @author future
+ */
+@Component
+public class SysPermissionService
+{
+    @Autowired
+    private ISysRoleService roleService;
+
+    @Autowired
+    private ISysMenuService menuService;
+
+    /**
+     * 获取角色数据权限
+     * 
+     * @param user 用户信息
+     * @return 角色权限信息
+     */
+    public Set<String> getRolePermission(SysUser user)
+    {
+        Set<String> roles = new HashSet<String>();
+        // 管理员拥有所有权限
+        if (user.isAdmin())
+        {
+            roles.add("admin");
+        }
+        else
+        {
+            roles.addAll(roleService.selectRolePermissionByUserId(user.getUserId()));
+        }
+        return roles;
+    }
+
+    /**
+     * 获取菜单数据权限
+     * 
+     * @param user 用户信息
+     * @return 菜单权限信息
+     */
+    public Set<String> getMenuPermission(SysUser user)
+    {
+        Set<String> perms = new HashSet<String>();
+        // 管理员拥有所有权限
+        if (user.isAdmin())
+        {
+            perms.add("*:*:*");
+        }
+        else
+        {
+            perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));
+        }
+        return perms;
+    }
+}

+ 220 - 0
Future/future-framework/src/main/java/com/future/framework/web/service/TokenService.java

@@ -0,0 +1,220 @@
+package com.future.framework.web.service;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import javax.servlet.http.HttpServletRequest;
+
+import com.future.system.domain.model.LoginUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import com.future.common.constant.Constants;
+import com.future.common.core.redis.RedisCache;
+import com.future.common.utils.ServletUtils;
+import com.future.common.utils.StringUtils;
+import com.future.common.utils.ip.AddressUtils;
+import com.future.common.utils.ip.IpUtils;
+import com.future.common.utils.uuid.IdUtils;
+import eu.bitwalker.useragentutils.UserAgent;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+
+/**
+ * token验证处理
+ *
+ * @author future
+ */
+@Component
+public class TokenService
+{
+    // 令牌自定义标识
+    @Value("${token.header}")
+    private String header;
+
+    // 令牌秘钥
+    @Value("${token.secret}")
+    private String secret;
+
+    // 令牌有效期(默认30分钟)
+    @Value("${token.expireTime}")
+    private int expireTime;
+
+    protected static final long MILLIS_SECOND = 1000;
+
+    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
+
+    private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 获取用户身份信息
+     *
+     * @return 用户信息
+     */
+    public LoginUser getLoginUser(HttpServletRequest request)
+    {
+        // 获取请求携带的令牌
+        String token = getToken(request);
+        if (StringUtils.isNotEmpty(token))
+        {
+            Claims claims = parseToken(token);
+            // 解析对应的权限以及用户信息
+            String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
+            String userKey = getTokenKey(uuid);
+            LoginUser user = redisCache.getCacheObject(userKey);
+            return user;
+        }
+        return null;
+    }
+
+    /**
+     * 设置用户身份信息
+     */
+    public void setLoginUser(LoginUser loginUser)
+    {
+        if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
+        {
+            refreshToken(loginUser);
+        }
+    }
+
+    /**
+     * 删除用户身份信息
+     */
+    public void delLoginUser(String token)
+    {
+        if (StringUtils.isNotEmpty(token))
+        {
+            String userKey = getTokenKey(token);
+            redisCache.deleteObject(userKey);
+        }
+    }
+
+    /**
+     * 创建令牌
+     *
+     * @param loginUser 用户信息
+     * @return 令牌
+     */
+    public String createToken(LoginUser loginUser)
+    {
+        String token = IdUtils.fastUUID();
+        loginUser.setToken(token);
+        setUserAgent(loginUser);
+        refreshToken(loginUser);
+
+        Map<String, Object> claims = new HashMap<>();
+        claims.put(Constants.LOGIN_USER_KEY, token);
+        return createToken(claims);
+    }
+
+    /**
+     * 验证令牌有效期,相差不足20分钟,自动刷新缓存
+     *
+     * @param loginUser
+     * @return 令牌
+     */
+    public void verifyToken(LoginUser loginUser)
+    {
+        long expireTime = loginUser.getExpireTime();
+        long currentTime = System.currentTimeMillis();
+        if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
+        {
+            refreshToken(loginUser);
+        }
+    }
+
+    /**
+     * 刷新令牌有效期
+     *
+     * @param loginUser 登录信息
+     */
+    public void refreshToken(LoginUser loginUser)
+    {
+        loginUser.setLoginTime(System.currentTimeMillis());
+        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
+        // 根据uuid将loginUser缓存
+        String userKey = getTokenKey(loginUser.getToken());
+        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
+    }
+
+    /**
+     * 设置用户代理信息
+     *
+     * @param loginUser 登录信息
+     */
+    public void setUserAgent(LoginUser loginUser)
+    {
+        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
+        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
+        loginUser.setIpaddr(ip);
+        loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
+        loginUser.setBrowser(userAgent.getBrowser().getName());
+        loginUser.setOs(userAgent.getOperatingSystem().getName());
+    }
+
+    /**
+     * 从数据声明生成令牌
+     *
+     * @param claims 数据声明
+     * @return 令牌
+     */
+    private String createToken(Map<String, Object> claims)
+    {
+        String token = Jwts.builder()
+                .setClaims(claims)
+                .signWith(SignatureAlgorithm.HS512, secret).compact();
+        return token;
+    }
+
+    /**
+     * 从令牌中获取数据声明
+     *
+     * @param token 令牌
+     * @return 数据声明
+     */
+    private Claims parseToken(String token)
+    {
+        return Jwts.parser()
+                .setSigningKey(secret)
+                .parseClaimsJws(token)
+                .getBody();
+    }
+
+    /**
+     * 从令牌中获取用户名
+     *
+     * @param token 令牌
+     * @return 用户名
+     */
+    public String getUsernameFromToken(String token)
+    {
+        Claims claims = parseToken(token);
+        return claims.getSubject();
+    }
+
+    /**
+     * 获取请求token
+     *
+     * @param request
+     * @return token
+     */
+    private String getToken(HttpServletRequest request)
+    {
+        String token = request.getHeader(header);
+        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
+        {
+            token = token.replace(Constants.TOKEN_PREFIX, "");
+        }
+        return token;
+    }
+
+    private String getTokenKey(String uuid)
+    {
+        return Constants.LOGIN_TOKEN_KEY + uuid;
+    }
+}

+ 60 - 0
Future/future-framework/src/main/java/com/future/framework/web/service/UserDetailsServiceImpl.java

@@ -0,0 +1,60 @@
+package com.future.framework.web.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+import com.future.system.domain.entity.SysUser;
+import com.future.system.domain.model.LoginUser;
+import com.future.common.enums.UserStatus;
+import com.future.common.exception.BaseException;
+import com.future.common.utils.StringUtils;
+import com.future.system.service.ISysUserService;
+
+/**
+ * 用户验证处理
+ *
+ * @author future
+ */
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService
+{
+    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
+
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private SysPermissionService permissionService;
+
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
+    {
+        SysUser user = userService.selectUserByUserName(username);
+        if (StringUtils.isNull(user))
+        {
+            log.info("登录用户:{} 不存在.", username);
+            throw new UsernameNotFoundException("登录用户:" + username + " 不存在");
+        }
+        else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
+        {
+            log.info("登录用户:{} 已被删除.", username);
+            throw new BaseException("对不起,您的账号:" + username + " 已被删除");
+        }
+        else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
+        {
+            log.info("登录用户:{} 已被停用.", username);
+            throw new BaseException("对不起,您的账号:" + username + " 已停用");
+        }
+
+        return createLoginUser(user);
+    }
+
+    public UserDetails createLoginUser(SysUser user)
+    {
+        return new LoginUser(user, permissionService.getMenuPermission(user));
+    }
+}

+ 37 - 0
Future/future-gencodelocal/pom.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>future</artifactId>
+        <groupId>com.future</groupId>
+        <version>3.4.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>future-gencodelocal</artifactId>
+
+    <dependencies>
+        <!-- 通用工具-->
+        <dependency>
+            <groupId>com.future</groupId>
+            <artifactId>future-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.generator</groupId>
+            <artifactId>mybatis-generator-core</artifactId>
+            <version>1.3.7</version>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+    </dependencies>
+
+
+
+</project>

+ 0 - 0
Future/future-gencodelocal/src/main/java/com/CommentGenerator.java


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels