Browse Source

Merge branch 'master' of http://git.tjyourong.com.cn/ctop/adsp-boot

 Conflicts:
	jeecg-boot-base-common/src/main/java/org/jeecg/common/constant/CommonConstant.java
	jeecg-boot-base-common/src/main/java/org/jeecg/common/system/api/ISysBaseApi.java
	jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/DynamicDataSourceModel.java
	jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/LoginUser.java
	jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/SysCategoryModel.java
	jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/SysPermissionDataRuleModel.java
	jeecg-boot-base-common/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java
	jeecg-boot-module-activiti/pom.xml
	jeecg-boot-module-activiti/src/main/java/org/jeecg/modules/activiti/service/Impl/ActZprocessServiceImpl.java
	jeecg-boot-module-activiti/src/main/java/org/jeecg/modules/activiti/web/ActProcessInsController.java
	jeecg-boot-module-system/pom.xml
	jeecg-boot-module-system/src/main/java/org/jeecg/config/ShiroConfig.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/websocket/WebSocket.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysAnnouncement.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDataSource.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDepartPermission.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDepartRole.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDepartRolePermission.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDepartRoleUser.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDepartMapper.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDepartMapper.xml
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDictService.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java
	jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/FindsDepartsChildrenUtil.java
	jeecg-boot-module-system/src/main/resources/application-dev.yml
	module-common/src/main/java/cn/com/ctop/common/module/entity/SysUser.java
xuzuoyun 5 năm trước cách đây
mục cha
commit
3e804a6da9
100 tập tin đã thay đổi với 6229 bổ sung1883 xóa
  1. 4 0
      .gitattributes
  2. 61 0
      Dockerfile
  3. 22 121
      README.md
  4. 7 1
      jeecg-boot-base-common/pom.xml
  5. 23 23
      jeecg-boot-base-common/src/main/java/org/jeecg/common/api/vo/Result.java
  6. 0 36
      jeecg-boot-base-common/src/main/java/org/jeecg/common/aspect/annotation/AutoLog.java
  7. 0 42
      jeecg-boot-base-common/src/main/java/org/jeecg/common/aspect/annotation/Dict.java
  8. 18 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/aspect/annotation/OnlineAuth.java
  9. 0 29
      jeecg-boot-base-common/src/main/java/org/jeecg/common/aspect/annotation/PermissionData.java
  10. 82 75
      jeecg-boot-base-common/src/main/java/org/jeecg/common/constant/CommonConstant.java
  11. 14 12
      jeecg-boot-base-common/src/main/java/org/jeecg/common/constant/CommonSendStatus.java
  12. 135 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java
  13. 481 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/es/JeecgElasticsearchTemplate.java
  14. 98 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/es/QueryStringBuilder.java
  15. 42 5
      jeecg-boot-base-common/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java
  16. 36 37
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/api/ISysBaseApi.java
  17. 99 78
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java
  18. 0 2
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/base/entity/JeecgEntity.java
  19. 334 181
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/controller/CommonController.java
  20. 44 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/query/MatchTypeEnum.java
  21. 342 81
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/query/QueryGenerator.java
  22. 1 3
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/query/QueryRuleEnum.java
  23. 18 20
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/util/JeecgDataAutorUtils.java
  24. 179 182
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/util/JwtUtil.java
  25. 3 1
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/DictModel.java
  26. 8 8
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/DynamicDataSourceModel.java
  27. 13 14
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/LoginUser.java
  28. 6 4
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/SysCategoryModel.java
  29. 7 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/SysPermissionDataRuleModel.java
  30. 43 47
      jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/SysUserCacheInfo.java
  31. 15 5
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/BrowserUtils.java
  32. 167 140
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/DateUtils.java
  33. 66 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/DySmsEnum.java
  34. 57 50
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/DySmsHelper.java
  35. 29 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/HTMLUtils.java
  36. 2 2
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/IPUtils.java
  37. 96 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/ImportExcelUtil.java
  38. 10 9
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/PasswordUtil.java
  39. 61 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/PmsUtil.java
  40. 42 41
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/RedisUtil.java
  41. 121 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/RestDesformUtil.java
  42. 247 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/RestUtil.java
  43. 63 67
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/SpringContextUtils.java
  44. 69 13
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
  45. 98 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/TokenUtils.java
  46. 4 4
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/UUIDGenerator.java
  47. 161 152
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/YouBianCodeUtil.java
  48. 92 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/dynamic/db/DataSourceCachePool.java
  49. 31 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/dynamic/db/DbValidationQueryEnum.java
  50. 300 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/dynamic/db/DynamicDBUtil.java
  51. 173 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/dynamic/db/FreemarkerParseFactory.java
  52. 212 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/dynamic/db/SqlUtils.java
  53. 28 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/BaseColumn.java
  54. 98 27
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/CommonProperty.java
  55. 8 8
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/JsonSchemaDescrip.java
  56. 12 41
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/JsonschemaUtil.java
  57. 1 1
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/DictProperty.java
  58. 38 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/HiddenProperty.java
  59. 66 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/LinkDownProperty.java
  60. 0 3
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/NumberProperty.java
  61. 23 27
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/StringProperty.java
  62. 46 0
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/SwitchProperty.java
  63. 60 14
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/TreeSelectProperty.java
  64. 1 1
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java
  65. 1 3
      jeecg-boot-base-common/src/main/java/org/jeecg/common/util/superSearch/QueryRuleEnum.java
  66. 0 78
      jeecg-boot-base-common/src/main/java/org/jeecg/modules/system/entity/SysPermissionDataRule.java
  67. 51 0
      jeecg-boot-base-common/src/main/resources/static/pca.json
  68. 18 9
      jeecg-boot-module-activiti/pom.xml
  69. 1 8
      jeecg-boot-module-activiti/src/main/java/org/jeecg/modules/activiti/service/Impl/ActZprocessServiceImpl.java
  70. 1 1
      jeecg-boot-module-activiti/src/main/java/org/jeecg/modules/activiti/web/ActProcessInsController.java
  71. 4 0
      jeecg-boot-module-system/.gitattributes
  72. 81 1
      jeecg-boot-module-system/pom.xml
  73. 15 12
      jeecg-boot-module-system/src/main/java/org/jeecg/JeecgApplication.java
  74. 8 8
      jeecg-boot-module-system/src/main/java/org/jeecg/JeecgOneGui.java
  75. 30 23
      jeecg-boot-module-system/src/main/java/org/jeecg/JeecgOneToMainUtil.java
  76. 3 2
      jeecg-boot-module-system/src/main/java/org/jeecg/config/AutoPoiConfig.java
  77. 38 0
      jeecg-boot-module-system/src/main/java/org/jeecg/config/MinioConfig.java
  78. 10 9
      jeecg-boot-module-system/src/main/java/org/jeecg/config/MybatisPlusConfig.java
  79. 0 4
      jeecg-boot-module-system/src/main/java/org/jeecg/config/RedisConfig.java
  80. 24 0
      jeecg-boot-module-system/src/main/java/org/jeecg/config/RestTemplateConfig.java
  81. 60 0
      jeecg-boot-module-system/src/main/java/org/jeecg/config/RuleEngineConfig.java
  82. 88 29
      jeecg-boot-module-system/src/main/java/org/jeecg/config/ShiroConfig.java
  83. 31 0
      jeecg-boot-module-system/src/main/java/org/jeecg/config/StaticConfig.java
  84. 24 8
      jeecg-boot-module-system/src/main/java/org/jeecg/config/Swagger2Config.java
  85. 16 8
      jeecg-boot-module-system/src/main/java/org/jeecg/config/WebMvcConfiguration.java
  86. 18 0
      jeecg-boot-module-system/src/main/java/org/jeecg/config/WebSocketConfig.java
  87. 56 53
      jeecg-boot-module-system/src/main/java/org/jeecg/config/mybatis/MybatisInterceptor.java
  88. 31 0
      jeecg-boot-module-system/src/main/java/org/jeecg/config/oss/OssBootConfiguration.java
  89. 168 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/append/xd_schedule/controller/XdScheduleController.java
  90. 100 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/append/xd_schedule/entity/XdSchedule.java
  91. 14 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/append/xd_schedule/mapper/XdScheduleMapper.java
  92. 2 2
      module-common/src/main/java/cn/com/ctop/common/module/mapper/xml/VideoWatermarkTemplateMapper.xml
  93. 14 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/append/xd_schedule/service/IXdScheduleService.java
  94. 187 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/append/xd_schedule/service/impl/XdScheduleServiceImpl.java
  95. 107 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/controller/CasClientController.java
  96. 103 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/CASServiceUtil.java
  97. 292 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/XmlUtils.java
  98. 0 3
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/ActorController.java
  99. 16 15
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/AdvertiserController.java
  100. 0 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/AgentInfoController.java

+ 4 - 0
.gitattributes

@@ -0,0 +1,4 @@
+*.js linguist-language=Java
+*.css linguist-language=Java
+*.html linguist-language=Java
+*.vue linguist-language=Java

+ 61 - 0
Dockerfile

@@ -0,0 +1,61 @@
+#https://blog.csdn.net/sinat_19528249/article/details/99994464
+# Version 0.1
+# 基础镜像
+FROM centos:7
+# 维护者信息
+MAINTAINER kangxiaolin ksf@zgykkj.com
+VOLUME /tmp
+#自动安装依赖
+RUN  cd /etc/yum.repos.d/ \
+    && yum -y install wget \
+    && wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
+    && yum clean all \
+    && yum makecache \
+    && yum update -y \
+    &&  yum -y  install nginx  \
+    &&  yum -y  install  java-1.8.0-openjdk java-1.8.0-openjdk-devel  \
+    &&  yum -y  install redis    \
+#这里可以设置 域名
+# 可以送本地加载 使用ADD 也可以直接写
+   && echo "server {  \
+                       listen       81; \
+                       location ^~ /jeecg-boot { \
+                      proxy_pass              http://127.0.0.1:8080/jeecg-boot/; \
+                      proxy_set_header        Host 127.0.0.1; \
+                      proxy_set_header        X-Real-IP \$remote_addr; \
+                      proxy_set_header        X-Forwarded-For \$proxy_add_x_forwarded_for; \
+                  } \
+                  #解决Router(mode: 'history')模式下,刷新路由地址不能找到页面的问题 \
+                  location / { \
+                     root   /var/www/html/; \
+                      index  index.html index.htm; \
+                      if (!-e \$request_filename) { \
+                          rewrite ^(.*)\$ /index.html?s=\$1 last; \
+                          break; \
+                      } \
+                  } \
+                  access_log  /var/log/nginx/access.log ; \
+              } " > /etc/nginx/conf.d/default.conf  \
+
+ # 设置启动脚本
+     && touch /etc/init.d/start.sh \
+     && touch jeecgboot.log \
+     && chmod +x /etc/init.d/start.sh \
+     && echo "#!/bin/bash  " >> /etc/init.d/start.sh \
+     && echo "/usr/bin/redis-server  & " >> /etc/init.d/start.sh \
+     && echo "/usr/sbin/nginx  -c /etc/nginx/nginx.conf" >> /etc/init.d/start.sh \
+     && echo " java -jar /jeecgboot.jar   " >> /etc/init.d/start.sh \
+     &&  mkdir  -p  /var/www \
+     &&  mkdir -p /var/www/html
+# 前端迁移到系统文件中 默认是80端口 同级目录下的html地址
+ADD  ant-design-vue-jeecg/dist/ /var/www/html/
+# 拷贝相关的jar包
+ADD jeecg-boot/jeecg-boot-module-system/target/jeecg-boot-module-system-2.2.0.jar jeecgboot.jar
+EXPOSE  80  8080 81
+ENTRYPOINT /bin/sh -c   /etc/init.d/start.sh
+
+#启动脚本
+#docker rmi $(docker images | grep "^<none>" | awk "{print $3}") 删除<none>
+
+#docker build -t jeecgboot:centos .
+#docker run --privileged=true  -itd --name test -v /sys/fs/cgroup:/sys/fs/cgroup:ro  -p 81:81 -p 8080:8080 -p 82:80  jeecgboot:centos

+ 22 - 121
README.md

@@ -1,7 +1,7 @@
 Jeecg-Boot 快速开发平台
 ===============
 
-当前最新版本: 2.0.2(发布日期:20190708
+当前最新版本: 2.2.0(发布日期:20200506
 
 
 ## 后端技术架构
@@ -33,10 +33,22 @@ Jeecg-Boot 快速开发平台
 
 - 缓存:Redis
 
- 
-## 开发文档
 
-- 查询过滤器用法
+## 技术文档
+
+
+- 在线演示 :  [http://boot.jeecg.com](http://boot.jeecg.com)
+
+- 在线文档:  [http://doc.jeecg.com/1273753](http://doc.jeecg.com/1273753)
+
+- 常见问题:  [入门常见问题大全](http://bbs.jeecg.com/forum.php?mod=viewthread&tid=7816&extra=page%3D1)
+
+- QQ交流群 :  ①284271917、②769925425
+
+
+## 专项文档
+
+#### 一、查询过滤器用法
 
 ```
 QueryWrapper<?> queryWrapper = QueryGenerator.initQueryWrapper(?, req.getParameterMap());
@@ -77,133 +89,22 @@ QueryWrapper<?> queryWrapper = QueryGenerator.initQueryWrapper(?, req.getParamet
 | 多选字段模糊查询     | 上述4 有一个特例,若某一查询字段前后都带逗号 则会将其视为走这种查询方式 ,该查询方式是将查询条件以逗号分割再遍历数组 将每个元素作like查询 用or拼接,例如 现在name传入值 ,a,b,c, 那么结果sql就是 name like '%a%' or name like '%b%' or name like '%c%' |    |
 
 
-- Autopoi使用文档(EXCEL工具类 -  EasyPOI衍变升级重构版本)
+#### 二、AutoPoi(EXCEL工具类-EasyPOI衍变升级重构版本)
  
   [在线文档](https://github.com/zhangdaiscott/autopoi)
   
 
 
+#### 三、代码生成器
 
-- **代码生成器**
-
-** 功能说明**:   一键生成的代码(包括:controller、service、dao、mapper、entity、vue)
+> 功能说明:   一键生成的代码(包括:controller、service、dao、mapper、entity、vue)
  
- **模板位置**: src/main/resources/jeecg/code-template  
+ - 模板位置: src/main/resources/jeecg/code-template
+ - 技术文档: http://doc.jeecg.com
 
-**使用方法**: 
- 
- 【**一对一模板**】  
-  
-**1.**先找到**jeecg-boot/src/resources/jeecg**下的  
-**jeecg_config.properties**和**jeecg_database.properties**两个文件。  
-**jeecg_config.properties:** 用来配置文件生成的路径,  
-    
-**jeecg_database.properties:** 用来配置数据库相关配置.  
-         
-         
-**2.**配置好这些配置之后,我们需要找到**jeecg-boot/src/main/java/org/jeecg/JeecgOneGUI.java**类,也就是启动一对一代码生成器的入口;
-  
-    
-**3.**右键运行该类,紧接着会弹出一个窗口,如下图:  
-        ![](https://static.oschina.net/uploads/img/201904/14222638_Svth.png)  
-          
-          
-**4.**然后根据窗口左侧的提示,在右侧填写对应的信息即可.
-     
- 【**一对多模板**】  
-   
-   
-**1.**先找到**jeecg-boot/src/resources/jeecg**下的
-    
-**jeecg_config.properties**和**jeecg_database.properties**两个文件。  
-  
-**jeecg_config.properties:** 是配置文件生成路径的,  
-  
-  
-**jeecg_database.properties:** 是配置数据库相关配置的文件。  
-       
-       
-**2.**接着我们需要找到**jeecg-boot/src/main/java/org/jeecg/JeecgOneToMainUtil.java**这个类。
-     该类是生成一对多模板的启动入口。  
-       
-       
-**3.**该类中需要三个步骤来配置一对多表的信息。  
-  
-    
-  (1) 第一步: 配置主表信息,代码如下:
-  
-```
-		//第一步:设置主表配置
-		MainTableVo mainTable = new MainTableVo();
-		mainTable.setTableName("jeecg_order_main");//表名
-		mainTable.setEntityName("TestOrderMain");	 //实体名
-		mainTable.setEntityPackage("test2");	 //包名
-		mainTable.setFtlDescription("订单");	 //描述
-		
-```
-  (2) 第二步: 配置子表信息,**有多个则配置多个**, 代码如下: 
-     
-  ①比如: 配置子表 1:
-  
-  ```
-		//第二步:设置子表集合配置
-		List<SubTableVo> subTables = new ArrayList<SubTableVo>();
-		//[1].子表一
-		SubTableVo po = new SubTableVo();
-		po.setTableName("jeecg_order_customer");//表名
-		po.setEntityName("TestOrderCustom");	    //实体名
-		po.setEntityPackage("test2");	        //包名
-		po.setFtlDescription("客户明细");       //描述
-		//子表外键参数配置
-		/*说明: 
-		 * a) 子表引用主表主键ID作为外键,外键字段必须以_ID结尾;
-		 * b) 主表和子表的外键字段名字,必须相同(除主键ID外);
-		 * c) 多个外键字段,采用逗号分隔;
-		*/
-		po.setForeignKeys(new String[]{"order_id"});
-		subTables.add(po);
-  ```
-  ②比如: 配置子表 2:  
-  
-```
-		//[2].子表二
-		SubTableVo po2 = new SubTableVo();
-		po2.setTableName("jeecg_order_ticket");		//表名
-		po2.setEntityName("TestOrderTicket");			//实体名
-		po2.setEntityPackage("test2"); 				//包名
-		po2.setFtlDescription("产品明细");			//描述
-		//子表外键参数配置
-		/*说明: 
-		 * a) 子表引用主表主键ID作为外键,外键字段必须以_ID结尾;
-		 * b) 主表和子表的外键字段名字,必须相同(除主键ID外);
-		 * c) 多个外键字段,采用逗号分隔;
-		*/
-		po2.setForeignKeys(new String[]{"order_id"});
-		subTables.add(po2);  
-  ```
-  ③将整合了子表VO的subTables添加到主表对象当中去: 
 
-```
-  mainTable.setSubTables(subTables);
-  ```
-  ④需要注意如下代码,该代码的作用是,为子表设置主外键关联,当添加数据时,  
-主表的主键将会添加到子表的"order_id"中:  
-  
-```
-  		po2.setForeignKeys(new String[]{"order_id"});
-  ```
-    
-  (3) 第三步: 启动(run)程序,生成代码, 代码如下:
-  
-  ```
-  		//第三步:一对多(父子表)数据模型,代码生成
-		new CodeGenerateOneToMany(mainTable,subTables).generateCodeFile();
-  ```
- 
-[在线文档](https://github.com/zhangdaiscott/autopoi)  
-  
 
-- **编码排重使用示例**   
+#### 四、编码排重使用示例
 
 重复校验效果:
 ![输入图片说明](https://static.oschina.net/uploads/img/201904/19191836_eGkQ.png "在这里输入图片标题")

+ 7 - 1
jeecg-boot-base-common/pom.xml

@@ -4,6 +4,12 @@
     <modelVersion>4.0.0</modelVersion>
     <artifactId>jeecg-boot-base-common</artifactId>
     <version>2.0.2</version>
+    <dependencies>
+        <dependency>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy</artifactId>
+        </dependency>
+    </dependencies>
     <parent>
         <groupId>org.jeecgframework.boot</groupId>
         <artifactId>jeecg-boot-parent</artifactId>
@@ -29,4 +35,4 @@
         </repository>
     </repositories>
 
-</project>
+</project>

+ 23 - 23
jeecg-boot-base-common/src/main/java/org/jeecg/common/api/vo/Result.java

@@ -1,11 +1,11 @@
 package org.jeecg.common.api.vo;
 
-import java.io.Serializable;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 import org.jeecg.common.constant.CommonConstant;
 
-import lombok.Data;
+import java.io.Serializable;
 
 /**
  *   接口返回数据格式
@@ -36,7 +36,7 @@ public class Result<T> implements Serializable {
 	 */
 	@ApiModelProperty(value = "返回代码")
 	private Integer code = 0;
-	
+
 	/**
 	 * 返回数据对象 data
 	 */
@@ -48,64 +48,64 @@ public class Result<T> implements Serializable {
 	 */
 	@ApiModelProperty(value = "时间戳")
 	private long timestamp = System.currentTimeMillis();
+
 	public Result() {
-		
-	}
-	
-	public Result<T> error500(String message) {
-		this.message = message;
-		this.code = CommonConstant.SC_INTERNAL_SERVER_ERROR_500;
-		this.success = false;
-		return this;
+
 	}
-	
+
 	public Result<T> success(String message) {
 		this.message = message;
 		this.code = CommonConstant.SC_OK_200;
 		this.success = true;
 		return this;
 	}
-	
+
 	public static Result<Object> ok() {
-		Result<Object> r = new Result<Object>();
+		Result<Object> r = new Result<>();
 		r.setSuccess(true);
 		r.setCode(CommonConstant.SC_OK_200);
 		r.setMessage("成功");
 		return r;
 	}
-	
+
 	public static Result<Object> ok(String msg) {
-		Result<Object> r = new Result<Object>();
+		Result<Object> r = new Result<>();
 		r.setSuccess(true);
 		r.setCode(CommonConstant.SC_OK_200);
 		r.setMessage(msg);
 		return r;
 	}
-	
+
 	public static Result<Object> ok(Object data) {
-		Result<Object> r = new Result<Object>();
+		Result<Object> r = new Result<>();
 		r.setSuccess(true);
 		r.setCode(CommonConstant.SC_OK_200);
 		r.setResult(data);
 		return r;
 	}
-	
+
 	public static Result<Object> error(String msg) {
 		return error(CommonConstant.SC_INTERNAL_SERVER_ERROR_500, msg);
 	}
-	
+
 	public static Result<Object> error(int code, String msg) {
-		Result<Object> r = new Result<Object>();
+		Result<Object> r = new Result<>();
 		r.setCode(code);
 		r.setMessage(msg);
 		r.setSuccess(false);
 		return r;
 	}
-	
+
+	public Result<T> error500(String message) {
+		this.message = message;
+		this.code = CommonConstant.SC_INTERNAL_SERVER_ERROR_500;
+		this.success = false;
+		return this;
+	}
 	/**
 	 * 无权限访问返回结果
 	 */
 	public static Result<Object> noauth(String msg) {
 		return error(CommonConstant.SC_JEECG_NO_AUTHZ, msg);
 	}
-}
+}

+ 0 - 36
jeecg-boot-base-common/src/main/java/org/jeecg/common/aspect/annotation/AutoLog.java

@@ -1,36 +0,0 @@
-package org.jeecg.common.aspect.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import org.jeecg.common.constant.CommonConstant;
-
-/**
- * 系统日志注解
- * 
- * @Author scott
- * @email jeecgos@163.com
- * @Date 2019年1月14日
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface AutoLog {
-
-	/**
-	 * 日志内容
-	 * 
-	 * @return
-	 */
-	String value() default "";
-
-	/**
-	 * 日志类型
-	 * 
-	 * @return 0:操作日志;1:登录日志;2:定时任务;
-	 */
-	int logType() default CommonConstant.LOG_TYPE_2;
-}

+ 0 - 42
jeecg-boot-base-common/src/main/java/org/jeecg/common/aspect/annotation/Dict.java

@@ -1,42 +0,0 @@
-package org.jeecg.common.aspect.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- *  类描述:  字典注解
- * 作    者: dangzhenghui
- * 日    期: 2019年03月17日-下午9:37:16
- */
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface Dict {
-    /**
-     * 方法描述:  数据code
-     * 作    者: dangzhenghui
-     * 日    期: 2019年03月17日-下午9:37:16
-     *
-     * @return 返回类型: String
-     */
-    String dicCode();
-
-    /**
-     * 方法描述:  数据Text
-     * 作    者: dangzhenghui
-     * 日    期: 2019年03月17日-下午9:37:16
-     *
-     * @return 返回类型: String
-     */
-    String dicText() default "";
-
-    /**
-     * 方法描述: 数据字典表
-     * 作    者: dangzhenghui
-     * 日    期: 2019年03月17日-下午9:37:16
-     *
-     * @return 返回类型: String
-     */
-    String dictTable() default "";
-}

+ 18 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/aspect/annotation/OnlineAuth.java

@@ -0,0 +1,18 @@
+package org.jeecg.common.aspect.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * online请求拦截专用注解
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE,ElementType.METHOD})
+@Documented
+public @interface OnlineAuth {
+
+    /**
+     * 请求关键字,在xxx/code之前的字符串
+     * @return
+     */
+    String value();
+}

+ 0 - 29
jeecg-boot-base-common/src/main/java/org/jeecg/common/aspect/annotation/PermissionData.java

@@ -1,29 +0,0 @@
-package org.jeecg.common.aspect.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
-  *  数据权限注解
- * @Author taoyan
- * @Date 2019年4月11日
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE,ElementType.METHOD})
-@Documented
-public @interface PermissionData {
-	/**
-	 * 暂时没用
-	 * @return
-	 */
-	String value() default "";
-	
-	
-	/**
-	 * 配置菜单的组件路径,用于数据权限
-	 */
-	String pageComponent() default "";
-}

+ 82 - 75
jeecg-boot-base-common/src/main/java/org/jeecg/common/constant/CommonConstant.java

@@ -2,72 +2,73 @@ package org.jeecg.common.constant;
 
 public interface CommonConstant {
 
-    /**
-     * 正常状态
-     */
-    public static final Integer STATUS_NORMAL = 0;
-
-    /**
-     * 禁用状态
-     */
-    public static final Integer STATUS_DISABLE = -1;
-
-    /**
-     * 删除标志
-     */
-    public static final Integer DEL_FLAG_1 = 1;
-
-    /**
-     * 未删除
-     */
-    public static final Integer DEL_FLAG_0 = 0;
-
-    /**
-     * 系统日志类型: 登录
-     */
-    public static final int LOG_TYPE_1 = 1;
-
-    /**
-     * 系统日志类型: 操作
-     */
-    public static final int LOG_TYPE_2 = 2;
-
-    /**
-     * 操作日志类型: 查询
-     */
-    public static final int OPERATE_TYPE_1 = 1;
-
-    /**
-     * 操作日志类型: 添加
-     */
-    public static final int OPERATE_TYPE_2 = 2;
-
-    /**
-     * 操作日志类型: 更新
-     */
-    public static final int OPERATE_TYPE_3 = 3;
-
-    /**
-     * 操作日志类型: 删除
-     */
-    public static final int OPERATE_TYPE_4 = 4;
-
-    /**
-     * 操作日志类型: 倒入
-     */
-    public static final int OPERATE_TYPE_5 = 5;
-
-    /**
-     * 操作日志类型: 导出
-     */
-    public static final int OPERATE_TYPE_6 = 6;
-
-
-    /** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
+	/**
+	 * 正常状态
+	 */
+	public static final Integer STATUS_NORMAL = 0;
+
+	/**
+	 * 禁用状态
+	 */
+	public static final Integer STATUS_DISABLE = -1;
+
+	/**
+	 * 删除标志
+	 */
+	public static final Integer DEL_FLAG_1 = 1;
+
+	/**
+	 * 未删除
+	 */
+	public static final Integer DEL_FLAG_0 = 0;
+
+	/**
+	 * 系统日志类型: 登录
+	 */
+	public static final int LOG_TYPE_1 = 1;
+
+
+	/**
+	 * 系统日志类型: 操作
+	 */
+	public static final int LOG_TYPE_2 = 2;
+
+	/**
+	 * 操作日志类型: 查询
+	 */
+	public static final int OPERATE_TYPE_1 = 1;
+
+	/**
+	 * 操作日志类型: 添加
+	 */
+	public static final int OPERATE_TYPE_2 = 2;
+
+	/**
+	 * 操作日志类型: 更新
+	 */
+	public static final int OPERATE_TYPE_3 = 3;
+
+	/**
+	 * 操作日志类型: 删除
+	 */
+	public static final int OPERATE_TYPE_4 = 4;
+
+	/**
+	 * 操作日志类型: 倒入
+	 */
+	public static final int OPERATE_TYPE_5 = 5;
+
+	/**
+	 * 操作日志类型: 导出
+	 */
+	public static final int OPERATE_TYPE_6 = 6;
+	
+	
+	/** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
     public static final Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
     /** {@code 200 OK} (HTTP/1.0 - RFC 1945) */
     public static final Integer SC_OK_200 = 200;
-
+    
     /**访问权限认证未通过 510*/
     public static final Integer SC_JEECG_NO_AUTHZ=510;
 
@@ -79,50 +80,56 @@ public interface CommonConstant {
     public static final int  TOKEN_EXPIRE_TIME  = 3600;
 
 
+    /** 登录用户拥有角色缓存KEY前缀 */
+    public static String LOGIN_USER_CACHERULES_ROLE = "loginUser_cacheRules::Roles_";
+    /** 登录用户拥有权限缓存KEY前缀 */
+    public static String LOGIN_USER_CACHERULES_PERMISSION  = "loginUser_cacheRules::Permissions_";
+    /** 登录用户令牌缓存KEY前缀 */
+
     /**
      *  0:一级菜单
      */
     public static final Integer MENU_TYPE_0  = 0;
-    /**
-     *  1:子菜单
-     */
+   /**
+    *  1:子菜单 
+    */
     public static final Integer MENU_TYPE_1  = 1;
     /**
      *  2:按钮权限
      */
     public static final Integer MENU_TYPE_2  = 2;
-
+    
     /**通告对象类型(USER:指定用户,ALL:全体用户)*/
     public static final String MSG_TYPE_UESR  = "USER";
     public static final String MSG_TYPE_ALL  = "ALL";
-
+    
     /**发布状态(0未发布,1已发布,2已撤销)*/
     public static final String NO_SEND  = "0";
     public static final String HAS_SEND  = "1";
     public static final String HAS_CANCLE  = "2";
-
+    
     /**阅读状态(0未读,1已读)*/
     public static final String HAS_READ_FLAG  = "1";
     public static final String NO_READ_FLAG  = "0";
-
+    
     /**优先级(L低,M中,H高)*/
     public static final String PRIORITY_L  = "L";
     public static final String PRIORITY_M  = "M";
     public static final String PRIORITY_H  = "H";
-
+    
     /**
      * 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
      */
     public static final String SMS_TPL_TYPE_0  = "0";
     public static final String SMS_TPL_TYPE_1  = "1";
     public static final String SMS_TPL_TYPE_2  = "2";
-
+    
     /**
      * 状态(0无效1有效)
      */
     public static final String STATUS_0 = "0";
     public static final String STATUS_1 = "1";
-
+    
     /**
      * 同步工作流引擎1同步0不同步
      */
@@ -134,7 +141,7 @@ public interface CommonConstant {
      */
     public static final String MSG_CATEGORY_1 = "1";
     public static final String MSG_CATEGORY_2 = "2";
-
+    
     /**
      * 是否配置菜单的数据权限 1是0否
      */
@@ -146,7 +153,7 @@ public interface CommonConstant {
      */
     public static final Integer USER_UNFREEZE = 1;
     public static final Integer USER_FREEZE = 2;
-
+    
     /**字典翻译文本后缀*/
     public static final String DICT_TEXT_SUFFIX = "_dictText";
 

+ 14 - 12
jeecg-boot-base-common/src/main/java/org/jeecg/common/constant/CommonSendStatus.java

@@ -6,17 +6,19 @@ package org.jeecg.common.constant;
  *
  */
 public interface CommonSendStatus {
-    /**
-     * 未发布
-     */
-    public static final String UNPUBLISHED_STATUS_0 = "0";
 
-    /**
-     * 已发布
-     */
-    public static final String PUBLISHED_STATUS_1 = "1";
-    /**
-     * 撤销
-     */
-    public static final String REVOKE_STATUS_2 = "2";
+	public static final String UNPUBLISHED_STATUS_0 = "0";	//未发布
+
+	public static final String PUBLISHED_STATUS_1 = "1";		//已发布
+
+	public static final String REVOKE_STATUS_2 = "2";			//撤销
+
+
+
+	/**流程催办——系统通知消息模板*/
+	public static final String TZMB_BPM_CUIBAN = "bpm_cuiban";
+	/**标准模板—系统消息通知*/
+	public static final String TZMB_SYS_TS_NOTE = "sys_ts_note";
+	/**流程超时提醒——系统通知消息模板*/
+	public static final String TZMB_BPM_CHAOSHI_TIP = "bpm_chaoshi_tip";
 }

+ 135 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java

@@ -0,0 +1,135 @@
+package org.jeecg.common.constant;
+
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.Resource;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.List;
+
+@Component("pca")
+public class ProvinceCityArea {
+
+    @Value("classpath:static/pca.json")
+    private Resource jsonData;
+
+    List<Area> areaList;
+
+    public String getText(String code){
+        this.initAreaList();
+        if(this.areaList!=null || this.areaList.size()>0){
+            List<String> ls = new ArrayList<String>();
+            getAreaByCode(code,ls);
+            return String.join("/",ls);
+        }
+        return "";
+    }
+
+    public String getCode(String text){
+        this.initAreaList();
+        if(areaList!=null || areaList.size()>0){
+            for(int i=areaList.size()-1;i>=0;i--){
+                if(text.indexOf(areaList.get(i).getText())>=0){
+                    return areaList.get(i).getId();
+                }
+            }
+        }
+        return null;
+    }
+
+    public void getAreaByCode(String code,List<String> ls){
+        for(Area area: areaList){
+            if(area.getId().equals(code)){
+                String pid = area.getPid();
+                ls.add(0,area.getText());
+                getAreaByCode(pid,ls);
+            }
+        }
+    }
+
+    private void initAreaList(){
+        //System.out.println("=====================");
+        if(this.areaList==null || this.areaList.size()==0){
+            this.areaList = new ArrayList<Area>();
+            try {
+                File file = jsonData.getFile();
+                String jsonData = this.jsonRead(file);
+                JSONObject baseJson = JSONObject.parseObject(jsonData);
+                //第一层 省
+                JSONObject provinceJson = baseJson.getJSONObject("86");
+                for(String provinceKey: provinceJson.keySet()){
+                    //System.out.println("===="+provinceKey);
+                    Area province = new Area(provinceKey,provinceJson.getString(provinceKey),"86");
+                    this.areaList.add(province);
+                    //第二层 市
+                    JSONObject cityJson = baseJson.getJSONObject(provinceKey);
+                    for(String cityKey:cityJson.keySet()){
+                        //System.out.println("-----"+cityKey);
+                        Area city = new Area(cityKey,cityJson.getString(cityKey),provinceKey);
+                        this.areaList.add(city);
+                        //第三层 区
+                        JSONObject areaJson =  baseJson.getJSONObject(cityKey);
+                        if(areaJson!=null){
+                            for(String areaKey:areaJson.keySet()){
+                                //System.out.println("········"+areaKey);
+                                Area area = new Area(areaKey,areaJson.getString(areaKey),cityKey);
+                                this.areaList.add(area);
+                            }
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+
+    private String jsonRead(File file){
+        Scanner scanner = null;
+        StringBuilder buffer = new StringBuilder();
+        try {
+            scanner = new Scanner(file, "utf-8");
+            while (scanner.hasNextLine()) {
+                buffer.append(scanner.nextLine());
+            }
+        } catch (Exception e) {
+
+        } finally {
+            if (scanner != null) {
+                scanner.close();
+            }
+        }
+        return buffer.toString();
+    }
+
+    class Area{
+        String id;
+        String text;
+        String pid;
+
+        public Area(String id,String text,String pid){
+            this.id = id;
+            this.text = text;
+            this.pid = pid;
+        }
+
+        public String getId() {
+            return id;
+        }
+
+        public String getText() {
+            return text;
+        }
+
+        public String getPid() {
+            return pid;
+        }
+    }
+}

+ 481 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/es/JeecgElasticsearchTemplate.java

@@ -0,0 +1,481 @@
+package org.jeecg.common.es;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.jeecg.common.util.RestUtil;
+import org.jeecg.common.util.oConvertUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+
+/**
+ * 关于 ElasticSearch 的一些方法(创建索引、添加数据、查询等)
+ *
+ * @author sunjianlei
+ */
+@Slf4j
+@Component
+public class JeecgElasticsearchTemplate {
+    /** es服务地址 */
+    private String baseUrl;
+    private final String FORMAT_JSON = "format=json";
+
+    // ElasticSearch 最大可返回条目数
+    public static final int ES_MAX_SIZE = 10000;
+
+    public JeecgElasticsearchTemplate(@Value("${jeecg.elasticsearch.cluster-nodes}") String baseUrl, @Value("${jeecg.elasticsearch.check-enabled}") boolean checkEnabled) {
+        log.debug("JeecgElasticsearchTemplate BaseURL:" + baseUrl);
+        if (StringUtils.isNotEmpty(baseUrl)) {
+            this.baseUrl = baseUrl;
+            // 验证配置的ES地址是否有效
+            if (checkEnabled) {
+                try {
+                    RestUtil.get(this.getBaseUrl().toString());
+                    log.info("ElasticSearch 服务连接成功");
+                } catch (Exception e) {
+                    log.warn("ElasticSearch 服务连接失败,原因:配置未通过。可能是BaseURL未配置或配置有误,也可能是Elasticsearch服务未启动。接下来将会拒绝执行任何方法!");
+                }
+            }
+        }
+    }
+
+    public StringBuilder getBaseUrl(String indexName, String typeName) {
+        typeName = typeName.trim().toLowerCase();
+        return this.getBaseUrl(indexName).append("/").append(typeName);
+    }
+
+    public StringBuilder getBaseUrl(String indexName) {
+        indexName = indexName.trim().toLowerCase();
+        return this.getBaseUrl().append("/").append(indexName);
+    }
+
+    public StringBuilder getBaseUrl() {
+        return new StringBuilder("http://").append(this.baseUrl);
+    }
+
+    /**
+     * cat 查询ElasticSearch系统数据,返回json
+     */
+    public <T> ResponseEntity<T> _cat(String urlAfter, Class<T> responseType) {
+        String url = this.getBaseUrl().append("/_cat").append(urlAfter).append("?").append(FORMAT_JSON).toString();
+        return RestUtil.request(url, HttpMethod.GET, null, null, null, responseType);
+    }
+
+    /**
+     * 查询所有索引
+     * <p>
+     * 查询地址:GET http://{baseUrl}/_cat/indices
+     */
+    public JSONArray getIndices() {
+        return getIndices(null);
+    }
+
+
+    /**
+     * 查询单个索引
+     * <p>
+     * 查询地址:GET http://{baseUrl}/_cat/indices/{indexName}
+     */
+    public JSONArray getIndices(String indexName) {
+        StringBuilder urlAfter = new StringBuilder("/indices");
+        if (!StringUtils.isEmpty(indexName)) {
+            urlAfter.append("/").append(indexName.trim().toLowerCase());
+        }
+        return _cat(urlAfter.toString(), JSONArray.class).getBody();
+    }
+
+    /**
+     * 索引是否存在
+     */
+    public boolean indexExists(String indexName) {
+        try {
+            JSONArray array = getIndices(indexName);
+            return array != null;
+        } catch (org.springframework.web.client.HttpClientErrorException ex) {
+            if (HttpStatus.NOT_FOUND == ex.getStatusCode()) {
+                return false;
+            } else {
+                throw ex;
+            }
+        }
+    }
+
+    /**
+     * 根据ID获取索引数据,未查询到返回null
+     * <p>
+     * 查询地址:GET http://{baseUrl}/{indexName}/{typeName}/{dataId}
+     *
+     * @param indexName 索引名称
+     * @param typeName  type,一个任意字符串,用于分类
+     * @param dataId    数据id
+     * @return
+     */
+    public JSONObject getDataById(String indexName, String typeName, String dataId) {
+        String url = this.getBaseUrl(indexName, typeName).append("/").append(dataId).toString();
+        log.info("url:" + url);
+        JSONObject result = RestUtil.get(url);
+        boolean found = result.getBoolean("found");
+        if (found) {
+            return result.getJSONObject("_source");
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * 创建索引
+     * <p>
+     * 查询地址:PUT http://{baseUrl}/{indexName}
+     */
+    public boolean createIndex(String indexName) {
+        String url = this.getBaseUrl(indexName).toString();
+
+        /* 返回结果 (仅供参考)
+        "createIndex": {
+            "shards_acknowledged": true,
+            "acknowledged": true,
+            "index": "hello_world"
+        }
+        */
+        try {
+            return RestUtil.put(url).getBoolean("acknowledged");
+        } catch (org.springframework.web.client.HttpClientErrorException ex) {
+            if (HttpStatus.BAD_REQUEST == ex.getStatusCode()) {
+                log.warn("索引创建失败:" + indexName + " 已存在,无需再创建");
+            } else {
+                ex.printStackTrace();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 删除索引
+     * <p>
+     * 查询地址:DELETE http://{baseUrl}/{indexName}
+     */
+    public boolean removeIndex(String indexName) {
+        String url = this.getBaseUrl(indexName).toString();
+        try {
+            return RestUtil.delete(url).getBoolean("acknowledged");
+        } catch (org.springframework.web.client.HttpClientErrorException ex) {
+            if (HttpStatus.NOT_FOUND == ex.getStatusCode()) {
+                log.warn("索引删除失败:" + indexName + " 不存在,无需删除");
+            } else {
+                ex.printStackTrace();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 获取索引字段映射(可获取字段类型)
+     * <p>
+     *
+     * @param indexName 索引名称
+     * @param typeName  分类名称
+     * @return
+     */
+    public JSONObject getIndexMapping(String indexName, String typeName) {
+        String url = this.getBaseUrl(indexName, typeName).append("/_mapping?").append(FORMAT_JSON).toString();
+        log.info("getIndexMapping-url:" + url);
+        /*
+         * 参考返回JSON结构:
+         *
+         *{
+         *    // 索引名称
+         *    "[indexName]": {
+         *        "mappings": {
+         *            // 分类名称
+         *            "[typeName]": {
+         *                "properties": {
+         *                    // 字段名
+         *                    "input_number": {
+         *                        // 字段类型
+         *                        "type": "long"
+         *                    },
+         *                    "input_string": {
+         *                        "type": "text",
+         *                        "fields": {
+         *                            "keyword": {
+         *                                "type": "keyword",
+         *                                "ignore_above": 256
+         *                            }
+         *                        }
+         *                    }
+         *                 }
+         *            }
+         *        }
+         *    }
+         * }
+         */
+        try {
+            return RestUtil.get(url);
+        } catch (org.springframework.web.client.HttpClientErrorException e) {
+            String message = e.getMessage();
+            if (message != null && message.contains("404 Not Found")) {
+                return null;
+            }
+            throw e;
+        }
+    }
+
+    /**
+     * 获取索引字段映射,返回Java实体类
+     *
+     * @param indexName
+     * @param typeName
+     * @return
+     */
+    public <T> Map<String, T> getIndexMappingFormat(String indexName, String typeName, Class<T> clazz) {
+        JSONObject mapping = this.getIndexMapping(indexName, typeName);
+        Map<String, T> map = new HashMap<>();
+        if (mapping == null) {
+            return map;
+        }
+        // 获取字段属性
+        JSONObject properties = mapping.getJSONObject(indexName)
+                .getJSONObject("mappings")
+                .getJSONObject(typeName)
+                .getJSONObject("properties");
+        // 封装成 java类型
+        for (String key : properties.keySet()) {
+            T entity = properties.getJSONObject(key).toJavaObject(clazz);
+            map.put(key, entity);
+        }
+        return map;
+    }
+
+    /**
+     * 保存数据,详见:saveOrUpdate
+     */
+    public boolean save(String indexName, String typeName, String dataId, JSONObject data) {
+        return this.saveOrUpdate(indexName, typeName, dataId, data);
+    }
+
+    /**
+     * 更新数据,详见:saveOrUpdate
+     */
+    public boolean update(String indexName, String typeName, String dataId, JSONObject data) {
+        return this.saveOrUpdate(indexName, typeName, dataId, data);
+    }
+
+    /**
+     * 保存或修改索引数据
+     * <p>
+     * 查询地址:PUT http://{baseUrl}/{indexName}/{typeName}/{dataId}
+     *
+     * @param indexName 索引名称
+     * @param typeName  type,一个任意字符串,用于分类
+     * @param dataId    数据id
+     * @param data      要存储的数据
+     * @return
+     */
+    public boolean saveOrUpdate(String indexName, String typeName, String dataId, JSONObject data) {
+        String url = this.getBaseUrl(indexName, typeName).append("/").append(dataId).append("?refresh=wait_for").toString();
+        /* 返回结果(仅供参考)
+       "createIndexA2": {
+            "result": "created",
+            "_shards": {
+                "total": 2,
+                "successful": 1,
+                "failed": 0
+            },
+            "_seq_no": 0,
+            "_index": "test_index_1",
+            "_type": "test_type_1",
+            "_id": "a2",
+            "_version": 1,
+            "_primary_term": 1
+        }
+         */
+
+        try {
+            // 去掉 data 中为空的值
+            Set<String> keys = data.keySet();
+            List<String> emptyKeys = new ArrayList<>(keys.size());
+            for (String key : keys) {
+                String value = data.getString(key);
+                //1、剔除空值
+                if (oConvertUtils.isEmpty(value) || "[]".equals(value)) {
+                    emptyKeys.add(key);
+                }
+                //2、剔除上传控件值(会导致ES同步失败,报异常failed to parse field [ge_pic] of type [text] )
+                if (oConvertUtils.isNotEmpty(value) && value.indexOf("[{")!=-1) {
+                    emptyKeys.add(key);
+                    log.info("-------剔除上传控件字段------------key: "+ key);
+                }
+            }
+            for (String key : emptyKeys) {
+                data.remove(key);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        try {
+            String result = RestUtil.put(url, data).getString("result");
+            return "created".equals(result) || "updated".equals(result);
+        } catch (Exception e) {
+            log.error(e.getMessage() + "\n-- url: " + url + "\n-- data: " + data.toJSONString());
+            //TODO 打印接口返回异常json
+            return false;
+        }
+    }
+
+    /**
+     * 删除索引数据
+     * <p>
+     * 请求地址:DELETE http://{baseUrl}/{indexName}/{typeName}/{dataId}
+     */
+    public boolean delete(String indexName, String typeName, String dataId) {
+        String url = this.getBaseUrl(indexName, typeName).append("/").append(dataId).toString();
+        /* 返回结果(仅供参考)
+        {
+            "_index": "es_demo",
+            "_type": "docs",
+            "_id": "001",
+            "_version": 3,
+            "result": "deleted",
+            "_shards": {
+                "total": 1,
+                "successful": 1,
+                "failed": 0
+            },
+            "_seq_no": 28,
+            "_primary_term": 18
+        }
+        */
+        try {
+            return "deleted".equals(RestUtil.delete(url).getString("result"));
+        } catch (org.springframework.web.client.HttpClientErrorException ex) {
+            if (HttpStatus.NOT_FOUND == ex.getStatusCode()) {
+                return false;
+            } else {
+                throw ex;
+            }
+        }
+    }
+
+
+    /* = = = 以下关于查询和查询条件的方法 = = =*/
+
+    /**
+     * 查询数据
+     * <p>
+     * 请求地址:POST http://{baseUrl}/{indexName}/{typeName}/_search
+     */
+    public JSONObject search(String indexName, String typeName, JSONObject queryObject) {
+        String url = this.getBaseUrl(indexName, typeName).append("/_search").toString();
+
+        log.info("url:" + url + " ,search: " + queryObject.toJSONString());
+        JSONObject res = RestUtil.post(url, queryObject);
+        log.info("url:" + url + " ,return res: \n" + res.toJSONString());
+        return res;
+    }
+
+    /**
+     * @param _source (源滤波器)指定返回的字段,传null返回所有字段
+     * @param query
+     * @param from    从第几条数据开始
+     * @param size    返回条目数
+     * @return { "query": query }
+     */
+    public JSONObject buildQuery(List<String> _source, JSONObject query, int from, int size) {
+        JSONObject json = new JSONObject();
+        if (_source != null) {
+            json.put("_source", _source);
+        }
+        json.put("query", query);
+        json.put("from", from);
+        json.put("size", size);
+        return json;
+    }
+
+    /**
+     * @return { "bool" : { "must": must, "must_not": mustNot, "should": should } }
+     */
+    public JSONObject buildBoolQuery(JSONArray must, JSONArray mustNot, JSONArray should) {
+        JSONObject bool = new JSONObject();
+        if (must != null) {
+            bool.put("must", must);
+        }
+        if (mustNot != null) {
+            bool.put("must_not", mustNot);
+        }
+        if (should != null) {
+            bool.put("should", should);
+        }
+        JSONObject json = new JSONObject();
+        json.put("bool", bool);
+        return json;
+    }
+
+    /**
+     * @param field 要查询的字段
+     * @param args  查询参数,参考: *哈哈* OR *哒* NOT *呵* OR *啊*
+     * @return
+     */
+    public JSONObject buildQueryString(String field, String... args) {
+        if (field == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder(field).append(":(");
+        if (args != null) {
+            for (String arg : args) {
+                sb.append(arg).append(" ");
+            }
+        }
+        sb.append(")");
+        return this.buildQueryString(sb.toString());
+    }
+
+    /**
+     * @return { "query_string": { "query": query }  }
+     */
+    public JSONObject buildQueryString(String query) {
+        JSONObject queryString = new JSONObject();
+        queryString.put("query", query);
+        JSONObject json = new JSONObject();
+        json.put("query_string", queryString);
+        return json;
+    }
+
+    /**
+     * @param field      查询字段
+     * @param min        最小值
+     * @param max        最大值
+     * @param containMin 范围内是否包含最小值
+     * @param containMax 范围内是否包含最大值
+     * @return { "range" : { field : { 『 "gt『e』?containMin" : min 』?min!=null , 『 "lt『e』?containMax" : max 』}} }
+     */
+    public JSONObject buildRangeQuery(String field, Object min, Object max, boolean containMin, boolean containMax) {
+        JSONObject inner = new JSONObject();
+        if (min != null) {
+            if (containMin) {
+                inner.put("gte", min);
+            } else {
+                inner.put("gt", min);
+            }
+        }
+        if (max != null) {
+            if (containMax) {
+                inner.put("lte", max);
+            } else {
+                inner.put("lt", max);
+            }
+        }
+        JSONObject range = new JSONObject();
+        range.put(field, inner);
+        JSONObject json = new JSONObject();
+        json.put("range", range);
+        return json;
+    }
+
+}
+

+ 98 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/es/QueryStringBuilder.java

@@ -0,0 +1,98 @@
+package org.jeecg.common.es;
+
+/**
+ * 用于创建 ElasticSearch 的 queryString
+ *
+ * @author sunjianlei
+ */
+public class QueryStringBuilder {
+
+    StringBuilder builder;
+
+    public QueryStringBuilder(String field, String str, boolean not, boolean addQuot) {
+        builder = this.createBuilder(field, str, not, addQuot);
+    }
+
+    public QueryStringBuilder(String field, String str, boolean not) {
+        builder = this.createBuilder(field, str, not, true);
+    }
+
+    /**
+     * 创建 StringBuilder
+     *
+     * @param field
+     * @param str
+     * @param not     是否是不匹配
+     * @param addQuot 是否添加双引号
+     * @return
+     */
+    public StringBuilder createBuilder(String field, String str, boolean not, boolean addQuot) {
+        StringBuilder sb = new StringBuilder(field).append(":(");
+        if (not) {
+            sb.append(" NOT ");
+        }
+        this.addQuotEffect(sb, str, addQuot);
+        return sb;
+    }
+
+    public QueryStringBuilder and(String str) {
+        return this.and(str, true);
+    }
+
+    public QueryStringBuilder and(String str, boolean addQuot) {
+        builder.append(" AND ");
+        this.addQuot(str, addQuot);
+        return this;
+    }
+
+    public QueryStringBuilder or(String str) {
+        return this.or(str, true);
+    }
+
+    public QueryStringBuilder or(String str, boolean addQuot) {
+        builder.append(" OR ");
+        this.addQuot(str, addQuot);
+        return this;
+    }
+
+    public QueryStringBuilder not(String str) {
+        return this.not(str, true);
+    }
+
+    public QueryStringBuilder not(String str, boolean addQuot) {
+        builder.append(" NOT ");
+        this.addQuot(str, addQuot);
+        return this;
+    }
+
+    /**
+    * 添加双引号(模糊查询,不能加双引号)
+    */
+    private QueryStringBuilder addQuot(String str, boolean addQuot) {
+        return this.addQuotEffect(this.builder, str, addQuot);
+    }
+
+    /**
+     * 是否在两边加上双引号
+     * @param builder
+     * @param str
+     * @param addQuot
+     * @return
+     */
+    private QueryStringBuilder addQuotEffect(StringBuilder builder, String str, boolean addQuot) {
+        if (addQuot) {
+            builder.append('"');
+        }
+        builder.append(str);
+        if (addQuot) {
+            builder.append('"');
+        }
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return builder.append(")").toString();
+    }
+
+}

+ 42 - 5
jeecg-boot-base-common/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java

@@ -1,12 +1,16 @@
 package org.jeecg.common.exception;
 
+import io.lettuce.core.RedisConnectionException;
 import org.apache.shiro.authz.AuthorizationException;
 import org.apache.shiro.authz.UnauthorizedException;
 import org.jeecg.common.api.vo.Result;
+import org.springframework.dao.DataIntegrityViolationException;
 import org.springframework.dao.DuplicateKeyException;
+import org.springframework.data.redis.connection.PoolException;
 import org.springframework.web.HttpRequestMethodNotSupportedException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.multipart.MaxUploadSizeExceededException;
 import org.springframework.web.servlet.NoHandlerFoundException;
 
 import lombok.extern.slf4j.Slf4j;
@@ -46,13 +50,12 @@ public class JeecgBootExceptionHandler {
 	public Result<?> handleAuthorizationException(AuthorizationException e){
 		log.error(e.getMessage(), e);
 		return Result.noauth("没有权限,请联系管理员授权");
-
 	}
 
 	@ExceptionHandler(Exception.class)
 	public Result<?> handleException(Exception e){
 		log.error(e.getMessage(), e);
-		return Result.error(e.getMessage());
+		return Result.error("操作失败,"+e.getMessage());
 	}
 	
 	/**
@@ -61,9 +64,43 @@ public class JeecgBootExceptionHandler {
 	 * @return
 	 */
 	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
-	public Result<?> HttpRequestMethodNotSupportedException(Exception e){
-		log.error(e.getMessage(), e);
-		return Result.error("没有权限,请联系管理员授权");
+	public Result<?> HttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e){
+		StringBuffer sb = new StringBuffer();
+		sb.append("不支持");
+		sb.append(e.getMethod());
+		sb.append("请求方法,");
+		sb.append("支持以下");
+		String [] methods = e.getSupportedMethods();
+		if(methods!=null){
+			for(String str:methods){
+				sb.append(str);
+				sb.append("、");
+			}
+		}
+		log.error(sb.toString(), e);
+		//return Result.error("没有权限,请联系管理员授权");
+		return Result.error(405,sb.toString());
 	}
 
+	 /**
+	  * spring默认上传大小100MB 超出大小捕获异常MaxUploadSizeExceededException
+	  */
+    @ExceptionHandler(MaxUploadSizeExceededException.class)
+    public Result<?> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
+    	log.error(e.getMessage(), e);
+        return Result.error("文件大小超出10MB限制, 请压缩或降低文件质量! ");
+    }
+
+    @ExceptionHandler(DataIntegrityViolationException.class)
+    public Result<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
+    	log.error(e.getMessage(), e);
+        return Result.error("字段太长,超出数据库字段的长度");
+    }
+
+    @ExceptionHandler(PoolException.class)
+    public Result<?> handlePoolException(PoolException e) {
+    	log.error(e.getMessage(), e);
+        return Result.error("Redis 连接异常!");
+    }
+
 }

+ 36 - 37
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/api/ISysBaseApi.java

@@ -1,15 +1,14 @@
 package org.jeecg.common.system.api;
 
-import java.sql.SQLException;
-import java.util.List;
-import java.util.Map;
-
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import org.jeecg.common.system.vo.*;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletResponse;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
 
 /**
  * @Description: 底层共通业务API,提供其他独立模块调用
@@ -28,14 +27,14 @@ public interface ISysBaseApi {
 	void addLog(String LogContent, Integer logType, Integer operatetype);
 
 	/**
-	 * 根据用户账号查询用户信息
+	  * 根据用户账号查询用户信息
 	 * @param username
 	 * @return
 	 */
 	public LoginUser getUserByName(String username);
 
 	/**
-	 * 根据用户id查询用户信息
+	  * 根据用户id查询用户信息
 	 * @param id
 	 * @return
 	 */
@@ -70,7 +69,7 @@ public interface ISysBaseApi {
 	public String getDatabaseType() throws SQLException;
 
 	/**
-	 * 获取数据字典
+	  * 获取数据字典
 	 * @param code
 	 * @return
 	 */
@@ -79,32 +78,32 @@ public interface ISysBaseApi {
 	/** 查询所有的父级字典,按照create_time排序 */
 	public List<DictModel> queryAllDict();
 
-	/**
-	 * 查询所有分类字典
-	 * @return
-	 */
+    /**
+     * 查询所有分类字典
+     * @return
+     */
 	public List<SysCategoryModel> queryAllDSysCategory();
 
 	/**
-	 * 获取表数据字典
+	  * 获取表数据字典
 	 * @param table
 	 * @param text
 	 * @param code
 	 * @return
 	 */
-	List<DictModel> queryTableDictItemsByCode(String table, String text, String code);
+    List<DictModel> queryTableDictItemsByCode(String table, String text, String code);
 
-	/**
-	 * 查询所有部门 作为字典信息 id -->value,departName -->text
-	 * @return
-	 */
-	public List<DictModel> queryAllDepartBackDictModel();
+    /**
+   	 * 查询所有部门 作为字典信息 id -->value,departName -->text
+   	 * @return
+   	 */
+   	public List<DictModel> queryAllDepartBackDictModel();
 
-	/**
-	 * 查询所有部门,拼接查询条件
-	 * @return
-	 */
-	List<JSONObject> queryAllDepart(Wrapper wrapper);
+    /**
+   	 * 查询所有部门,拼接查询条件
+   	 * @return
+   	 */
+   	List<JSONObject> queryAllDepart(Wrapper wrapper);
 
 	/**
 	 * 发送系统消息
@@ -202,19 +201,19 @@ public interface ISysBaseApi {
 	 */
 	public List<ComboModel> queryAllUser();
 
-	/**
-	 * 获取所有有效用户 带参
-	 * userIds 默认选中用户
-	 * @return
-	 */
-	public JSONObject queryAllUser(String[] userIds, int pageNo, int pageSize);
+    /**
+     * 获取所有有效用户 带参
+     * userIds 默认选中用户
+     * @return
+     */
+    public JSONObject queryAllUser(String[] userIds, int pageNo, int pageSize);
 
-	/**
-	 * 获取所有有效用户 拼接查询条件
-	 *
-	 * @return
-	 */
-	List<JSONObject> queryAllUser(Wrapper wrapper);
+    /**
+     * 获取所有有效用户 拼接查询条件
+     *
+     * @return
+     */
+    List<JSONObject> queryAllUser(Wrapper wrapper);
 
 	/**
 	 * 获取所有角色
@@ -224,7 +223,7 @@ public interface ISysBaseApi {
 
 	/**
 	 * 获取所有角色 带参
-	 * roleIds 默认选中角色
+     * roleIds 默认选中角色
 	 * @return
 	 */
 	public List<ComboModel> queryAllRole(String[] roleIds );
@@ -326,7 +325,7 @@ public interface ISysBaseApi {
 	 * @return
 	 * @param userId
 	 */
-	void meetingSignWebsocket(String userId);
+    void meetingSignWebsocket(String userId);
 	/**
 	 * 根据name获取所有参与用户
 	 * userNames

+ 99 - 78
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java

@@ -1,18 +1,14 @@
 package org.jeecg.common.system.base.controller;
 
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.IService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.beanutils.PropertyUtils;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.system.base.entity.JeecgEntity;
-import org.jeecg.common.system.base.service.JeecgService;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.oConvertUtils;
 import org.jeecgframework.poi.excel.ExcelImportUtil;
 import org.jeecgframework.poi.excel.def.NormalExcelConstants;
 import org.jeecgframework.poi.excel.entity.ExportParams;
@@ -23,9 +19,13 @@ import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartHttpServletRequest;
 import org.springframework.web.servlet.ModelAndView;
 
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-
-import lombok.extern.slf4j.Slf4j;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * @Description: Controller基类
@@ -34,73 +34,94 @@ import lombok.extern.slf4j.Slf4j;
  * @Version: 1.0
  */
 @Slf4j
-public class JeecgController<T extends JeecgEntity, S extends JeecgService<T>> {
-	@Autowired
-	S service;
+public class JeecgController<T, S extends IService<T>> {
+    @Autowired
+    S service;
+
+    /**
+     * 导出excel
+     *
+     * @param request
+     */
+    protected ModelAndView exportXls(HttpServletRequest request, T object, Class<T> clazz, String title) {
+        // Step.1 组装查询条件
+        QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+
+        // Step.2 获取导出数据
+        List<T> pageList = service.list(queryWrapper);
+        List<T> exportList = null;
+
+        // 过滤选中数据
+        String selections = request.getParameter("selections");
+        if (oConvertUtils.isNotEmpty(selections)) {
+            List<String> selectionList = Arrays.asList(selections.split(","));
+            exportList = pageList.stream().filter(item -> selectionList.contains(getId(item))).collect(Collectors.toList());
+        } else {
+            exportList = pageList;
+        }
+
+        // Step.3 AutoPoi 导出Excel
+        ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
+        mv.addObject(NormalExcelConstants.FILE_NAME, title); //此处设置的filename无效 ,前端会重更新设置一下
+        mv.addObject(NormalExcelConstants.CLASS, clazz);
+        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title));
+        mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
+        return mv;
+    }
 
-	/**
-	 * 导出excel
-	 *
-	 * @param request
-	 * @param response
-	 */
-	protected ModelAndView exportXls(HttpServletRequest request,T object,Class<T> clazz,String title) {
-		//--------------------------------------------------------------------------------
-		//获取当前用户
-		LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
-		//--------------------------------------------------------------------------------
-		// Step.1 组装查询条件
-		QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
 
-		// Step.2 AutoPoi 导出Excel
-		ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
-		List<T> pageList = service.list(queryWrapper);
-		// 导出文件名称
-        //此处设置的filename无效 ,前端会重更新设置一下
-        mv.addObject(NormalExcelConstants.FILE_NAME, title);
-		mv.addObject(NormalExcelConstants.CLASS, clazz);
-		mv.addObject(NormalExcelConstants.PARAMS, new ExportParams(title + "报表", "导出人:"+sysUser.getRealname(), title + "表"));
-		mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
-		return mv;
-	}
+    /**
+     * 获取对象ID
+     *
+     * @return
+     */
+    private String getId(T item) {
+        try {
+            return PropertyUtils.getProperty(item, "id").toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
 
-	/**
-	 * 通过excel导入数据
-	 *
-	 * @param request
-	 * @param response
-	 * @return
-	 */
-	protected Result<?> importExcel(HttpServletRequest request, HttpServletResponse response, Class<T> clazz) {
-		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
-		Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
-		for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
-            MultipartFile file = entity.getValue();
-			ImportParams params = new ImportParams();
-			params.setTitleRows(2);
-			params.setHeadRows(1);
-			params.setNeedSave(true);
-			try {
-				List<T> list = ExcelImportUtil.importExcel(file.getInputStream(), clazz, params);
-				//update-begin-author:taoyan date:20190528 for:批量插入数据
-				long start = System.currentTimeMillis();
-				service.saveBatch(list);
-				//400条 saveBatch消耗时间1592毫秒  循环插入消耗时间1947毫秒
-				//1200条  saveBatch消耗时间3687毫秒 循环插入消耗时间5212毫秒
-				log.info("消耗时间"+(System.currentTimeMillis()-start)+"毫秒");
-				//update-end-author:taoyan date:20190528 for:批量插入数据
-				return Result.ok("文件导入成功!数据行数:" + list.size());
-			} catch (Exception e) {
-				log.error(e.getMessage(), e);
-				return Result.error("文件导入失败:" + e.getMessage());
-			} finally {
-				try {
-					file.getInputStream().close();
-				} catch (IOException e) {
-					e.printStackTrace();
-				}
-			}
-		}
-		return Result.error("文件导入失败!");
-	}
+    /**
+     * 通过excel导入数据
+     *
+     * @param request
+     * @param response
+     * @return
+     */
+    protected Result<?> importExcel(HttpServletRequest request, HttpServletResponse response, Class<T> clazz) {
+        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
+        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
+            MultipartFile file = entity.getValue();// 获取上传文件对象
+            ImportParams params = new ImportParams();
+            params.setTitleRows(2);
+            params.setHeadRows(1);
+            params.setNeedSave(true);
+            try {
+                List<T> list = ExcelImportUtil.importExcel(file.getInputStream(), clazz, params);
+                //update-begin-author:taoyan date:20190528 for:批量插入数据
+                long start = System.currentTimeMillis();
+                service.saveBatch(list);
+                //400条 saveBatch消耗时间1592毫秒  循环插入消耗时间1947毫秒
+                //1200条  saveBatch消耗时间3687毫秒 循环插入消耗时间5212毫秒
+                log.info("消耗时间" + (System.currentTimeMillis() - start) + "毫秒");
+                //update-end-author:taoyan date:20190528 for:批量插入数据
+                return Result.ok("文件导入成功!数据行数:" + list.size());
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+                return Result.error("文件导入失败:" + e.getMessage());
+            } finally {
+                try {
+                    file.getInputStream().close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return Result.error("文件导入失败!");
+    }
 }

+ 0 - 2
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/base/entity/JeecgEntity.java

@@ -1,7 +1,6 @@
 package org.jeecg.common.system.base.entity;
 
 import java.io.Serializable;
-
 import org.jeecgframework.poi.excel.annotation.Excel;
 import org.springframework.format.annotation.DateTimeFormat;
 
@@ -23,7 +22,6 @@ import lombok.experimental.Accessors;
 @Data
 @EqualsAndHashCode(callSuper = false)
 @Accessors(chain = true)
-
 public class JeecgEntity implements Serializable {
 	private static final long serialVersionUID = 1L;
 

+ 334 - 181
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/controller/CommonController.java

@@ -1,31 +1,31 @@
 package org.jeecg.common.system.controller;
 
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.util.CommonUtils;
+import org.jeecg.common.util.RestUtil;
+import org.jeecg.common.util.TokenUtils;
+import org.jeecg.common.util.oConvertUtils;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.server.ServletServerHttpRequest;
 import org.springframework.util.AntPathMatcher;
 import org.springframework.util.FileCopyUtils;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartHttpServletRequest;
 import org.springframework.web.servlet.HandlerMapping;
 import org.springframework.web.servlet.ModelAndView;
 
-import lombok.extern.slf4j.Slf4j;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLDecoder;
 
 /**
  * <p>
@@ -39,184 +39,337 @@ import lombok.extern.slf4j.Slf4j;
 @RestController
 @RequestMapping("/sys/common")
 public class CommonController {
+	@Value(value = "${jeecg.path.upload}")
+	private String uploadpath;
 
-    @Value(value = "${jeecg.path.upload}")
-    private String uploadpath;
+	/**
+	 * 本地:local minio:minio 阿里:alioss
+	 */
+	@Value(value="${jeecg.uploadType}")
+	private String uploadType;
 
-    /**
-     * @return
-     * @Author 政辉
-     */
-    @GetMapping("/403")
-    public Result<?> noauth() {
-        return Result.error("没有权限,请联系管理员授权");
-    }
+	/**
+	 * @Author 政辉
+	 * @return
+	 */
+	@GetMapping("/403")
+	public Result<?> noauth()  {
+		return Result.error("没有权限,请联系管理员授权");
+	}
 
-    @PostMapping(value = "/upload")
-    public Result<?> upload(HttpServletRequest request, HttpServletResponse response) {
-        Result<?> result = new Result<>();
-        try {
-            String ctxPath = uploadpath;
-            String fileName = null;
-            String bizPath = "files";
-            String nowday = new SimpleDateFormat("yyyyMMdd").format(new Date());
-            File file = new File(ctxPath + File.separator + bizPath + File.separator + nowday);
-            if (!file.exists()) {
-                file.mkdirs();
-            }
-            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
-            MultipartFile mf = multipartRequest.getFile("file");
-            // 获取文件名
-            String orgName = mf.getOriginalFilename();
-            fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.indexOf("."));
-            String savePath = file.getPath() + File.separator + fileName;
-            File savefile = new File(savePath);
-            FileCopyUtils.copy(mf.getBytes(), savefile);
-            String dbpath = bizPath + File.separator + nowday + File.separator + fileName;
-            if (dbpath.contains("\\")) {
-                dbpath = dbpath.replace("\\", "/");
-            }
-            result.setMessage(dbpath);
-            result.setSuccess(true);
-        } catch (IOException e) {
-            result.setSuccess(false);
-            result.setMessage(e.getMessage());
-            log.error(e.getMessage(), e);
-        }
-        return result;
-    }
+	/**
+	 * 文件上传统一方法
+	 * @param request
+	 * @param response
+	 * @return
+	 */
+	@PostMapping(value = "/upload")
+	public Result<?> upload(HttpServletRequest request, HttpServletResponse response) {
+		Result<?> result = new Result<>();
+		String savePath = "";
+		String bizPath = request.getParameter("biz");
+		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+		MultipartFile file = multipartRequest.getFile("file");// 获取上传文件对象
+		if(oConvertUtils.isEmpty(bizPath)){
+			if(CommonConstant.UPLOAD_TYPE_OSS.equals(uploadType)){
+				//未指定目录,则用阿里云默认目录 upload
+				bizPath = "upload";
+				//result.setMessage("使用阿里云文件上传时,必须添加目录!");
+				//result.setSuccess(false);
+				//return result;
+			}else{
+				bizPath = "";
+			}
+		}
+		if(CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)){
+			//针对jeditor编辑器如何使 lcaol模式,采用 base64格式存储
+			String jeditor = request.getParameter("jeditor");
+			if(oConvertUtils.isNotEmpty(jeditor)){
+				result.setMessage(CommonConstant.UPLOAD_TYPE_LOCAL);
+				result.setSuccess(true);
+				return result;
+			}else{
+				savePath = this.uploadLocal(file,bizPath);
+			}
+		}else{
+//			savePath = sysBaseApi.upload(file,bizPath,uploadType);
+		}
+		if(oConvertUtils.isNotEmpty(savePath)){
+			result.setMessage(savePath);
+			result.setSuccess(true);
+		}else {
+			result.setMessage("上传失败!");
+			result.setSuccess(false);
+		}
+		return result;
+	}
 
-    /**
-     * 预览图片
-     * 请求地址:http://localhost:8080/common/view/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
-     *
-     * @param request
-     * @param response
-     */
-    @GetMapping(value = "/view/**")
-    public void view(HttpServletRequest request, HttpServletResponse response) {
-        // ISO-8859-1 ==> UTF-8 进行编码转换
-        String imgPath = extractPathFromPattern(request);
-        // 其余处理略
-        InputStream inputStream = null;
-        OutputStream outputStream = null;
-        try {
-            imgPath = imgPath.replace("..", "");
-            if (imgPath.endsWith(",")) {
-                imgPath = imgPath.substring(0, imgPath.length() - 1);
-            }
-            response.setContentType("image/jpeg;charset=utf-8");
-            String localPath = uploadpath;
-            String imgurl = localPath + File.separator + imgPath;
-            inputStream = new BufferedInputStream(new FileInputStream(imgurl));
-            outputStream = response.getOutputStream();
-            byte[] buf = new byte[1024];
-            int len;
-            while ((len = inputStream.read(buf)) > 0) {
-                outputStream.write(buf, 0, len);
-            }
-            response.flushBuffer();
-        } catch (IOException e) {
-            log.error("预览图片失败" + e.getMessage());
-        } finally {
-            if (inputStream != null) {
-                try {
-                    inputStream.close();
-                } catch (IOException e) {
-                    log.error(e.getMessage(), e);
-                }
-            }
-            if (outputStream != null) {
-                try {
-                    outputStream.close();
-                } catch (IOException e) {
-                    log.error(e.getMessage(), e);
-                }
-            }
-        }
+	/**
+	 * 本地文件上传
+	 * @param mf 文件
+	 * @param bizPath  自定义路径
+	 * @return
+	 */
+	private String uploadLocal(MultipartFile mf,String bizPath){
+		try {
+			String ctxPath = uploadpath;
+			String fileName = null;
+			File file = new File(ctxPath + File.separator + bizPath + File.separator );
+			if (!file.exists()) {
+				file.mkdirs();// 创建文件根目录
+			}
+			String orgName = mf.getOriginalFilename();// 获取文件名
+			orgName = CommonUtils.getFileName(orgName);
+			if(orgName.indexOf(".")!=-1){
+				fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.indexOf("."));
+			}else{
+				fileName = orgName+ "_" + System.currentTimeMillis();
+			}
+			String savePath = file.getPath() + File.separator + fileName;
+			File savefile = new File(savePath);
+			FileCopyUtils.copy(mf.getBytes(), savefile);
+			String dbpath = null;
+			if(oConvertUtils.isNotEmpty(bizPath)){
+				dbpath = bizPath + File.separator + fileName;
+			}else{
+				dbpath = fileName;
+			}
+			if (dbpath.contains("\\")) {
+				dbpath = dbpath.replace("\\", "/");
+			}
+			return dbpath;
+		} catch (IOException e) {
+			log.error(e.getMessage(), e);
+		}
+		return "";
+	}
 
-    }
+//	@PostMapping(value = "/upload2")
+//	public Result<?> upload2(HttpServletRequest request, HttpServletResponse response) {
+//		Result<?> result = new Result<>();
+//		try {
+//			String ctxPath = uploadpath;
+//			String fileName = null;
+//			String bizPath = "files";
+//			String tempBizPath = request.getParameter("biz");
+//			if(oConvertUtils.isNotEmpty(tempBizPath)){
+//				bizPath = tempBizPath;
+//			}
+//			String nowday = new SimpleDateFormat("yyyyMMdd").format(new Date());
+//			File file = new File(ctxPath + File.separator + bizPath + File.separator + nowday);
+//			if (!file.exists()) {
+//				file.mkdirs();// 创建文件根目录
+//			}
+//			MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+//			MultipartFile mf = multipartRequest.getFile("file");// 获取上传文件对象
+//			String orgName = mf.getOriginalFilename();// 获取文件名
+//			fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.indexOf("."));
+//			String savePath = file.getPath() + File.separator + fileName;
+//			File savefile = new File(savePath);
+//			FileCopyUtils.copy(mf.getBytes(), savefile);
+//			String dbpath = bizPath + File.separator + nowday + File.separator + fileName;
+//			if (dbpath.contains("\\")) {
+//				dbpath = dbpath.replace("\\", "/");
+//			}
+//			result.setMessage(dbpath);
+//			result.setSuccess(true);
+//		} catch (IOException e) {
+//			result.setSuccess(false);
+//			result.setMessage(e.getMessage());
+//			log.error(e.getMessage(), e);
+//		}
+//		return result;
+//	}
 
-    /**
-     * 下载文件
-     * 请求地址:http://localhost:8080/common/download/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
-     *
-     * @param request
-     * @param response
-     * @throws Exception
-     */
-    @GetMapping(value = "/download/**")
-    public void download(HttpServletRequest request, HttpServletResponse response) throws Exception {
-        // ISO-8859-1 ==> UTF-8 进行编码转换
-        String filePath = extractPathFromPattern(request);
-        // 其余处理略
-        InputStream inputStream = null;
-        OutputStream outputStream = null;
-        try {
-            filePath = filePath.replace("..", "");
-            if (filePath.endsWith(",")) {
-                filePath = filePath.substring(0, filePath.length() - 1);
-            }
-            String localPath = uploadpath;
-            String downloadFilePath = localPath + File.separator + filePath;
-            File file = new File(downloadFilePath);
-            if (file.exists()) {
-                // 设置强制下载不打开      
-                response.setContentType("application/force-download");
-                response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"), "iso-8859-1"));
-                inputStream = new BufferedInputStream(new FileInputStream(file));
-                outputStream = response.getOutputStream();
-                byte[] buf = new byte[1024];
-                int len;
-                while ((len = inputStream.read(buf)) > 0) {
-                    outputStream.write(buf, 0, len);
-                }
-                response.flushBuffer();
-            }
+	/**
+	 * 预览图片&下载文件
+	 * 请求地址:http://localhost:8080/common/static/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
+	 *
+	 * @param request
+	 * @param response
+	 */
+	@GetMapping(value = "/static/**")
+	public void view(HttpServletRequest request, HttpServletResponse response) {
+		// ISO-8859-1 ==> UTF-8 进行编码转换
+		String imgPath = extractPathFromPattern(request);
+		if(oConvertUtils.isEmpty(imgPath) || imgPath=="null"){
+			return;
+		}
+		// 其余处理略
+		InputStream inputStream = null;
+		OutputStream outputStream = null;
+		try {
+			imgPath = imgPath.replace("..", "");
+			if (imgPath.endsWith(",")) {
+				imgPath = imgPath.substring(0, imgPath.length() - 1);
+			}
+			String filePath = uploadpath + File.separator + imgPath;
+			File file = new File(filePath);
+			if(!file.exists()){
+				response.setStatus(404);
+				throw new RuntimeException("文件不存在..");
+			}
+			response.setContentType("application/force-download");// 设置强制下载不打开
+			response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"),"iso-8859-1"));
+			inputStream = new BufferedInputStream(new FileInputStream(filePath));
+			outputStream = response.getOutputStream();
+			byte[] buf = new byte[1024];
+			int len;
+			while ((len = inputStream.read(buf)) > 0) {
+				outputStream.write(buf, 0, len);
+			}
+			response.flushBuffer();
+		} catch (IOException e) {
+			log.error("预览文件失败" + e.getMessage());
+			response.setStatus(404);
+			e.printStackTrace();
+		} finally {
+			if (inputStream != null) {
+				try {
+					inputStream.close();
+				} catch (IOException e) {
+					log.error(e.getMessage(), e);
+				}
+			}
+			if (outputStream != null) {
+				try {
+					outputStream.close();
+				} catch (IOException e) {
+					log.error(e.getMessage(), e);
+				}
+			}
+		}
 
-        } catch (Exception e) {
-            log.info("文件下载失败" + e.getMessage());
-        } finally {
-            if (inputStream != null) {
-                try {
-                    inputStream.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-            if (outputStream != null) {
-                try {
-                    outputStream.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
+	}
 
-    }
+//	/**
+//	 * 下载文件
+//	 * 请求地址:http://localhost:8080/common/download/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
+//	 *
+//	 * @param request
+//	 * @param response
+//	 * @throws Exception
+//	 */
+//	@GetMapping(value = "/download/**")
+//	public void download(HttpServletRequest request, HttpServletResponse response) throws Exception {
+//		// ISO-8859-1 ==> UTF-8 进行编码转换
+//		String filePath = extractPathFromPattern(request);
+//		// 其余处理略
+//		InputStream inputStream = null;
+//		OutputStream outputStream = null;
+//		try {
+//			filePath = filePath.replace("..", "");
+//			if (filePath.endsWith(",")) {
+//				filePath = filePath.substring(0, filePath.length() - 1);
+//			}
+//			String localPath = uploadpath;
+//			String downloadFilePath = localPath + File.separator + filePath;
+//			File file = new File(downloadFilePath);
+//	         if (file.exists()) {
+//	         	response.setContentType("application/force-download");// 设置强制下载不打开            
+//	 			response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"),"iso-8859-1"));
+//	 			inputStream = new BufferedInputStream(new FileInputStream(file));
+//	 			outputStream = response.getOutputStream();
+//	 			byte[] buf = new byte[1024];
+//	 			int len;
+//	 			while ((len = inputStream.read(buf)) > 0) {
+//	 				outputStream.write(buf, 0, len);
+//	 			}
+//	 			response.flushBuffer();
+//	         }
+//
+//		} catch (Exception e) {
+//			log.info("文件下载失败" + e.getMessage());
+//			// e.printStackTrace();
+//		} finally {
+//			if (inputStream != null) {
+//				try {
+//					inputStream.close();
+//				} catch (IOException e) {
+//					e.printStackTrace();
+//				}
+//			}
+//			if (outputStream != null) {
+//				try {
+//					outputStream.close();
+//				} catch (IOException e) {
+//					e.printStackTrace();
+//				}
+//			}
+//		}
+//
+//	}
 
-    /**
-     * @param modelAndView
-     * @return
-     * @功能:pdf预览Iframe
-     */
-    @RequestMapping("/pdf/pdfPreviewIframe")
-    public ModelAndView pdfPreviewIframe(ModelAndView modelAndView) {
-        modelAndView.setViewName("pdfPreviewIframe");
-        return modelAndView;
-    }
+	/**
+	 * @功能:pdf预览Iframe
+	 * @param modelAndView
+	 * @return
+	 */
+	@RequestMapping("/pdf/pdfPreviewIframe")
+	public ModelAndView pdfPreviewIframe(ModelAndView modelAndView) {
+		modelAndView.setViewName("pdfPreviewIframe");
+		return modelAndView;
+	}
+
+	/**
+	  *  把指定URL后的字符串全部截断当成参数
+	  *  这么做是为了防止URL中包含中文或者特殊字符(/等)时,匹配不了的问题
+	 * @param request
+	 * @return
+	 */
+	private static String extractPathFromPattern(final HttpServletRequest request) {
+		String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
+		String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
+		return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
+	}
 
     /**
-     * 把指定URL后的字符串全部截断当成参数
-     * 这么做是为了防止URL中包含中文或者特殊字符(/等)时,匹配不了的问题
+     * 中转HTTP请求,解决跨域问题
      *
-     * @param request
+     * @param url 必填:请求地址
      * @return
      */
-    private static String extractPathFromPattern(final HttpServletRequest request) {
-        String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
-        String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
-        return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
+    @RequestMapping("/transitRESTful")
+    public Result transitRESTful(@RequestParam("url") String url, HttpServletRequest request) {
+        try {
+            ServletServerHttpRequest httpRequest = new ServletServerHttpRequest(request);
+            // 中转请求method、body
+            HttpMethod method = httpRequest.getMethod();
+            JSONObject params;
+            try {
+                params = JSON.parseObject(JSON.toJSONString(httpRequest.getBody()));
+            } catch (Exception e) {
+                params = new JSONObject();
+            }
+            // 中转请求问号参数
+            JSONObject variables = JSON.parseObject(JSON.toJSONString(request.getParameterMap()));
+            variables.remove("url");
+            // 在 headers 里传递Token
+            String token = TokenUtils.getTokenByRequest(request);
+            HttpHeaders headers = new HttpHeaders();
+            headers.set("X-Access-Token", token);
+            // 发送请求
+            String httpURL = URLDecoder.decode(url, "UTF-8");
+            ResponseEntity<String> response = RestUtil.request(httpURL, method, headers , variables, params, String.class);
+            // 封装返回结果
+            Result<Object> result = new Result<>();
+            int statusCode = response.getStatusCodeValue();
+            result.setCode(statusCode);
+            result.setSuccess(statusCode == 200);
+            String responseBody = response.getBody();
+            try {
+                // 尝试将返回结果转为JSON
+                Object json = JSON.parse(responseBody);
+                result.setResult(json);
+            } catch (Exception e) {
+                // 转成JSON失败,直接返回原始数据
+                result.setResult(responseBody);
+            }
+            return result;
+        } catch (Exception e) {
+            log.debug("中转HTTP请求失败", e);
+            return Result.error(e.getMessage());
+        }
     }
 
 }

+ 44 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/query/MatchTypeEnum.java

@@ -0,0 +1,44 @@
+package org.jeecg.common.system.query;
+
+import org.apache.commons.lang.StringUtils;
+import org.jeecg.common.util.oConvertUtils;
+
+/**
+ * 查询链接规则
+ *
+ * @Author Sunjianlei
+ */
+public enum MatchTypeEnum {
+
+    AND("AND"),
+    OR("OR");
+
+    private String value;
+
+    MatchTypeEnum(String value) {
+        this.value = value;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public static MatchTypeEnum getByValue(Object value) {
+        if (oConvertUtils.isEmpty(value)) {
+            return null;
+        }
+        return getByValue(value.toString());
+    }
+
+    public static MatchTypeEnum getByValue(String value) {
+        if (oConvertUtils.isEmpty(value)) {
+            return null;
+        }
+        for (MatchTypeEnum val : values()) {
+            if (val.getValue().toLowerCase().equals(value.toLowerCase())) {
+                return val;
+            }
+        }
+        return null;
+    }
+}

+ 342 - 81
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/query/QueryGenerator.java

@@ -5,11 +5,15 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.beanutils.PropertyUtils;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.DataBaseConstant;
+import org.jeecg.common.system.api.ISysBaseApi;
 import org.jeecg.common.system.util.JeecgDataAutorUtils;
 import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
+import org.jeecg.common.util.DateUtils;
 import org.jeecg.common.util.SqlInjectionUtil;
 import org.jeecg.common.util.oConvertUtils;
-import org.jeecg.modules.system.entity.SysPermissionDataRule;
+import org.jeecgframework.core.util.ApplicationContextUtil;
 import org.springframework.util.NumberUtils;
 
 import java.beans.PropertyDescriptor;
@@ -24,17 +28,25 @@ import java.util.regex.Pattern;
 
 @Slf4j
 public class QueryGenerator {
-
 	public static final String SQL_RULES_COLUMN = "SQL_RULES_COLUMN";
 
 	private static final String BEGIN = "_begin";
 	private static final String END = "_end";
+	/**
+	 * 数字类型字段,拼接此后缀 接受多值参数
+	 */
+	private static final String MULTI = "_MultiString";
 	private static final String STAR = "*";
 	private static final String COMMA = ",";
 	private static final String NOT_EQUAL = "!";
+	/**页面带有规则值查询,空格作为分隔符*/
+	private static final String QUERY_SEPARATE_KEYWORD = " ";
 	/**高级查询前端传来的参数名*/
 	private static final String SUPER_QUERY_PARAMS = "superQueryParams";
-
+	/** 高级查询前端传来的拼接方式参数名 */
+	private static final String SUPER_QUERY_MATCH_TYPE = "superQueryMatchType";
+	/** 单引号 */
+	public static final String SQL_SQ = "'";
 	/**排序列*/
 	private static final String ORDER_COLUMN = "column";
 	/**排序方式*/
@@ -42,12 +54,12 @@ public class QueryGenerator {
 	private static final String ORDER_TYPE_ASC = "ASC";
 
 	/**时间格式化 */
-    private static final ThreadLocal<SimpleDateFormat> LOCAL = new ThreadLocal<SimpleDateFormat>();
+	private static final ThreadLocal<SimpleDateFormat> local = new ThreadLocal<SimpleDateFormat>();
 	private static SimpleDateFormat getTime(){
-        SimpleDateFormat time = LOCAL.get();
+		SimpleDateFormat time = local.get();
 		if(time == null){
-			time = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
-            LOCAL.set(time);
+			time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+			local.set(time);
 		}
 		return time;
 	}
@@ -68,9 +80,9 @@ public class QueryGenerator {
 
 	/**
 	 * 组装Mybatis Plus 查询条件
-     * <p>使用此方法 需要有如下几点注意:
+	 * <p>使用此方法 需要有如下几点注意:
 	 * <br>1.使用QueryWrapper 而非LambdaQueryWrapper;
-     * <br>2.实例化QueryWrapper时不可将实体传入参数
+	 * <br>2.实例化QueryWrapper时不可将实体传入参数
 	 * <br>错误示例:如QueryWrapper<JeecgDemo> queryWrapper = new QueryWrapper<JeecgDemo>(jeecgDemo);
 	 * <br>正确示例:QueryWrapper<JeecgDemo> queryWrapper = new QueryWrapper<JeecgDemo>();
 	 * <br>3.也可以不使用这个方法直接调用 {@link #initQueryWrapper}直接获取实例
@@ -84,8 +96,8 @@ public class QueryGenerator {
 		*/
 
 		//区间条件组装 模糊查询 高级查询组装 简单排序 权限查询
-		PropertyDescriptor[] origDescriptors = PropertyUtils.getPropertyDescriptors(searchObj);
-		Map<String,SysPermissionDataRule> ruleMap = getRuleMap();
+		PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(searchObj);
+		Map<String,SysPermissionDataRuleModel> ruleMap = getRuleMap();
 
 		//权限规则自定义SQL表达式
 		for (String c : ruleMap.keySet()) {
@@ -115,13 +127,18 @@ public class QueryGenerator {
 					beginValue = parameterMap.get(name + BEGIN)[0].trim();
 					addQueryByRule(queryWrapper, name, type, beginValue, QueryRuleEnum.GE);
 
-                }
+				}
 				if (parameterMap != null && parameterMap.containsKey(name + END)) {
 					endValue = parameterMap.get(name + END)[0].trim();
 					addQueryByRule(queryWrapper, name, type, endValue, QueryRuleEnum.LE);
 				}
+				//多值查询
+				if (parameterMap != null && parameterMap.containsKey(name + MULTI)) {
+					endValue = parameterMap.get(name + MULTI)[0].trim();
+					addQueryByRule(queryWrapper, name.replace(MULTI,""), type, endValue, QueryRuleEnum.IN);
+				}
 
-                //判断单值  参数带不同标识字符串 走不同的查询
+				//判断单值  参数带不同标识字符串 走不同的查询
 				//TODO 这种前后带逗号的支持分割后模糊查询需要否 使多选字段的查询生效
 				Object value = PropertyUtils.getSimpleProperty(searchObj, name);
 				if (null != value && value.toString().startsWith(COMMA) && value.toString().endsWith(COMMA)) {
@@ -143,25 +160,28 @@ public class QueryGenerator {
 					//根据参数值带什么关键字符串判断走什么类型的查询
 					QueryRuleEnum rule = convert2Rule(value);
 					value = replaceValue(rule,value);
+					// add -begin 添加判断为字符串时设为全模糊查询
+					//if( (rule==null || QueryRuleEnum.EQ.equals(rule)) && "class java.lang.String".equals(type)) {
+						// 可以设置左右模糊或全模糊,因人而异
+						//rule = QueryRuleEnum.LIKE;
+					//}
+					// add -end 添加判断为字符串时设为全模糊查询
 					addEasyQuery(queryWrapper, name, rule, value);
 				}
 
-            } catch (Exception e) {
+			} catch (Exception e) {
 				log.error(e.getMessage(), e);
 			}
 		}
-        // 排序逻辑 处理
+		// 排序逻辑 处理
 		doMultiFieldsOrder(queryWrapper, parameterMap);
 
-        //高级查询
+		//高级查询
 		doSuperQuery(queryWrapper, parameterMap);
 
-    }
+	}
 
-    /**
-     * 多字段排序
-     * TODO 需要修改前端
-     */
+	//多字段排序 TODO 需要修改前端
 	public static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap) {
 		String column=null,order=null;
 		if(parameterMap!=null&& parameterMap.containsKey(ORDER_COLUMN)) {
@@ -177,7 +197,7 @@ public class QueryGenerator {
 				column = column.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX));
 			}
 			//SQL注入check
-            SqlInjectionUtil.filterContent(column);
+			SqlInjectionUtil.filterContent(column);
 
 			if (order.toUpperCase().indexOf(ORDER_TYPE_ASC)>=0) {
 				queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column));
@@ -187,7 +207,7 @@ public class QueryGenerator {
 		}
 	}
 
-    /**
+	/**
 	 * 高级查询
 	 * @param queryWrapper
 	 * @param parameterMap
@@ -195,21 +215,43 @@ public class QueryGenerator {
 	public static void doSuperQuery(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap) {
 		if(parameterMap!=null&& parameterMap.containsKey(SUPER_QUERY_PARAMS)){
 			String superQueryParams = parameterMap.get(SUPER_QUERY_PARAMS)[0];
-			// 解码
-			try {
-				superQueryParams = URLDecoder.decode(superQueryParams, "UTF-8");
-			} catch (UnsupportedEncodingException e) {
-				log.error("--高级查询参数转码失败!", e);
-			}
-			List<QueryCondition> conditions = JSON.parseArray(superQueryParams, QueryCondition.class);
-			log.info("---高级查询参数-->"+conditions.toString());
-
-            for (QueryCondition rule : conditions) {
-				if(oConvertUtils.isNotEmpty(rule.getField()) && oConvertUtils.isNotEmpty(rule.getRule()) && oConvertUtils.isNotEmpty(rule.getVal())){
-					addEasyQuery(queryWrapper, rule.getField(), QueryRuleEnum.getByValue(rule.getRule()), rule.getVal());
-				}
-			}
+			String superQueryMatchType = parameterMap.get(SUPER_QUERY_MATCH_TYPE) != null ? parameterMap.get(SUPER_QUERY_MATCH_TYPE)[0] : MatchTypeEnum.AND.getValue();
+            MatchTypeEnum matchType = MatchTypeEnum.getByValue(superQueryMatchType);
+            // update-begin--Author:sunjianlei  Date:20200325 for:高级查询的条件要用括号括起来,防止和用户的其他条件冲突 -------
+            try {
+                superQueryParams = URLDecoder.decode(superQueryParams, "UTF-8");
+                List<QueryCondition> conditions = JSON.parseArray(superQueryParams, QueryCondition.class);
+                if (conditions == null || conditions.size() == 0) {
+                    return;
+                }
+                log.info("---高级查询参数-->" + conditions.toString());
+                queryWrapper.and(andWrapper -> {
+                    for (int i = 0; i < conditions.size(); i++) {
+                        QueryCondition rule = conditions.get(i);
+                        if (oConvertUtils.isNotEmpty(rule.getField())
+                                && oConvertUtils.isNotEmpty(rule.getRule())
+                                && oConvertUtils.isNotEmpty(rule.getVal())) {
+
+                            log.debug("SuperQuery ==> " + rule.toString());
+                            addEasyQuery(andWrapper, rule.getField(), QueryRuleEnum.getByValue(rule.getRule()), rule.getVal());
+
+                            // 如果拼接方式是OR,就拼接OR
+                            if (MatchTypeEnum.OR == matchType && i < (conditions.size() - 1)) {
+                                andWrapper.or();
+                            }
+                        }
+                    }
+                    return andWrapper;
+                });
+            } catch (UnsupportedEncodingException e) {
+                log.error("--高级查询参数转码失败:" + superQueryParams, e);
+            } catch (Exception e) {
+                log.error("--高级查询拼接失败:" + e.getMessage());
+                e.printStackTrace();
+            }
+            // update-end--Author:sunjianlei  Date:20200325 for:高级查询的条件要用括号括起来,防止和用户的其他条件冲突 -------
 		}
+		//log.info(" superQuery getCustomSqlSegment: "+ queryWrapper.getCustomSqlSegment());
 	}
 	/**
 	 * 根据所传的值 转化成对应的比较方式
@@ -217,7 +259,7 @@ public class QueryGenerator {
 	 * @param value
 	 * @return
 	 */
-	public static QueryRuleEnum convert2Rule(Object value) {
+	private static QueryRuleEnum convert2Rule(Object value) {
 		// 避免空数据
 		if (value == null) {
 			return null;
@@ -227,16 +269,24 @@ public class QueryGenerator {
 			return null;
 		}
 		QueryRuleEnum rule =null;
+
+		//update-begin--Author:scott  Date:20190724 for:initQueryWrapper组装sql查询条件错误 #284-------------------
+		//TODO 此处规则,只适用于 le lt ge gt
 		// step 2 .>= =<
-		if (rule == null && val.length() >= 2) {
-			rule = QueryRuleEnum.getByValue(val.substring(0, 2));
+		if (rule == null && val.length() >= 3) {
+			if(QUERY_SEPARATE_KEYWORD.equals(val.substring(2, 3))){
+				rule = QueryRuleEnum.getByValue(val.substring(0, 2));
+			}
 		}
 		// step 1 .> <
-		if (rule == null && val.length() >= 1) {
-			rule = QueryRuleEnum.getByValue(val.substring(0, 1));
+		if (rule == null && val.length() >= 2) {
+			if(QUERY_SEPARATE_KEYWORD.equals(val.substring(1, 2))){
+				rule = QueryRuleEnum.getByValue(val.substring(0, 1));
+			}
 		}
+		//update-end--Author:scott  Date:20190724 for:initQueryWrapper组装sql查询条件错误 #284---------------------
 
-        // step 3 like
+		// step 3 like
 		if (rule == null && val.contains(STAR)) {
 			if (val.startsWith(STAR) && val.endsWith(STAR)) {
 				rule = QueryRuleEnum.LIKE;
@@ -251,21 +301,21 @@ public class QueryGenerator {
 			//TODO in 查询这里应该有个bug  如果一字段本身就是多选 此时用in查询 未必能查询出来
 			rule = QueryRuleEnum.IN;
 		}
-        // step 5 !=
+		// step 5 !=
 		if(rule == null && val.startsWith(NOT_EQUAL)){
 			rule = QueryRuleEnum.NE;
 		}
 		return rule != null ? rule : QueryRuleEnum.EQ;
 	}
 
-    /**
+	/**
 	 * 替换掉关键字字符
-     *
+	 *
 	 * @param rule
 	 * @param value
 	 * @return
 	 */
-	public static Object replaceValue(QueryRuleEnum rule, Object value) {
+	private static Object replaceValue(QueryRuleEnum rule, Object value) {
 		if (rule == null) {
 			return null;
 		}
@@ -280,16 +330,30 @@ public class QueryGenerator {
 		} else if (rule == QueryRuleEnum.RIGHT_LIKE) {
 			value = val.substring(0, val.length() - 1);
 		} else if (rule == QueryRuleEnum.IN) {
-            value = val.split(COMMA);
+			value = val.split(",");
 		} else {
-			value = val.replace(rule.getValue(),"");
+			//update-begin--Author:scott  Date:20190724 for:initQueryWrapper组装sql查询条件错误 #284-------------------
+			if(val.startsWith(rule.getValue())){
+				//TODO 此处逻辑应该注释掉-> 如果查询内容中带有查询匹配规则符号,就会被截取的(比如:>=您好)
+				value = val.replaceFirst(rule.getValue(),"");
+			}else if(val.startsWith(rule.getCondition()+QUERY_SEPARATE_KEYWORD)){
+				value = val.replaceFirst(rule.getCondition()+QUERY_SEPARATE_KEYWORD,"").trim();
+			}
+			//update-end--Author:scott  Date:20190724 for:initQueryWrapper组装sql查询条件错误 #284-------------------
 		}
 		return value;
 	}
 
-    private static void addQueryByRule(QueryWrapper<?> queryWrapper,String name,String type,String value,QueryRuleEnum rule) throws ParseException {
-		if(!"".equals(value)) {
+	private static void addQueryByRule(QueryWrapper<?> queryWrapper,String name,String type,String value,QueryRuleEnum rule) throws ParseException {
+		if(oConvertUtils.isNotEmpty(value)) {
 			Object temp;
+			// 针对数字类型字段,多值查询
+			if(value.indexOf(COMMA)!=-1){
+				temp = value;
+				addEasyQuery(queryWrapper, name, rule, temp);
+				return;
+			}
+
 			switch (type) {
 			case "class java.lang.Integer":
 				temp =  Integer.parseInt(value);
@@ -320,7 +384,7 @@ public class QueryGenerator {
 		}
 	}
 
-    /**
+	/**
 	 * 获取日期类型的值
 	 * @param value
 	 * @param rule
@@ -345,7 +409,7 @@ public class QueryGenerator {
 		return date;
 	}
 
-    /**
+	/**
 	  * 根据规则走不同的查询
 	 * @param queryWrapper QueryWrapper
 	 * @param name         字段名字
@@ -353,11 +417,10 @@ public class QueryGenerator {
 	 * @param value        查询条件值
 	 */
 	private static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) {
-		if (value == null || rule == null) {
+		if (value == null || rule == null || oConvertUtils.isEmpty(value)) {
 			return;
 		}
 		name = oConvertUtils.camelToUnderline(name);
-//		log.info("--查询规则-->"+name+" "+rule.getValue()+" "+value);
 		switch (rule) {
 		case GT:
 			queryWrapper.gt(name, value);
@@ -379,7 +442,7 @@ public class QueryGenerator {
 			break;
 		case IN:
 			if(value instanceof String) {
-                queryWrapper.in(name, (Object[]) value.toString().split(COMMA));
+				queryWrapper.in(name, (Object[])value.toString().split(","));
 			}else if(value instanceof String[]) {
 				queryWrapper.in(name, (Object[]) value);
 			}else {
@@ -401,7 +464,7 @@ public class QueryGenerator {
 		}
 	}
 	/**
-     *
+	 *
 	 * @param name
 	 * @return
 	 */
@@ -412,18 +475,19 @@ public class QueryGenerator {
 	}
 
 
-    /**
-     *
+
+	/**
+	 * 获取请求对应的数据权限规则
 	 * @return
 	 */
-	public static Map<String, SysPermissionDataRule> getRuleMap() {
-		Map<String, SysPermissionDataRule> ruleMap = new HashMap<String, SysPermissionDataRule>();
-		List<SysPermissionDataRule> list =JeecgDataAutorUtils.loadDataSearchConditon();
+	public static Map<String, SysPermissionDataRuleModel> getRuleMap() {
+		Map<String, SysPermissionDataRuleModel> ruleMap = new HashMap<String, SysPermissionDataRuleModel>();
+		List<SysPermissionDataRuleModel> list =JeecgDataAutorUtils.loadDataSearchConditon();
 		if(list != null&&list.size()>0){
 			if(list.get(0)==null){
 				return ruleMap;
 			}
-			for (SysPermissionDataRule rule : list) {
+			for (SysPermissionDataRuleModel rule : list) {
 				String column = rule.getRuleColumn();
 				if(QueryRuleEnum.SQL_RULES.getValue().equals(rule.getRuleConditions())) {
 					column = SQL_RULES_COLUMN+rule.getId();
@@ -434,10 +498,10 @@ public class QueryGenerator {
 		return ruleMap;
 	}
 
-    private static void addRuleToQueryWrapper(SysPermissionDataRule dataRule,String name, Class propertyType, QueryWrapper<?> queryWrapper) {
+	private static void addRuleToQueryWrapper(SysPermissionDataRuleModel dataRule, String name, Class propertyType, QueryWrapper<?> queryWrapper) {
 		QueryRuleEnum rule = QueryRuleEnum.getByValue(dataRule.getRuleConditions());
 		if(rule.equals(QueryRuleEnum.IN) && ! propertyType.equals(String.class)) {
-            String[] values = dataRule.getRuleValue().split(COMMA);
+			String[] values = dataRule.getRuleValue().split(",");
 			Object[] objs = new Object[values.length];
 			for (int i = 0; i < values.length; i++) {
 				objs[i] = NumberUtils.parseNumber(values[i], propertyType);
@@ -446,13 +510,20 @@ public class QueryGenerator {
 		}else {
 			if (propertyType.equals(String.class)) {
 				addEasyQuery(queryWrapper, name, rule, converRuleValue(dataRule.getRuleValue()));
-			} else {
+			}else if (propertyType.equals(Date.class)) {
+				String dateStr =converRuleValue(dataRule.getRuleValue());
+				if(dateStr.length()==10){
+					addEasyQuery(queryWrapper, name, rule, DateUtils.str2Date(dateStr,DateUtils.date_sdf.get()));
+				}else{
+					addEasyQuery(queryWrapper, name, rule, DateUtils.str2Date(dateStr,DateUtils.datetimeFormat.get()));
+				}
+			}else {
 				addEasyQuery(queryWrapper, name, rule, NumberUtils.parseNumber(dataRule.getRuleValue(), propertyType));
 			}
 		}
 	}
 
-    public static String converRuleValue(String ruleValue) {
+	public static String converRuleValue(String ruleValue) {
 		String value = JwtUtil.getSessionData(ruleValue);
 		if(oConvertUtils.isEmpty(value)) {
 			value = JwtUtil.getUserSystemData(ruleValue,null);
@@ -460,7 +531,27 @@ public class QueryGenerator {
 		return value!= null ? value : ruleValue;
 	}
 
-    public static String getSqlRuleValue(String sqlRule){
+	/**
+	* @author: scott
+	* @Description: 去掉值前后单引号
+	* @date: 2020/3/19 21:26
+	* @param ruleValue:
+	* @Return: java.lang.String
+	*/
+	public static String trimSingleQuote(String ruleValue) {
+		if (oConvertUtils.isEmpty(ruleValue)) {
+			return "";
+		}
+		if (ruleValue.startsWith(QueryGenerator.SQL_SQ)) {
+			ruleValue = ruleValue.substring(1);
+		}
+		if (ruleValue.endsWith(QueryGenerator.SQL_SQ)) {
+			ruleValue = ruleValue.substring(0, ruleValue.length() - 1);
+		}
+		return ruleValue;
+	}
+
+	public static String getSqlRuleValue(String sqlRule){
 		try {
 			Set<String> varParams = getSqlRuleParams(sqlRule);
 			for(String var:varParams){
@@ -473,7 +564,7 @@ public class QueryGenerator {
 		return sqlRule;
 	}
 
-    /**
+	/**
 	 * 获取sql中的#{key} 这个key组成的set
 	 */
 	public static Set<String> getSqlRuleParams(String sql) {
@@ -483,7 +574,7 @@ public class QueryGenerator {
 		Set<String> varParams = new HashSet<String>();
 		String regex = "\\#\\{\\w+\\}";
 
-        Pattern p = Pattern.compile(regex);
+		Pattern p = Pattern.compile(regex);
 		Matcher m = p.matcher(sql);
 		while(m.find()){
 			String var = m.group();
@@ -492,8 +583,8 @@ public class QueryGenerator {
 		return varParams;
 	}
 
-    /**
-     * 获取查询条件
+	/**
+	 * 获取查询条件
 	 * @param field
 	 * @param alias
 	 * @param value
@@ -506,6 +597,10 @@ public class QueryGenerator {
 		}
 		field =  alias+oConvertUtils.camelToUnderline(field);
 		QueryRuleEnum rule = QueryGenerator.convert2Rule(value);
+		return getSingleSqlByRule(rule, field, value, isString);
+	}
+
+	public static String getSingleSqlByRule(QueryRuleEnum rule,String field,Object value,boolean isString) {
 		String res = "";
 		switch (rule) {
 		case GT:
@@ -558,18 +653,26 @@ public class QueryGenerator {
 			str = str.substring(1);
 		}
 		if(isString) {
-			return " '"+str+"' ";
+			if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
+				return " N'"+str+"' ";
+			}else{
+				return " '"+str+"' ";
+			}
 		}else {
 			return value.toString();
 		}
 	}
 
-    private static String getInConditionValue(Object value,boolean isString) {
+	private static String getInConditionValue(Object value,boolean isString) {
 		if(isString) {
-            String[] temp = value.toString().split(COMMA);
+			String temp[] = value.toString().split(",");
 			String res="";
 			for (String string : temp) {
-				res+=",'"+string+"'";
+				if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
+					res+=",N'"+string+"'";
+				}else{
+					res+=",'"+string+"'";
+				}
 			}
 			return "("+res.substring(1)+")";
 		}else {
@@ -577,18 +680,176 @@ public class QueryGenerator {
 		}
 	}
 
-    private static String getLikeConditionValue(Object value) {
+	private static String getLikeConditionValue(Object value) {
 		String str = value.toString().trim();
 		if(str.startsWith("*") && str.endsWith("*")) {
-			return "'%"+str.substring(1,str.length()-1)+"%'";
+			if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
+				return "N'%"+str.substring(1,str.length()-1)+"%'";
+			}else{
+				return "'%"+str.substring(1,str.length()-1)+"%'";
+			}
 		}else if(str.startsWith("*")) {
-			return "'%"+str.substring(1)+"'";
+			if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
+				return "N'%"+str.substring(1)+"'";
+			}else{
+				return "'%"+str.substring(1)+"'";
+			}
 		}else if(str.endsWith("*")) {
-			return "'"+str.substring(0,str.length()-1)+"%'";
+			if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
+				return "N'"+str.substring(0,str.length()-1)+"%'";
+			}else{
+				return "'"+str.substring(0,str.length()-1)+"%'";
+			}
 		}else {
-			return str;
+			if(str.indexOf("%")>=0) {
+				if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
+					if(str.startsWith("'") && str.endsWith("'")){
+						return "N"+str;
+					}else{
+						return "N"+"'"+str+"'";
+					}
+				}else{
+					if(str.startsWith("'") && str.endsWith("'")){
+						return str;
+					}else{
+						return "'"+str+"'";
+					}
+				}
+			}else {
+				if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
+					return "N'%"+str+"%'";
+				}else{
+					return "'%"+str+"%'";
+				}
+			}
+		}
+	}
+
+	/**
+	 *   根据权限相关配置生成相关的SQL 语句
+	 * @return
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public static String installAuthJdbc(Class<?> clazz) {
+		StringBuffer sb = new StringBuffer();
+		//权限查询
+		Map<String,SysPermissionDataRuleModel> ruleMap = getRuleMap();
+		PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(clazz);
+		String sql_and = " and ";
+		for (String c : ruleMap.keySet()) {
+			if(oConvertUtils.isNotEmpty(c) && c.startsWith(SQL_RULES_COLUMN)){
+				sb.append(sql_and+getSqlRuleValue(ruleMap.get(c).getRuleValue()));
+			}
+		}
+		String name;
+		for (int i = 0; i < origDescriptors.length; i++) {
+			name = origDescriptors[i].getName();
+			if (judgedIsUselessField(name)) {
+				continue;
+			}
+			if(ruleMap.containsKey(name)) {
+				SysPermissionDataRuleModel dataRule = ruleMap.get(name);
+				QueryRuleEnum rule = QueryRuleEnum.getByValue(dataRule.getRuleConditions());
+				Class propType = origDescriptors[i].getPropertyType();
+				boolean isString = propType.equals(String.class);
+				Object value;
+				if(isString) {
+					value = converRuleValue(dataRule.getRuleValue());
+				}else {
+					value = NumberUtils.parseNumber(dataRule.getRuleValue(),propType);
+				}
+				String filedSql = getSingleSqlByRule(rule, oConvertUtils.camelToUnderline(name), value,isString);
+				sb.append(sql_and+filedSql);
+			}
+		}
+		log.info("query auth sql is:"+sb.toString());
+		return sb.toString();
+	}
+
+	/**
+	  * 根据权限相关配置 组装mp需要的权限
+	 * @return
+	 */
+	public static void installAuthMplus(QueryWrapper<?> queryWrapper,Class<?> clazz) {
+		//权限查询
+		Map<String,SysPermissionDataRuleModel> ruleMap = getRuleMap();
+		PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(clazz);
+		for (String c : ruleMap.keySet()) {
+			if(oConvertUtils.isNotEmpty(c) && c.startsWith(SQL_RULES_COLUMN)){
+				queryWrapper.and(i ->i.apply(getSqlRuleValue(ruleMap.get(c).getRuleValue())));
+			}
+		}
+		String name;
+		for (int i = 0; i < origDescriptors.length; i++) {
+			name = origDescriptors[i].getName();
+			if (judgedIsUselessField(name)) {
+				continue;
+			}
+			if(ruleMap.containsKey(name)) {
+				addRuleToQueryWrapper(ruleMap.get(name), name, origDescriptors[i].getPropertyType(), queryWrapper);
+			}
 		}
 	}
 
+	/**
+	 * 转换sql中的系统变量
+	 * @param sql
+	 * @return
+	 */
+	public static String convertSystemVariables(String sql){
+		return getSqlRuleValue(sql);
+	}
 
+	/**
+	 * 获取所有配置的权限 返回sql字符串 不受字段限制 配置什么就拿到什么
+	 * @return
+	 */
+	public static String getAllConfigAuth() {
+		StringBuffer sb = new StringBuffer();
+		//权限查询
+		Map<String,SysPermissionDataRuleModel> ruleMap = getRuleMap();
+		String sql_and = " and ";
+		for (String c : ruleMap.keySet()) {
+			SysPermissionDataRuleModel dataRule = ruleMap.get(c);
+			String ruleValue = dataRule.getRuleValue();
+			if(oConvertUtils.isEmpty(ruleValue)){
+				continue;
+			}
+			if(oConvertUtils.isNotEmpty(c) && c.startsWith(SQL_RULES_COLUMN)){
+				sb.append(sql_and+getSqlRuleValue(ruleValue));
+			}else{
+				boolean isString  = false;
+				ruleValue = ruleValue.trim();
+				if(ruleValue.startsWith("'") && ruleValue.endsWith("'")){
+					isString = true;
+					ruleValue = ruleValue.substring(1,ruleValue.length()-1);
+				}
+				QueryRuleEnum rule = QueryRuleEnum.getByValue(dataRule.getRuleConditions());
+				String value = converRuleValue(ruleValue);
+				String filedSql = getSingleSqlByRule(rule, c, value,isString);
+				sb.append(sql_and+filedSql);
+			}
+		}
+		log.info("query auth sql is = "+sb.toString());
+		return sb.toString();
+	}
+
+	/** 当前系统数据库类型 */
+	private static String DB_TYPE;
+	/**
+	 * 获取系统数据库类型
+	 */
+	private static String getDbType(){
+		if(oConvertUtils.isNotEmpty(DB_TYPE)){
+			return DB_TYPE;
+		}
+		try {
+			ISysBaseApi sysBaseAPI = ApplicationContextUtil.getContext().getBean(ISysBaseApi.class);
+			DB_TYPE = sysBaseAPI.getDatabaseType();
+			return DB_TYPE;
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return DB_TYPE;
+	}
 }

+ 1 - 3
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/query/QueryRuleEnum.java

@@ -8,9 +8,7 @@ import org.jeecg.common.util.oConvertUtils;
  * @Date 2019年02月14日
  */
 public enum QueryRuleEnum {
-    /**
-     * Query 规则 常量
-     */
+
     GT(">","gt","大于"),
     GE(">=","ge","大于等于"),
     LT("<","lt","小于"),

+ 18 - 20
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/util/JeecgDataAutorUtils.java

@@ -1,15 +1,14 @@
 package org.jeecg.common.system.util;
 
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-
+import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
 import org.jeecg.common.system.vo.SysUserCacheInfo;
 import org.jeecg.common.util.SpringContextUtils;
-import org.jeecg.modules.system.entity.SysPermissionDataRule;
 import org.springframework.util.StringUtils;
 
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * @ClassName: JeecgDataAutorUtils
  * @Description: 数据权限查询规则容器工具类
@@ -29,40 +28,38 @@ public class JeecgDataAutorUtils {
 	 * 往链接请求里面,传入数据查询条件
 	 * 
 	 * @param request
-     * @param dataRules
+	 * @param dataRules
 	 */
-	public static synchronized void installDataSearchConditon(HttpServletRequest request, List<SysPermissionDataRule> dataRules) {
+	public static synchronized void installDataSearchConditon(HttpServletRequest request, List<SysPermissionDataRuleModel> dataRules) {
 		@SuppressWarnings("unchecked")
-        // 1.先从request获取MENU_DATA_AUTHOR_RULES,如果存则获取到LIST
-                List<SysPermissionDataRule> list = (List<SysPermissionDataRule>) loadDataSearchConditon();
+		List<SysPermissionDataRuleModel> list = (List<SysPermissionDataRuleModel>)loadDataSearchConditon();// 1.先从request获取MENU_DATA_AUTHOR_RULES,如果存则获取到LIST
 		if (list==null) {
 			// 2.如果不存在,则new一个list
-			list = new ArrayList<SysPermissionDataRule>();
+			list = new ArrayList<SysPermissionDataRuleModel>();
 		}
-		for (SysPermissionDataRule tsDataRule : dataRules) {
+		for (SysPermissionDataRuleModel tsDataRule : dataRules) {
 			list.add(tsDataRule);
 		}
-        // 3.往list里面增量存指
-        request.setAttribute(MENU_DATA_AUTHOR_RULES, list);
+		request.setAttribute(MENU_DATA_AUTHOR_RULES, list); // 3.往list里面增量存指
 	}
 
 	/**
 	 * 获取请求对应的数据权限规则
-     *
+	 * 
 	 * @return
 	 */
 	@SuppressWarnings("unchecked")
-	public static synchronized List<SysPermissionDataRule> loadDataSearchConditon() {
-		return (List<SysPermissionDataRule>) SpringContextUtils.getHttpServletRequest().getAttribute(MENU_DATA_AUTHOR_RULES);
+	public static synchronized List<SysPermissionDataRuleModel> loadDataSearchConditon() {
+		return (List<SysPermissionDataRuleModel>) SpringContextUtils.getHttpServletRequest().getAttribute(MENU_DATA_AUTHOR_RULES);
 				
 	}
 
 	/**
 	 * 获取请求对应的数据权限SQL
-     *
+	 * 
 	 * @return
 	 */
-    public static synchronized String loadDataSearchConditonSqlString() {
+	public static synchronized String loadDataSearchConditonSQLString() {
 		return (String) SpringContextUtils.getHttpServletRequest().getAttribute(MENU_DATA_AUTHOR_RULE_SQL);
 	}
 
@@ -70,9 +67,10 @@ public class JeecgDataAutorUtils {
 	 * 往链接请求里面,传入数据查询条件
 	 * 
 	 * @param request
+	 * @param sql
 	 */
 	public static synchronized void installDataSearchConditon(HttpServletRequest request, String sql) {
-        String ruleSql = (String) loadDataSearchConditonSqlString();
+		String ruleSql = (String)loadDataSearchConditonSQLString();
 		if (!StringUtils.hasText(ruleSql)) {
 			request.setAttribute(MENU_DATA_AUTHOR_RULE_SQL,sql);
 		}

+ 179 - 182
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/util/JwtUtil.java

@@ -6,6 +6,11 @@ import com.auth0.jwt.algorithms.Algorithm;
 import com.auth0.jwt.exceptions.JWTDecodeException;
 import com.auth0.jwt.interfaces.DecodedJWT;
 import com.google.common.base.Joiner;
+
+import java.util.Date;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.constant.DataBaseConstant;
 import org.jeecg.common.exception.JeecgBootException;
@@ -14,10 +19,6 @@ import org.jeecg.common.system.vo.SysUserCacheInfo;
 import org.jeecg.common.util.SpringContextUtils;
 import org.jeecg.common.util.oConvertUtils;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
-import java.util.Date;
-
 /**
  * @Author Scott
  * @Date 2018-07-12 14:23
@@ -25,182 +26,178 @@ import java.util.Date;
  **/
 public class JwtUtil {
 
-    /**
-     * 过期时间30分钟
-     */
-    public static final long EXPIRE_TIME = 30 * 60 * 1000;
-
-    /**
-     * 校验token是否正确
-     *
-     * @param token  密钥
-     * @param secret 用户的密码
-     * @return 是否正确
-     */
-    public static boolean verify(String token, String username, String secret) {
-        try {
-            // 根据密码生成JWT效验器
-            Algorithm algorithm = Algorithm.HMAC256(secret);
-            JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
-            // 效验TOKEN
-            DecodedJWT jwt = verifier.verify(token);
-            return true;
-        } catch (Exception exception) {
-            return false;
-        }
-    }
-
-    /**
-     * 获得token中的信息无需secret解密也能获得
-     *
-     * @return token中包含的用户名
-     */
-    public static String getUsername(String token) {
-        try {
-            DecodedJWT jwt = JWT.decode(token);
-            return jwt.getClaim("username").asString();
-        } catch (JWTDecodeException e) {
-            return null;
-        }
-    }
-
-    /**
-     * 生成签名,5min后过期
-     *
-     * @param username 用户名
-     * @param secret   用户的密码
-     * @return 加密的token
-     */
-    public static String sign(String username, String secret) {
-        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
-        Algorithm algorithm = Algorithm.HMAC256(secret);
-        // 附带username信息
-        return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
-
-    }
-
-    /**
-     * 根据request中的token获取用户账号
-     *
-     * @param request
-     * @return
-     * @throws JeecgBootException
-     */
-    public static String getUserNameByToken(HttpServletRequest request) throws JeecgBootException {
-        String accessToken = request.getHeader("X-Access-Token");
-        String username = getUsername(accessToken);
-        if (oConvertUtils.isEmpty(username)) {
-            throw new JeecgBootException("未获取到用户");
-        }
-        return username;
-    }
-
-    /**
-     * 从session中获取变量
-     *
-     * @param key
-     * @return
-     */
-    public static String getSessionData(String key) {
-        //${myVar}%
-        //得到${} 后面的值
-        String moshi = "";
-        if (key.indexOf("}") != -1) {
-            moshi = key.substring(key.indexOf("}") + 1);
-        }
-        String returnValue = null;
-        if (key.contains("#{")) {
-            key = key.substring(2, key.indexOf("}"));
-        }
-        if (oConvertUtils.isNotEmpty(key)) {
-            HttpSession session = SpringContextUtils.getHttpServletRequest().getSession();
-            returnValue = (String) session.getAttribute(key);
-        }
-        //结果加上${} 后面的值
-        if (returnValue != null) {
-            returnValue = returnValue + moshi;
-        }
-        return returnValue;
-    }
-
-    /**
-     * 从当前用户中获取变量
-     *
-     * @param key
-     * @param user
-     * @return
-     */
-
-    //TODO 急待改造 sckjkdsjsfjdk
-    public static String getUserSystemData(String key, SysUserCacheInfo user) {
-        if (user == null) {
-            user = JeecgDataAutorUtils.loadUserInfo();
-        }
-        //#{sys_user_code}%
-
-        // 获取登录用户信息
-        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-
-        String moshi = "";
-        if (key.indexOf("}") != -1) {
-            moshi = key.substring(key.indexOf("}") + 1);
-        }
-        String returnValue = null;
-        //针对特殊标示处理#{sysOrgCode},判断替换
-        if (key.contains("#{")) {
-            key = key.substring(2, key.indexOf("}"));
-        } else {
-            key = key;
-        }
-        //替换为系统登录用户帐号
-        if (key.equals(DataBaseConstant.SYS_USER_CODE) || key.equals(DataBaseConstant.SYS_USER_CODE_TABLE)) {
-            if (user == null) {
-                returnValue = sysUser.getUsername();
-            } else {
-                returnValue = user.getSysUserCode();
-            }
-        }
-        //替换为系统登录用户真实名字
-        if (key.equals(DataBaseConstant.SYS_USER_NAME) || key.equals(DataBaseConstant.SYS_USER_NAME_TABLE)) {
-            if (user == null) {
-                returnValue = sysUser.getRealname();
-            } else {
-                returnValue = user.getSysUserName();
-            }
-        }
-
-        //替换为系统用户登录所使用的机构编码
-        if (key.equals(DataBaseConstant.SYS_ORG_CODE) || key.equals(DataBaseConstant.SYS_ORG_CODE_TABLE)) {
-            if (user == null) {
-                returnValue = sysUser.getOrgCode();
-            } else {
-                returnValue = user.getSysOrgCode();
-            }
-
-        }
-        //替换为系统用户所拥有的所有机构编码
-        if (key.equals(DataBaseConstant.SYS_MULTI_ORG_CODE) || key.equals(DataBaseConstant.SYS_MULTI_ORG_CODE)) {
-            if (user.isOneDepart()) {
-                returnValue = user.getSysMultiOrgCode().get(0);
-            } else {
-                returnValue = Joiner.on(",").join(user.getSysMultiOrgCode());
-            }
-        }
-        //替换为当前系统时间(年月日)
-        if (key.equals(DataBaseConstant.SYS_DATE) || key.equals(DataBaseConstant.SYS_DATE_TABLE)) {
-            returnValue = user.getSysDate();
-        }
-        //替换为当前系统时间(年月日时分秒)
-        if (key.equals(DataBaseConstant.SYS_TIME) || key.equals(DataBaseConstant.SYS_TIME_TABLE)) {
-            returnValue = user.getSysTime();
-        }
-        //流程状态默认值(默认未发起)
-        if (key.equals(DataBaseConstant.BPM_STATUS_TABLE) || key.equals(DataBaseConstant.BPM_STATUS_TABLE)) {
-            returnValue = "1";
-        }
-        if (returnValue != null) {
-            returnValue = returnValue + moshi;
-        }
-        return returnValue;
-    }
+	// Token过期时间30分钟(用户登录过期时间是此时间的两倍,以token在reids缓存时间为准)
+	//public static final long EXPIRE_TIME = 30 * 60 * 1000;
+	public static final long EXPIRE_TIME = 8* 60 * 60 * 1000;
+
+	/**
+	 * 校验token是否正确
+	 *
+	 * @param token  密钥
+	 * @param secret 用户的密码
+	 * @return 是否正确
+	 */
+	public static boolean verify(String token, String username, String secret) {
+		try {
+			// 根据密码生成JWT效验器
+			Algorithm algorithm = Algorithm.HMAC256(secret);
+			JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
+			// 效验TOKEN
+			DecodedJWT jwt = verifier.verify(token);
+			return true;
+		} catch (Exception exception) {
+			return false;
+		}
+	}
+
+	/**
+	 * 获得token中的信息无需secret解密也能获得
+	 *
+	 * @return token中包含的用户名
+	 */
+	public static String getUsername(String token) {
+		try {
+			DecodedJWT jwt = JWT.decode(token);
+			return jwt.getClaim("username").asString();
+		} catch (JWTDecodeException e) {
+			return null;
+		}
+	}
+
+	/**
+	 * 生成签名,5min后过期
+	 *
+	 * @param username 用户名
+	 * @param secret   用户的密码
+	 * @return 加密的token
+	 */
+	public static String sign(String username, String secret) {
+		Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
+		Algorithm algorithm = Algorithm.HMAC256(secret);
+		// 附带username信息
+		return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
+
+	}
+
+	/**
+	 * 根据request中的token获取用户账号
+	 * 
+	 * @param request
+	 * @return
+	 * @throws JeecgBootException
+	 */
+	public static String getUserNameByToken(HttpServletRequest request) throws JeecgBootException {
+		String accessToken = request.getHeader("X-Access-Token");
+		String username = getUsername(accessToken);
+		if (oConvertUtils.isEmpty(username)) {
+			throw new JeecgBootException("未获取到用户");
+		}
+		return username;
+	}
+	
+	/**
+	  *  从session中获取变量
+	 * @param key
+	 * @return
+	 */
+	public static String getSessionData(String key) {
+		//${myVar}%
+		//得到${} 后面的值
+		String moshi = "";
+		if(key.indexOf("}")!=-1){
+			 moshi = key.substring(key.indexOf("}")+1);
+		}
+		String returnValue = null;
+		if (key.contains("#{")) {
+			key = key.substring(2,key.indexOf("}"));
+		}
+		if (oConvertUtils.isNotEmpty(key)) {
+			HttpSession session = SpringContextUtils.getHttpServletRequest().getSession();
+			returnValue = (String) session.getAttribute(key);
+		}
+		//结果加上${} 后面的值
+		if(returnValue!=null){returnValue = returnValue + moshi;}
+		return returnValue;
+	}
+	
+	/**
+	  * 从当前用户中获取变量
+	 * @param key
+	 * @param user
+	 * @return
+	 */
+	//TODO 急待改造 sckjkdsjsfjdk
+	public static String getUserSystemData(String key,SysUserCacheInfo user) {
+		if(user==null) {
+			user = JeecgDataAutorUtils.loadUserInfo();
+		}
+		//#{sys_user_code}%
+		
+		// 获取登录用户信息
+		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+		
+		String moshi = "";
+		if(key.indexOf("}")!=-1){
+			 moshi = key.substring(key.indexOf("}")+1);
+		}
+		String returnValue = null;
+		//针对特殊标示处理#{sysOrgCode},判断替换
+		if (key.contains("#{")) {
+			key = key.substring(2,key.indexOf("}"));
+		} else {
+			key = key;
+		}
+		//替换为系统登录用户帐号
+		if (key.equals(DataBaseConstant.SYS_USER_CODE)|| key.toLowerCase().equals(DataBaseConstant.SYS_USER_CODE_TABLE)) {
+			if(user==null) {
+				returnValue = sysUser.getUsername();
+			}else {
+				returnValue = user.getSysUserCode();
+			}
+		}
+		//替换为系统登录用户真实名字
+		else if (key.equals(DataBaseConstant.SYS_USER_NAME)|| key.toLowerCase().equals(DataBaseConstant.SYS_USER_NAME_TABLE)) {
+			if(user==null) {
+				returnValue = sysUser.getRealname();
+			}else {
+				returnValue = user.getSysUserName();
+			}
+		}
+		
+		//替换为系统用户登录所使用的机构编码
+		else if (key.equals(DataBaseConstant.SYS_ORG_CODE)|| key.toLowerCase().equals(DataBaseConstant.SYS_ORG_CODE_TABLE)) {
+			if(user==null) {
+				returnValue = sysUser.getOrgCode();
+			}else {
+				returnValue = user.getSysOrgCode();
+			}
+		}
+		//替换为系统用户所拥有的所有机构编码
+		else if (key.equals(DataBaseConstant.SYS_MULTI_ORG_CODE)|| key.toLowerCase().equals(DataBaseConstant.SYS_MULTI_ORG_CODE_TABLE)) {
+			if(user.isOneDepart()) {
+				returnValue = user.getSysMultiOrgCode().get(0);
+			}else {
+				returnValue = Joiner.on(",").join(user.getSysMultiOrgCode());
+			}
+		}
+		//替换为当前系统时间(年月日)
+		else if (key.equals(DataBaseConstant.SYS_DATE)|| key.toLowerCase().equals(DataBaseConstant.SYS_DATE_TABLE)) {
+			returnValue = user.getSysDate();
+		}
+		//替换为当前系统时间(年月日时分秒)
+		else if (key.equals(DataBaseConstant.SYS_TIME)|| key.toLowerCase().equals(DataBaseConstant.SYS_TIME_TABLE)) {
+			returnValue = user.getSysTime();
+		}
+		//流程状态默认值(默认未发起)
+		else if (key.equals(DataBaseConstant.BPM_STATUS)|| key.toLowerCase().equals(DataBaseConstant.BPM_STATUS_TABLE)) {
+			returnValue = "1";
+		}
+		if(returnValue!=null){returnValue = returnValue + moshi;}
+		return returnValue;
+	}
+	
+	public static void main(String[] args) {
+		 String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjUzMzY1MTMsInVzZXJuYW1lIjoiYWRtaW4ifQ.xjhud_tWCNYBOg_aRlMgOdlZoWFFKB_givNElHNw3X0";
+		 System.out.println(JwtUtil.getUsername(token));
+	}
 }

+ 3 - 1
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/DictModel.java

@@ -2,6 +2,8 @@ package org.jeecg.common.system.vo;
 
 import java.io.Serializable;
 
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
@@ -9,10 +11,10 @@ import lombok.experimental.Accessors;
 @Data
 @EqualsAndHashCode(callSuper = false)
 @Accessors(chain = true)
+@JsonIgnoreProperties(ignoreUnknown = true)
 public class DictModel implements Serializable{
 	private static final long serialVersionUID = 1L;
 
-
 	public DictModel() {
 	}
 	

+ 8 - 8
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/DynamicDataSourceModel.java

@@ -19,34 +19,34 @@ public class DynamicDataSourceModel {
     /**
      * id
      */
-    private String id;
+    private java.lang.String id;
     /**
      * 数据源编码
      */
-    private String code;
+    private java.lang.String code;
     /**
      * 数据库类型
      */
-    private String dbType;
+    private java.lang.String dbType;
     /**
      * 驱动类
      */
-    private String dbDriver;
+    private java.lang.String dbDriver;
     /**
      * 数据源地址
      */
-    private String dbUrl;
+    private java.lang.String dbUrl;
     /**
      * 数据库名称
      */
-    private String dbName;
+    private java.lang.String dbName;
     /**
      * 用户名
      */
-    private String dbUsername;
+    private java.lang.String dbUsername;
     /**
      * 密码
      */
-    private String dbPassword;
+    private java.lang.String dbPassword;
 
 }

+ 13 - 14
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/LoginUser.java

@@ -1,14 +1,13 @@
 package org.jeecg.common.system.vo;
 
-import java.util.Date;
-
-import org.springframework.format.annotation.DateTimeFormat;
-
 import com.fasterxml.jackson.annotation.JsonFormat;
-
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
 
 /**
  * <p>
@@ -21,8 +20,8 @@ import lombok.experimental.Accessors;
 @Data
 @EqualsAndHashCode(callSuper = false)
 @Accessors(chain = true)
-public class LoginUser {
-
+public class LoginUser implements Serializable {
+	private static final long serialVersionUID = 1L;
 	/**
 	 * 登录人id
 	 */
@@ -43,10 +42,10 @@ public class LoginUser {
 	 */
 	private String password;
 
-	/**
-	 * 当前登录部门code
-	 */
-	private String orgCode;
+     /**
+      * 当前登录部门code
+      */
+    private String orgCode;
 	/**
 	 * 头像
 	 */
@@ -81,9 +80,9 @@ public class LoginUser {
 
 	private Integer delFlag;
 	/**
-	 * 同步工作流引擎1同步0不同步
-	 */
-	private Integer activitiSync;
+     * 同步工作流引擎1同步0不同步
+     */
+    private Integer activitiSync;
 
 	/**
 	 * 创建时间

+ 6 - 4
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/SysCategoryModel.java

@@ -1,5 +1,7 @@
 package org.jeecg.common.system.vo;
 
+import org.jeecgframework.poi.excel.annotation.Excel;
+
 /**
  * @Author qinfeng
  * @Date 2020/2/19 12:01
@@ -8,13 +10,13 @@ package org.jeecg.common.system.vo;
  */
 public class SysCategoryModel {
     /**主键*/
-    private String id;
+    private java.lang.String id;
     /**父级节点*/
-    private String pid;
+    private java.lang.String pid;
     /**类型名称*/
-    private String name;
+    private java.lang.String name;
     /**类型编码*/
-    private String code;
+    private java.lang.String code;
 
     public String getId() {
         return id;

+ 7 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/SysPermissionDataRuleModel.java

@@ -1,5 +1,12 @@
 package org.jeecg.common.system.vo;
 
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
 import java.util.Date;
 
 /**

+ 43 - 47
jeecg-boot-base-common/src/main/java/org/jeecg/common/system/vo/SysUserCacheInfo.java

@@ -1,71 +1,67 @@
 package org.jeecg.common.system.vo;
 
-import org.jeecg.common.util.DateUtils;
-
 import java.util.List;
 
-/**
- * @author jeecg-boot
- * 2019年12月5日19:57:58
- */
+import org.jeecg.common.util.DateUtils;
+
 public class SysUserCacheInfo {
 
-    private String sysUserCode;
+	private String sysUserCode;
 
-    private String sysUserName;
+	private String sysUserName;
 
-    private String sysOrgCode;
+	private String sysOrgCode;
 
-    private List<String> sysMultiOrgCode;
+	private List<String> sysMultiOrgCode;
 
-    private boolean oneDepart;
+	private boolean oneDepart;
 
-    public boolean isOneDepart() {
-        return oneDepart;
-    }
+	public boolean isOneDepart() {
+		return oneDepart;
+	}
 
-    public void setOneDepart(boolean oneDepart) {
-        this.oneDepart = oneDepart;
-    }
+	public void setOneDepart(boolean oneDepart) {
+		this.oneDepart = oneDepart;
+	}
 
-    public String getSysDate() {
-        return DateUtils.formatDate();
-    }
+	public String getSysDate() {
+		return DateUtils.formatDate();
+	}
 
-    public String getSysTime() {
-        return DateUtils.now();
-    }
+	public String getSysTime() {
+		return DateUtils.now();
+	}
 
-    public String getSysUserCode() {
-        return sysUserCode;
-    }
+	public String getSysUserCode() {
+		return sysUserCode;
+	}
 
-    public void setSysUserCode(String sysUserCode) {
-        this.sysUserCode = sysUserCode;
-    }
+	public void setSysUserCode(String sysUserCode) {
+		this.sysUserCode = sysUserCode;
+	}
 
-    public String getSysUserName() {
-        return sysUserName;
-    }
+	public String getSysUserName() {
+		return sysUserName;
+	}
 
-    public void setSysUserName(String sysUserName) {
-        this.sysUserName = sysUserName;
-    }
+	public void setSysUserName(String sysUserName) {
+		this.sysUserName = sysUserName;
+	}
 
-    public String getSysOrgCode() {
-        return sysOrgCode;
-    }
+	public String getSysOrgCode() {
+		return sysOrgCode;
+	}
 
-    public void setSysOrgCode(String sysOrgCode) {
-        this.sysOrgCode = sysOrgCode;
-    }
+	public void setSysOrgCode(String sysOrgCode) {
+		this.sysOrgCode = sysOrgCode;
+	}
 
-    public List<String> getSysMultiOrgCode() {
-        return sysMultiOrgCode;
-    }
+	public List<String> getSysMultiOrgCode() {
+		return sysMultiOrgCode;
+	}
 
-    public void setSysMultiOrgCode(List<String> sysMultiOrgCode) {
-        this.sysMultiOrgCode = sysMultiOrgCode;
-    }
+	public void setSysMultiOrgCode(List<String> sysMultiOrgCode) {
+		this.sysMultiOrgCode = sysMultiOrgCode;
+	}
 
 }

+ 15 - 5
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/BrowserUtils.java

@@ -14,10 +14,8 @@ import javax.servlet.http.HttpServletRequest;
  */
 public class BrowserUtils {
 
-    /**
-     * 判断是否是IE
-     */
-    public static boolean isIe(HttpServletRequest request) {
+	// 判断是否是IE
+	public static boolean isIE(HttpServletRequest request) {
 		return (request.getHeader("USER-AGENT").toLowerCase().indexOf("msie") > 0 || request
 				.getHeader("USER-AGENT").toLowerCase().indexOf("rv:11.0") > 0) ? true
 				: false;
@@ -29,7 +27,7 @@ public class BrowserUtils {
 	 * @param request
 	 * @return
 	 */
-    public static Double getIeVersion(HttpServletRequest request) {
+	public static Double getIEversion(HttpServletRequest request) {
 		Double version = 0.0;
 		if (getBrowserType(request, IE11)) {
 			version = 11.0;
@@ -193,4 +191,16 @@ public class BrowserUtils {
 		return browserLangCode;
 	}
 
+    /** 判断请求是否来自电脑端 */
+    public static boolean isDesktop(HttpServletRequest request) {
+        return !isMobile(request);
+    }
+
+    /** 判断请求是否来自移动端 */
+    public static boolean isMobile(HttpServletRequest request) {
+        String ua = request.getHeader("User-Agent").toLowerCase();
+        Pattern pattern = Pattern.compile("(phone|pad|pod|iphone|ipod|ios|ipad|android|mobile|blackberry|iemobile|mqqbrowser|juc|fennec|wosbrowser|browserng|webos|symbian|windows phone)");
+        return pattern.matcher(ua).find();
+    }
+
 }

+ 167 - 140
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/DateUtils.java

@@ -23,21 +23,64 @@ public class DateUtils extends PropertyEditorSupport {
 
     private static Logger logger = LoggerFactory.getLogger(DateUtils.class);
 
-    /**
-     * 以毫秒表示的时间
-     */
+    public static ThreadLocal<SimpleDateFormat> date_sdf = new ThreadLocal<SimpleDateFormat>() {
+        @Override
+        protected SimpleDateFormat initialValue() {
+            return new SimpleDateFormat("yyyy-MM-dd");
+        }
+    };
+    public static ThreadLocal<SimpleDateFormat> yyyyMMdd = new ThreadLocal<SimpleDateFormat>() {
+        @Override
+        protected SimpleDateFormat initialValue() {
+            return new SimpleDateFormat("yyyyMMdd");
+        }
+    };
+    public static ThreadLocal<SimpleDateFormat> date_sdf_wz = new ThreadLocal<SimpleDateFormat>() {
+        @Override
+        protected SimpleDateFormat initialValue() {
+            return new SimpleDateFormat("yyyy年MM月dd日");
+        }
+    };
+    public static ThreadLocal<SimpleDateFormat> time_sdf = new ThreadLocal<SimpleDateFormat>() {
+        @Override
+        protected SimpleDateFormat initialValue() {
+            return new SimpleDateFormat("yyyy-MM-dd HH:mm");
+        }
+    };
+    public static ThreadLocal<SimpleDateFormat> yyyymmddhhmmss = new ThreadLocal<SimpleDateFormat>() {
+        @Override
+        protected SimpleDateFormat initialValue() {
+            return new SimpleDateFormat("yyyyMMddHHmmss");
+        }
+    };
+    public static ThreadLocal<SimpleDateFormat> short_time_sdf = new ThreadLocal<SimpleDateFormat>() {
+        @Override
+        protected SimpleDateFormat initialValue() {
+            return new SimpleDateFormat("HH:mm");
+        }
+    };
+    public static ThreadLocal<SimpleDateFormat> datetimeFormat = new ThreadLocal<SimpleDateFormat>() {
+        @Override
+        protected SimpleDateFormat initialValue() {
+            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        }
+    };
+
+    // 以毫秒表示的时间
     private static final long DAY_IN_MILLIS = 24 * 3600 * 1000L;
     private static final long HOUR_IN_MILLIS = 3600 * 1000L;
     private static final long MINUTE_IN_MILLIS = 60 * 1000L;
     private static final long SECOND_IN_MILLIS = 1000L;
 
+    public static String getNowHour(Date date) {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH");
+        return simpleDateFormat.format(date);
+    }
 
     public static Date getNowDate() throws ParseException {
         SimpleDateFormat dsdf = new SimpleDateFormat("yyyy-MM-dd");
         String nowDate = getNowDate("yyyy-MM-dd");
-        Date parse = dsdf.parse(nowDate);
-        return parse;
-
+        return dsdf.parse(nowDate);
     }
 
 
@@ -47,28 +90,14 @@ public class DateUtils extends PropertyEditorSupport {
         //将字符串形式的时间转化为Date类型的时间
         Date a = sdf.parse(beginDate);
         Date b = sdf.parse(nowDate);
-        //Date类的一个方法,如果a早于b返回true,否则返回false
-        if (a.before(b)) {
-            return true;
-        } else {
-            return false;
-        }
-
-		/*
-		 * 如果你不喜欢用上面这个太流氓的方法,也可以根据将Date转换成毫秒
-		if(a.getTime()-b.getTime()<0)
-			return true;
-		else
-			return false;
-		*/
+        return a.before(b);
     }
 
 
     public static String getDateByDateStr(String dateStr) throws ParseException {
         SimpleDateFormat dsdf = new SimpleDateFormat("yyyy-MM-dd");
         Date parse = dsdf.parse(dateStr);
-        String day = dsdf.format(parse);
-        return day;
+        return dsdf.format(parse);
     }
 
     public static Integer getHour(String dateStr) throws ParseException {
@@ -76,10 +105,27 @@ public class DateUtils extends PropertyEditorSupport {
         Calendar cal = Calendar.getInstance();
         Date date = sdf.parse(dateStr);
         cal.setTime(date);
-        Integer hour = cal.get(Calendar.HOUR_OF_DAY);
-        return hour;
+        return cal.get(Calendar.HOUR_OF_DAY);
+    }
 
+    public static String getEndTime(String time) throws ParseException {
+        SimpleDateFormat smf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date parse = smf.parse(time);
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(parse);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.add(Calendar.DAY_OF_MONTH, 1);
+        calendar.add(Calendar.SECOND, -1);
+        Date end = calendar.getTime();
+        String format = smf.format(end);
+        return format;
+    }
 
+    // 指定模式的时间格式
+    private static SimpleDateFormat getSDFormat(String pattern) {
+        return new SimpleDateFormat(pattern);
     }
 
     /**
@@ -93,6 +139,41 @@ public class DateUtils extends PropertyEditorSupport {
     }
 
     /**
+     * 日期转换为字符串
+     *
+     * @return 字符串
+     */
+    public static String date2Str() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+        return format.format(new Date());
+    }
+
+    public static List<Map<String, String>> getDateDayRange(String startDate, String endDate) throws ParseException {
+        List<Map<String, String>> list = new ArrayList<>();
+        String splitDate = DateUtils.addDay(endDate, -1);
+        splitDate = DateUtils.addDay(splitDate, 1);
+        if (DateUtils.compareDate(startDate, splitDate) >= 0) {
+            Map<String, String> map = new HashMap<String, String>();
+            map.put("startDate", startDate);
+            map.put("endDate", endDate);
+            list.add(map);
+        } else {
+            while (DateUtils.compareDate(startDate, splitDate) < 0 || DateUtils.compareDate(startDate, endDate) <= 0) {
+                Map<String, String> map = new HashMap<>();
+                map.put("startDate", splitDate);
+                map.put("endDate", endDate);
+                list.add(map);
+                splitDate = DateUtils.addDay(splitDate, -1);
+                endDate = DateUtils.addDay(endDate, -1);
+                if (DateUtils.compareDate(startDate, splitDate) > 0) {
+                    splitDate = startDate;
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
      * 当前日历,这里用中国时间表示
      *
      * @return 以当地时区表示的系统当前日历
@@ -100,7 +181,6 @@ public class DateUtils extends PropertyEditorSupport {
     public static Calendar getCalendar() {
         return Calendar.getInstance();
     }
-
     /**
      * 指定毫秒数表示的日历
      *
@@ -113,20 +193,6 @@ public class DateUtils extends PropertyEditorSupport {
         return cal;
     }
 
-    // ////////////////////////////////////////////////////////////////////////////
-    // getDate
-    // 各种方式获取的Date
-    // ////////////////////////////////////////////////////////////////////////////
-
-    /**
-     * 当前日期
-     *
-     * @return 系统当前时间
-     */
-    public static Date getDate() {
-        return new Date();
-    }
-
     /**
      * 字符串转换成日期
      *
@@ -147,17 +213,31 @@ public class DateUtils extends PropertyEditorSupport {
         }
         return null;
     }
-
+    /**
+     * 当前日期
+     *
+     * @return 系统当前时间
+     * @param l
+     */
+    public static Date getDate(long l) {
+        return new Date();
+    }
     /**
      * 日期转换为字符串
      *
+     * @param date_sdf 日期格式
      * @return 字符串
      */
-    public static String date2Str() {
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
-        return format.format(new Date());
+    public static String date2Str(SimpleDateFormat date_sdf) {
+        Date date = getDate();
+        if (null == date) {
+            return null;
+        }
+        return date_sdf.format(date);
+    }
+    public static Date getDate() {
+        return new Date();
     }
-
     /**
      * 格式化时间
      *
@@ -223,8 +303,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 当前时间的标准形式字符串
      */
     public static String now() {
-        SimpleDateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        return datetimeFormat.format(getCalendar().getTime());
+        return datetimeFormat.get().format(getCalendar().getTime());
     }
 
     /**
@@ -251,8 +330,7 @@ public class DateUtils extends PropertyEditorSupport {
         Date dt = new Date();
         DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         String nowTime = df.format(dt);
-        Timestamp buydate = Timestamp.valueOf(nowTime);
-        return buydate;
+        return Timestamp.valueOf(nowTime);
     }
 
     // ////////////////////////////////////////////////////////////////////////////
@@ -310,8 +388,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 默认日期按“年-月-日“格式显示
      */
     public static String formatDate() {
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
-        return format.format(getCalendar().getTime());
+        return date_sdf.get().format(getCalendar().getTime());
     }
 
     /**
@@ -320,8 +397,14 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 默认日期按“yyyy-MM-dd HH:mm:ss“格式显示
      */
     public static String formatDateTime() {
-        SimpleDateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        return datetimeFormat.format(getCalendar().getTime());
+        return datetimeFormat.get().format(getCalendar().getTime());
+    }
+
+    /**
+     * 获取时间字符串
+     */
+    public static String getDataString(SimpleDateFormat formatstr) {
+        return formatstr.format(getCalendar().getTime());
     }
 
     /**
@@ -331,8 +414,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 指定日期按“年-月-日“格式显示
      */
     public static String formatDate(Calendar cal) {
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
-        return format.format(cal.getTime());
+        return date_sdf.get().format(cal.getTime());
     }
 
     /**
@@ -342,8 +424,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 指定日期按“年-月-日“格式显示
      */
     public static String formatDate(Date date) {
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
-        return format.format(date);
+        return date_sdf.get().format(date);
     }
 
     /**
@@ -353,8 +434,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 指定毫秒数表示日期按“年-月-日“格式显示
      */
     public static String formatDate(long millis) {
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
-        return format.format(new Date(millis));
+        return date_sdf.get().format(new Date(millis));
     }
 
     /**
@@ -364,7 +444,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 默认日期按指定格式显示
      */
     public static String formatDate(String pattern) {
-        return getDateFormat(pattern).format(getCalendar().getTime());
+        return getSDFormat(pattern).format(getCalendar().getTime());
     }
 
     /**
@@ -375,7 +455,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 指定日期按指定格式显示
      */
     public static String formatDate(Calendar cal, String pattern) {
-        return getDateFormat(pattern).format(cal.getTime());
+        return getSDFormat(pattern).format(cal.getTime());
     }
 
     /**
@@ -386,7 +466,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 指定日期按指定格式显示
      */
     public static String formatDate(Date date, String pattern) {
-        return getDateFormat(pattern).format(date);
+        return getSDFormat(pattern).format(date);
     }
 
     // ////////////////////////////////////////////////////////////////////////////
@@ -400,8 +480,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 默认日期按“年-月-日 时:分“格式显示
      */
     public static String formatTime() {
-        SimpleDateFormat timeSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
-        return timeSdf.format(getCalendar().getTime());
+        return time_sdf.get().format(getCalendar().getTime());
     }
 
     /**
@@ -411,8 +490,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 指定毫秒数表示日期按“年-月-日 时:分“格式显示
      */
     public static String formatTime(long millis) {
-        SimpleDateFormat timeSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
-        return timeSdf.format(new Date(millis));
+        return time_sdf.get().format(new Date(millis));
     }
 
     /**
@@ -422,8 +500,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 指定日期按“年-月-日 时:分“格式显示
      */
     public static String formatTime(Calendar cal) {
-        SimpleDateFormat timeSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
-        return timeSdf.format(cal.getTime());
+        return time_sdf.get().format(cal.getTime());
     }
 
     /**
@@ -433,8 +510,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 指定日期按“年-月-日 时:分“格式显示
      */
     public static String formatTime(Date date) {
-        SimpleDateFormat timeSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
-        return timeSdf.format(date);
+        return time_sdf.get().format(date);
     }
 
     // ////////////////////////////////////////////////////////////////////////////
@@ -448,8 +524,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 默认日期按“时:分“格式显示
      */
     public static String formatShortTime() {
-        SimpleDateFormat shortTimeSdf = new SimpleDateFormat("HH:mm");
-        return shortTimeSdf.format(getCalendar().getTime());
+        return short_time_sdf.get().format(getCalendar().getTime());
     }
 
     /**
@@ -459,8 +534,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @return 指定毫秒数表示日期按“时:分“格式显示
      */
     public static String formatShortTime(long millis) {
-        SimpleDateFormat shortTimeSdf = new SimpleDateFormat("HH:mm");
-        return shortTimeSdf.format(new Date(millis));
+        return short_time_sdf.get().format(new Date(millis));
     }
 
     /**
@@ -516,10 +590,9 @@ public class DateUtils extends PropertyEditorSupport {
      * @param src     将要转换的原始字符窜
      * @param pattern 转换的匹配格式
      * @return 如果转换成功则返回转换后的日期
-     * @throws ParseException
      * @throws
      */
-    public static Calendar parseCalendar(String src, String pattern) throws ParseException {
+    public static Calendar parseCalendar(String src, String pattern){
 
         Date date = parseDate(src, pattern);
         Calendar cal = Calendar.getInstance();
@@ -527,7 +600,7 @@ public class DateUtils extends PropertyEditorSupport {
         return cal;
     }
 
-    public static String formatAddDate(String src, String pattern, int amount) throws ParseException {
+    public static String formatAddDate(String src, String pattern, int amount) {
         Calendar cal;
         cal = parseCalendar(src, pattern);
         cal.add(Calendar.DATE, amount);
@@ -543,7 +616,7 @@ public class DateUtils extends PropertyEditorSupport {
      * @throws ParseException
      * @throws
      */
-    public static Timestamp parseTimestamp(String src, String pattern) throws ParseException {
+    public static Timestamp parseTimestamp(String src, String pattern) {
         Date date = parseDate(src, pattern);
         return new Timestamp(date.getTime());
     }
@@ -593,13 +666,10 @@ public class DateUtils extends PropertyEditorSupport {
         SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
         Date date = sdf1.parse(createTime);
         SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        String str = sdf2.format(date);
-
-        return str;
+        return sdf2.format(date);
     }
 
     public static Map<String, Object> getStartEndTime(String createTime) throws ParseException {
-
         SimpleDateFormat smf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         Date parse = smf.parse(createTime);
         Calendar calendar = Calendar.getInstance();
@@ -646,7 +716,7 @@ public class DateUtils extends PropertyEditorSupport {
      * HH:mm:ss“ * @param text String类型的时间值
      */
     @Override
-    public void setAsText(String text) throws IllegalArgumentException {
+    public void setAsText(String text) {
         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
         SimpleDateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         if (StringUtils.hasText(text)) {
@@ -687,43 +757,18 @@ public class DateUtils extends PropertyEditorSupport {
         }
     }
 
-    public static List<Map<String, String>> getDateDayRange(String startDate, String endDate) throws ParseException {
-        List<Map<String, String>> list = new ArrayList<>();
-        String splitDate = DateUtils.addDay(endDate, -1);
-        splitDate = DateUtils.addDay(splitDate, 1);
-        if (DateUtils.compareDate(startDate, splitDate) >= 0) {
-            Map<String, String> map = new HashMap<String, String>();
-            map.put("startDate", startDate);
-            map.put("endDate", endDate);
-            list.add(map);
-        } else {
-            while (DateUtils.compareDate(startDate, splitDate) < 0 || DateUtils.compareDate(startDate, endDate) <= 0) {
-                Map<String, String> map = new HashMap<String, String>();
-                map.put("startDate", splitDate);
-                map.put("endDate", endDate);
-                list.add(map);
-                splitDate = DateUtils.addDay(splitDate, -1);
-                endDate = DateUtils.addDay(endDate, -1);
-                if (DateUtils.compareDate(startDate, splitDate) > 0) {
-                    splitDate = startDate;
-                }
-            }
-        }
-        return list;
-    }
-
     public static List<Map<String, String>> getDateWeekRange(String startDate, String endDate) throws ParseException {
-        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
+        List<Map<String, String>> list = new ArrayList<>();
         String splitDate = DateUtils.addWeek(endDate, -1);
         splitDate = DateUtils.addDay(splitDate, 1);
         if (DateUtils.compareDate(startDate, splitDate) >= 0) {
-            Map<String, String> map = new HashMap<String, String>();
+            Map<String, String> map = new HashMap<>();
             map.put("startDate", startDate);
             map.put("endDate", endDate);
             list.add(map);
         } else {
             while (DateUtils.compareDate(startDate, splitDate) < 0 || DateUtils.compareDate(startDate, endDate) <= 0) {
-                Map<String, String> map = new HashMap<String, String>();
+                Map<String, String> map = new HashMap<>();
                 map.put("startDate", splitDate);
                 map.put("endDate", endDate);
                 list.add(map);
@@ -738,17 +783,17 @@ public class DateUtils extends PropertyEditorSupport {
     }
 
     public static List<Map<String, String>> getDateMonthRange(String startDate, String endDate) throws ParseException {
-        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
+        List<Map<String, String>> list = new ArrayList<>();
         String splitDate = DateUtils.addMonth(endDate, -1);
         splitDate = DateUtils.addDay(splitDate, 1);
         if (DateUtils.compareDate(startDate, splitDate) >= 0) {
-            Map<String, String> map = new HashMap<String, String>();
+            Map<String, String> map = new HashMap<>();
             map.put("startDate", startDate);
             map.put("endDate", endDate);
             list.add(map);
         } else {
             while (DateUtils.compareDate(startDate, splitDate) < 0 || DateUtils.compareDate(startDate, endDate) <= 0) {
-                Map<String, String> map = new HashMap<String, String>();
+                Map<String, String> map = new HashMap<>();
                 map.put("startDate", splitDate);
                 map.put("endDate", endDate);
                 list.add(map);
@@ -844,11 +889,10 @@ public class DateUtils extends PropertyEditorSupport {
 
     public static Map<String, Object> getBeforeDate() {
         Date dNow = new Date();
-        Date dBefore = new Date();
         Calendar calendar = Calendar.getInstance();
         calendar.setTime(dNow);
         calendar.add(Calendar.DAY_OF_MONTH, -1);
-        dBefore = calendar.getTime();
+        Date dBefore = calendar.getTime();
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
         String defaultStartDate = sdf.format(dBefore);
         defaultStartDate = defaultStartDate + " 00:00:00";
@@ -865,7 +909,6 @@ public class DateUtils extends PropertyEditorSupport {
      * @param date   传入的初始日期
      * @param num    天数
      * @return
-     * @throws ParseException
      */
     public static String getAnotherDay(String format, String date, Integer num) {
 
@@ -914,8 +957,6 @@ public class DateUtils extends PropertyEditorSupport {
     }
 
     public static Map<String, Object> compareDate(String format, String date1, String date2) {
-
-
         DateFormat df = new SimpleDateFormat(format);
         Map<String, Object> map = new HashMap<>();
         try {
@@ -945,11 +986,9 @@ public class DateUtils extends PropertyEditorSupport {
      * @throws ParseException
      */
     public static String getYear(String format, String date) throws ParseException {
-
         SimpleDateFormat df = new SimpleDateFormat(format);
         Date parse = df.parse(date);
         return String.format("%tY", parse);
-
     }
 
     /**
@@ -975,7 +1014,6 @@ public class DateUtils extends PropertyEditorSupport {
      * @throws ParseException
      */
     public static String getDay(String format, String date) throws ParseException {
-
         SimpleDateFormat df = new SimpleDateFormat(format);
         Date parse = df.parse(date);
         return String.format("%td", parse);
@@ -1016,7 +1054,6 @@ public class DateUtils extends PropertyEditorSupport {
         calendar.setTime(date);
         calendar.setFirstDayOfWeek(Calendar.FRIDAY);
         calendar.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
-        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
         return calendar.getTime();
     }
 
@@ -1026,13 +1063,12 @@ public class DateUtils extends PropertyEditorSupport {
      */
     public static Map<String, Integer> getYearQuarter(Date date) {
         Map<String, Integer> dateMap = new HashMap<>();
-
         Calendar calendar = new GregorianCalendar();
         calendar.setTime(date);
         int originYear = calendar.get(Calendar.YEAR);
         int originMonth = calendar.get(Calendar.MONTH);
-        int originQuarter = DateUtils.getQuarter(date); //本月所在季度(按照日期来的)
-
+        //本月所在季度(按照日期来的)
+        int originQuarter = DateUtils.getQuarter(date);
         Calendar calendar1 = new GregorianCalendar();
         calendar1.setTime(date);
         calendar1.setFirstDayOfWeek(Calendar.FRIDAY);
@@ -1054,7 +1090,8 @@ public class DateUtils extends PropertyEditorSupport {
         //如果本周第一天(周五)和当前天不在一个月内,说明周跨月了
         if (fridayMonth == originMonth && thursdayMonth == originMonth) {
             dateMap.put("year", originYear);
-            dateMap.put("month", originMonth + 1);  //最后一个月是11,应该+1
+            //最后一个月是11,应该+1
+            dateMap.put("month", originMonth + 1);
             dateMap.put("quarter", originQuarter);
             return dateMap;
         } else if (fridayYear < originYear || (fridayYear == originYear && fridayMonth < originMonth)) {
@@ -1248,14 +1285,10 @@ public class DateUtils extends PropertyEditorSupport {
         startCalendar.setTime(start);
         GregorianCalendar endCalendar = new GregorianCalendar();
         endCalendar.setTime(end);
-
         int startYear = startCalendar.get(Calendar.YEAR);
         int startMonth = startCalendar.get(Calendar.MONTH) + 1;
-        int startDay = startCalendar.get(Calendar.DAY_OF_MONTH);
         int endYear = endCalendar.get(Calendar.YEAR);
         int endMonth = endCalendar.get(Calendar.MONTH) + 1;
-        int endDay = endCalendar.get(Calendar.DAY_OF_MONTH);
-
         return (endYear - startYear) * 12 + (endMonth - startMonth);
     }
 
@@ -1317,30 +1350,24 @@ public class DateUtils extends PropertyEditorSupport {
         return (int) betweenDate;
     }
 
-    public static Date addMonth(Date date) {
-        Calendar calendar = Calendar.getInstance();//日历对象
-        calendar.add(Calendar.MONTH, -1);//月份减一
-        return calendar.getTime();
-    }
-
     /**
      * 判断两个日期间隔是否大于半年
      *
      * @return
      */
-    public static boolean isMoreSixMonth(String startDate, String endDate) {
+    public static boolean isMoreSixMonth(String startDate, String endDate) throws ParseException {
         Calendar c = Calendar.getInstance();
         c.setTime(Objects.requireNonNull(parseDate(startDate, SystemDateConstant.yyyy_MM_dd)));
         long time1 = c.getTimeInMillis();
         c.setTime(Objects.requireNonNull(parseDate(endDate, SystemDateConstant.yyyy_MM_dd)));
         long time2 = c.getTimeInMillis();
-        long between_days = (time2 - time1) / (1000 * 3600 * 24);
-        int day = Integer.parseInt(String.valueOf(between_days));
+        long betweenDays = (time2 - time1) / (1000 * 3600 * 24);
+        int day = Integer.parseInt(String.valueOf(betweenDays));
         return day > 180;
     }
 
     public static List<Date> findDates(Date dBegin, Date dEnd) {
-        List<Date> lDate = new ArrayList<Date>();
+        List<Date> lDate = new ArrayList<>();
         lDate.add(dBegin);
         Calendar calBegin = Calendar.getInstance();
         // 使用给定的 Date 设置此 Calendar 的时间

+ 66 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/DySmsEnum.java

@@ -0,0 +1,66 @@
+package org.jeecg.common.util;
+
+import org.apache.commons.lang.StringUtils;
+
+public enum DySmsEnum {
+	
+	LOGIN_TEMPLATE_CODE("SMS_175435174","JEECG","code"),
+	FORGET_PASSWORD_TEMPLATE_CODE("SMS_175435174","JEECG","code"),
+	REGISTER_TEMPLATE_CODE("SMS_175430166","JEECG","code");
+	
+	/**
+	 * 短信模板编码
+	 */
+	private String templateCode;
+	/**
+	 * 签名
+	 */
+	private String signName;
+	/**
+	 * 短信模板必需的数据名称,多个key以逗号分隔,此处配置作为校验
+	 */
+	private String keys;
+	
+	private DySmsEnum(String templateCode,String signName,String keys) {
+		this.templateCode = templateCode;
+		this.signName = signName;
+		this.keys = keys;
+	}
+	
+	public String getTemplateCode() {
+		return templateCode;
+	}
+	
+	public void setTemplateCode(String templateCode) {
+		this.templateCode = templateCode;
+	}
+	
+	public String getSignName() {
+		return signName;
+	}
+	
+	public void setSignName(String signName) {
+		this.signName = signName;
+	}
+	
+	public String getKeys() {
+		return keys;
+	}
+
+	public void setKeys(String keys) {
+		this.keys = keys;
+	}
+
+	public static DySmsEnum toEnum(String templateCode) {
+		if(StringUtils.isEmpty(templateCode)){
+			return null;
+		}
+		for(DySmsEnum item : DySmsEnum.values()) {
+			if(item.getTemplateCode().equals(templateCode)) {
+				return item;
+			}
+		}
+		return null;
+	}
+}
+

+ 57 - 50
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/DySmsHelper.java

@@ -2,6 +2,8 @@ package org.jeecg.common.util;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+
+import com.alibaba.fastjson.JSONObject;
 import com.aliyuncs.DefaultAcsClient;
 import com.aliyuncs.IAcsClient;
 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
@@ -17,75 +19,64 @@ import com.aliyuncs.profile.IClientProfile;
  * 工程依赖了2个jar包(存放在工程的libs目录下)
  * 1:aliyun-java-sdk-core.jar
  * 2:aliyun-java-sdk-dysmsapi.jar
- * <p>
+ *
  * 备注:Demo工程编码采用UTF-8
  * 国际短信发送请勿参照此DEMO
  */
 public class DySmsHelper {
+	
+	private final static Logger logger=LoggerFactory.getLogger(DySmsHelper.class);
 
-    private final static Logger logger = LoggerFactory.getLogger(DySmsHelper.class);
-
-    /**
-     * 产品名称:云通信短信API产品,开发者无需替换
-     */
-    static final String PRODUCT = "Dysmsapi";
-    /**
-     * 产品域名,开发者无需替换
-     */
-    static final String DOMAIN = "dysmsapi.aliyuncs.com";
-
-    /**
-     * TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
-     *
-     * @return
-     */
-
-    static final String ACCESS_KEY_ID = "?";
-    static final String ACCESS_KEY_SECRET = "?";
+    //产品名称:云通信短信API产品,开发者无需替换
+    static final String product = "Dysmsapi";
+    //产品域名,开发者无需替换
+    static final String domain = "dysmsapi.aliyuncs.com";
 
-    /**
-     * 登陆时采用的短信发送模板编码
-     */
-    public static final String LOGIN_TEMPLATE_CODE = "SMS_167040816";
+    // TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
+    static  String accessKeyId;
+    static  String accessKeySecret;
 
-    /**
-     * 忘记密码时采用的短信发送模板编码
-     */
-    public static final String FORGET_PASSWORD_TEMPLATE_CODE = "SMS_167040816";
-
-
-    /**
-     * 注册时采用的短信发送模板编码
-     */
-    public static final String REGISTER_TEMPLATE_CODE = "SMS_144146309";
+    public static void setAccessKeyId(String accessKeyId) {
+        DySmsHelper.accessKeyId = accessKeyId;
+    }
 
-    /**
-     * 必填:短信签名-可在短信控制台中找到
-     */
-    public static final String SIGN_NAME = "JEECG";
+    public static void setAccessKeySecret(String accessKeySecret) {
+        DySmsHelper.accessKeySecret = accessKeySecret;
+    }
 
+    public static String getAccessKeyId() {
+        return accessKeyId;
+    }
 
-    public static boolean sendSms(String phone, String code, String templateCode) throws ClientException {
-        //可自助调整超时时间
+    public static String getAccessKeySecret() {
+        return accessKeySecret;
+    }
+    
+    
+    public static boolean sendSms(String phone,JSONObject templateParamJson,DySmsEnum dySmsEnum) throws ClientException {
+    	//可自助调整超时时间
         System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
         System.setProperty("sun.net.client.defaultReadTimeout", "10000");
-
+        
         //初始化acsClient,暂不支持region化
-        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", ACCESS_KEY_ID, ACCESS_KEY_SECRET);
-        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", PRODUCT, DOMAIN);
+        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
+        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
         IAcsClient acsClient = new DefaultAcsClient(profile);
-
+        
+        //验证json参数
+        validateParam(templateParamJson,dySmsEnum);
+        
         //组装请求对象-具体描述见控制台-文档部分内容
         SendSmsRequest request = new SendSmsRequest();
         //必填:待发送手机号
         request.setPhoneNumbers(phone);
         //必填:短信签名-可在短信控制台中找到
-        request.setSignName(SIGN_NAME);
+        request.setSignName(dySmsEnum.getSignName());
         //必填:短信模板-可在短信控制台中找到
-        request.setTemplateCode("SMS_167040816");
+        request.setTemplateCode(dySmsEnum.getTemplateCode());
         //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
-        request.setTemplateParam("{\"code\":\"" + code + "\"}");
-
+        request.setTemplateParam(templateParamJson.toJSONString());
+        
         //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
         //request.setSmsUpExtendCode("90997");
 
@@ -93,17 +84,33 @@ public class DySmsHelper {
         //request.setOutId("yourOutId");
 
         boolean result = false;
+
         //hint 此处可能会抛出异常,注意catch
         SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
         logger.info("短信接口返回的数据----------------");
-        logger.info("{Code:" + sendSmsResponse.getCode() + ",Message:" + sendSmsResponse.getMessage() + ",RequestId:" + sendSmsResponse.getRequestId() + ",BizId:" + sendSmsResponse.getBizId() + "}");
+        logger.info("{Code:" + sendSmsResponse.getCode()+",Message:" + sendSmsResponse.getMessage()+",RequestId:"+ sendSmsResponse.getRequestId()+",BizId:"+sendSmsResponse.getBizId()+"}");
         if ("OK".equals(sendSmsResponse.getCode())) {
             result = true;
         }
         return result;
+        
+    }
+    
+    private static void validateParam(JSONObject templateParamJson,DySmsEnum dySmsEnum) {
+    	String keys = dySmsEnum.getKeys();
+    	String [] keyArr = keys.split(",");
+    	for(String item :keyArr) {
+    		if(!templateParamJson.containsKey(item)) {
+    			throw new RuntimeException("模板缺少参数:"+item);
+    		}
+    	}
     }
+    
 
     public static void main(String[] args) throws ClientException, InterruptedException {
-        sendSms("13800138000", "123456", FORGET_PASSWORD_TEMPLATE_CODE);
+    	JSONObject obj = new JSONObject();
+    	obj.put("code", "1234");
+    	sendSms("13800138000", obj, DySmsEnum.FORGET_PASSWORD_TEMPLATE_CODE);
+    	
     }
 }

+ 29 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/HTMLUtils.java

@@ -0,0 +1,29 @@
+package org.jeecg.common.util;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.web.util.HtmlUtils;
+
+/**
+ * HTML 工具类
+ */
+public class HTMLUtils {
+
+    /**
+     * 获取HTML内的文本,不包含标签
+     *
+     * @param html HTML 代码
+     */
+    public static String getInnerText(String html) {
+        if (StringUtils.isNotBlank(html)) {
+            //去掉 html 的标签
+            String content = html.replaceAll("</?[^>]+>", "");
+            // 将多个空格合并成一个空格
+            content = content.replaceAll("(&nbsp;)+", "&nbsp;");
+            // 反向转义字符
+            content = HtmlUtils.htmlUnescape(content);
+            return content.trim();
+        }
+        return "";
+    }
+
+}

+ 2 - 2
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/IPUtils.java

@@ -1,11 +1,11 @@
 package org.jeecg.common.util;
 
+import javax.servlet.http.HttpServletRequest;
 
-import com.alibaba.druid.util.StringUtils;
+import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.servlet.http.HttpServletRequest;
 /**
  * IP地址
  * 

+ 96 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/ImportExcelUtil.java

@@ -0,0 +1,96 @@
+package org.jeecg.common.util;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.IService;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.constant.CommonConstant;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 导出返回信息
+ */
+@Slf4j
+public class ImportExcelUtil {
+
+    public static Result<?> imporReturnRes(int errorLines,int successLines,List<String> errorMessage) throws IOException {
+        if (errorLines == 0) {
+            return Result.ok("共" + successLines + "行数据全部导入成功!");
+        } else {
+            JSONObject result = new JSONObject(5);
+            int totalCount = successLines + errorLines;
+            result.put("totalCount", totalCount);
+            result.put("errorCount", errorLines);
+            result.put("successCount", successLines);
+            result.put("msg", "总上传行数:" + totalCount + ",已导入行数:" + successLines + ",错误行数:" + errorLines);
+            String fileUrl = PmsUtil.saveErrorTxtByList(errorMessage, "userImportExcelErrorLog");
+            int lastIndex = fileUrl.lastIndexOf(File.separator);
+            String fileName = fileUrl.substring(lastIndex + 1);
+            result.put("fileUrl", "/sys/common/static/" + fileUrl);
+            result.put("fileName", fileName);
+            Result res = Result.ok(result);
+            res.setCode(201);
+            res.setMessage("文件导入成功,但有错误。");
+            return res;
+        }
+    }
+
+    public static List<String> importDateSave(List<Object> list, Class serviceClass,List<String> errorMessage,String errorFlag)  {
+        IService bean =(IService) SpringContextUtils.getBean(serviceClass);
+        for (int i = 0; i < list.size(); i++) {
+            try {
+                boolean save = bean.save(list.get(i));
+                if(!save){
+                    throw new Exception(errorFlag);
+                }
+            } catch (Exception e) {
+                String message = e.getMessage();
+                int lineNumber = i + 1;
+                // 通过索引名判断出错信息
+                if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_ROLE_CODE)) {
+                    errorMessage.add("第 " + lineNumber + " 行:角色编码已经存在,忽略导入。");
+                } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_JOB_CLASS_NAME)) {
+                    errorMessage.add("第 " + lineNumber + " 行:任务类名已经存在,忽略导入。");
+                }else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_CODE)) {
+                    errorMessage.add("第 " + lineNumber + " 行:职务编码已经存在,忽略导入。");
+                }else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_DEPART_ORG_CODE)) {
+                    errorMessage.add("第 " + lineNumber + " 行:部门编码已经存在,忽略导入。");
+                }else {
+                    errorMessage.add("第 " + lineNumber + " 行:未知错误,忽略导入");
+                    log.error(e.getMessage(), e);
+                }
+            }
+        }
+        return errorMessage;
+    }
+
+    public static List<String> importDateSaveOne(Object obj, Class serviceClass,List<String> errorMessage,int i,String errorFlag)  {
+        IService bean =(IService) SpringContextUtils.getBean(serviceClass);
+        try {
+            boolean save = bean.save(obj);
+            if(!save){
+                throw new Exception(errorFlag);
+            }
+        } catch (Exception e) {
+            String message = e.getMessage();
+            int lineNumber = i + 1;
+            // 通过索引名判断出错信息
+            if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_ROLE_CODE)) {
+                errorMessage.add("第 " + lineNumber + " 行:角色编码已经存在,忽略导入。");
+            } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_JOB_CLASS_NAME)) {
+                errorMessage.add("第 " + lineNumber + " 行:任务类名已经存在,忽略导入。");
+            }else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_CODE)) {
+                errorMessage.add("第 " + lineNumber + " 行:职务编码已经存在,忽略导入。");
+            }else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_DEPART_ORG_CODE)) {
+                errorMessage.add("第 " + lineNumber + " 行:部门编码已经存在,忽略导入。");
+            }else {
+                errorMessage.add("第 " + lineNumber + " 行:未知错误,忽略导入");
+                log.error(e.getMessage(), e);
+            }
+        }
+        return errorMessage;
+    }
+}

+ 10 - 9
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/PasswordUtil.java

@@ -17,8 +17,8 @@ public class PasswordUtil {
 	/**
 	 * 定义使用的算法为:PBEWITHMD5andDES算法
 	 */
-    public static final String ALGORITHM = "PBEWithMD5AndDES";
-    public static final String SALT = "63293188";
+	public static final String ALGORITHM = "PBEWithMD5AndDES";//加密算法
+	public static final String Salt = "63293188";//密钥
 
 	/**
 	 * 定义迭代次数为1000次
@@ -39,7 +39,7 @@ public class PasswordUtil {
 
 	public static byte[] getStaticSalt() {
 		// 产出盐
-        return SALT.getBytes();
+		return Salt.getBytes();
 	}
 
 	/**
@@ -49,7 +49,7 @@ public class PasswordUtil {
 	 *            生成密钥时所使用的密码
 	 * @return Key PBE算法密钥
 	 * */
-    private static Key getPbeKey(String password) {
+	private static Key getPBEKey(String password) {
 		// 实例化使用的算法
 		SecretKeyFactory keyFactory;
 		SecretKey secretKey = null;
@@ -81,15 +81,16 @@ public class PasswordUtil {
 	 */
 	public static String encrypt(String plaintext, String password, String salt) {
 
-        Key key = getPbeKey(password);
+		Key key = getPBEKey(password);
 		byte[] encipheredData = null;
 		PBEParameterSpec parameterSpec = new PBEParameterSpec(salt.getBytes(), ITERATIONCOUNT);
 		try {
 			Cipher cipher = Cipher.getInstance(ALGORITHM);
 
 			cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
-
-			encipheredData = cipher.doFinal(plaintext.getBytes());
+			//update-begin-author:sccott date:20180815 for:中文作为用户名时,加密的密码windows和linux会得到不同的结果 gitee/issues/IZUD7
+			encipheredData = cipher.doFinal(plaintext.getBytes("utf-8"));
+			//update-end-author:sccott date:20180815 for:中文作为用户名时,加密的密码windows和linux会得到不同的结果 gitee/issues/IZUD7
 		} catch (Exception e) {
 		}
 		return bytesToHexString(encipheredData);
@@ -109,7 +110,7 @@ public class PasswordUtil {
 	 */
 	public static String decrypt(String ciphertext, String password, String salt) {
 
-        Key key = getPbeKey(password);
+		Key key = getPBEKey(password);
 		byte[] passDec = null;
 		PBEParameterSpec parameterSpec = new PBEParameterSpec(salt.getBytes(), ITERATIONCOUNT);
 		try {
@@ -157,7 +158,7 @@ public class PasswordUtil {
 	 * @return
 	 */
 	public static byte[] hexStringToBytes(String hexString) {
-        if (hexString == null || "".equals(hexString)) {
+		if (hexString == null || hexString.equals("")) {
 			return null;
 		}
 		hexString = hexString.toUpperCase();

+ 61 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/PmsUtil.java

@@ -0,0 +1,61 @@
+package org.jeecg.common.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@Component
+public class PmsUtil {
+
+
+    private static String uploadPath;
+
+    @Value("${jeecg.path.upload}")
+    public void setUploadPath(String uploadPath) {
+        PmsUtil.uploadPath = uploadPath;
+    }
+
+    public static String saveErrorTxtByList(List<String> msg, String name) {
+        Date d = new Date();
+        String saveDir = "logs" + File.separator + DateUtils.yyyyMMdd.get().format(d) + File.separator;
+        String saveFullDir = uploadPath + File.separator + saveDir;
+
+        File saveFile = new File(saveFullDir);
+        if (!saveFile.exists()) {
+            saveFile.mkdirs();
+        }
+        name += DateUtils.yyyymmddhhmmss.get().format(d) + Math.round(Math.random() * 10000);
+        String saveFilePath = saveFullDir + name + ".txt";
+
+        try {
+            //封装目的地
+            BufferedWriter bw = new BufferedWriter(new FileWriter(saveFilePath));
+            //遍历集合
+            for (String s : msg) {
+                //写数据
+                if (s.indexOf("_") > 0) {
+                    String arr[] = s.split("_");
+                    bw.write("第" + arr[0] + "行:" + arr[1]);
+                } else {
+                    bw.write(s);
+                }
+                //bw.newLine();
+                bw.write("\r\n");
+            }
+            //释放资源
+            bw.flush();
+            bw.close();
+        } catch (Exception e) {
+            log.info("excel导入生成错误日志文件异常:" + e.getMessage());
+        }
+        return saveDir + name + ".txt";
+    }
+
+}

+ 42 - 41
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/RedisUtil.java

@@ -1,16 +1,17 @@
 package org.jeecg.common.util;
 
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.jeecg.common.exception.JeecgBootException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
 /**
  * redis 工具类
  * @Author Scott
@@ -26,7 +27,7 @@ public class RedisUtil {
 
 	/**
 	 * 指定缓存失效时间
-     *
+	 * 
 	 * @param key  键
 	 * @param time 时间(秒)
 	 * @return
@@ -45,7 +46,7 @@ public class RedisUtil {
 
 	/**
 	 * 根据key 获取过期时间
-     *
+	 * 
 	 * @param key 键 不能为null
 	 * @return 时间(秒) 返回0代表为永久有效
 	 */
@@ -55,7 +56,7 @@ public class RedisUtil {
 
 	/**
 	 * 判断key是否存在
-     *
+	 * 
 	 * @param key 键
 	 * @return true 存在 false不存在
 	 */
@@ -70,7 +71,7 @@ public class RedisUtil {
 
 	/**
 	 * 删除缓存
-     *
+	 * 
 	 * @param key 可以传一个值 或多个
 	 */
 	@SuppressWarnings("unchecked")
@@ -87,7 +88,7 @@ public class RedisUtil {
 	// ============================String=============================
 	/**
 	 * 普通缓存获取
-     *
+	 * 
 	 * @param key 键
 	 * @return 值
 	 */
@@ -97,7 +98,7 @@ public class RedisUtil {
 
 	/**
 	 * 普通缓存放入
-     *
+	 * 
 	 * @param key   键
 	 * @param value 值
 	 * @return true成功 false失败
@@ -115,7 +116,7 @@ public class RedisUtil {
 
 	/**
 	 * 普通缓存放入并设置时间
-     *
+	 * 
 	 * @param key   键
 	 * @param value 值
 	 * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
@@ -137,9 +138,9 @@ public class RedisUtil {
 
 	/**
 	 * 递增
-     *
+	 * 
 	 * @param key 键
-     * @param delta  要增加几(大于0)
+	 * @param by  要增加几(大于0)
 	 * @return
 	 */
 	public long incr(String key, long delta) {
@@ -151,9 +152,9 @@ public class RedisUtil {
 
 	/**
 	 * 递减
-     *
+	 * 
 	 * @param key 键
-     * @param delta 要减少几(小于0)
+	 * @param by  要减少几(小于0)
 	 * @return
 	 */
 	public long decr(String key, long delta) {
@@ -166,7 +167,7 @@ public class RedisUtil {
 	// ================================Map=================================
 	/**
 	 * HashGet
-     *
+	 * 
 	 * @param key  键 不能为null
 	 * @param item 项 不能为null
 	 * @return 值
@@ -177,7 +178,7 @@ public class RedisUtil {
 
 	/**
 	 * 获取hashKey对应的所有键值
-     *
+	 * 
 	 * @param key 键
 	 * @return 对应的多个键值
 	 */
@@ -187,7 +188,7 @@ public class RedisUtil {
 
 	/**
 	 * HashSet
-     *
+	 * 
 	 * @param key 键
 	 * @param map 对应多个键值
 	 * @return true 成功 false 失败
@@ -204,7 +205,7 @@ public class RedisUtil {
 
 	/**
 	 * HashSet 并设置时间
-     *
+	 * 
 	 * @param key  键
 	 * @param map  对应多个键值
 	 * @param time 时间(秒)
@@ -225,7 +226,7 @@ public class RedisUtil {
 
 	/**
 	 * 向一张hash表中放入数据,如果不存在将创建
-     *
+	 * 
 	 * @param key   键
 	 * @param item  项
 	 * @param value 值
@@ -243,7 +244,7 @@ public class RedisUtil {
 
 	/**
 	 * 向一张hash表中放入数据,如果不存在将创建
-     *
+	 * 
 	 * @param key   键
 	 * @param item  项
 	 * @param value 值
@@ -265,7 +266,7 @@ public class RedisUtil {
 
 	/**
 	 * 删除hash表中的值
-     *
+	 * 
 	 * @param key  键 不能为null
 	 * @param item 项 可以使多个 不能为null
 	 */
@@ -275,7 +276,7 @@ public class RedisUtil {
 
 	/**
 	 * 判断hash表中是否有该项的值
-     *
+	 * 
 	 * @param key  键 不能为null
 	 * @param item 项 不能为null
 	 * @return true 存在 false不存在
@@ -286,7 +287,7 @@ public class RedisUtil {
 
 	/**
 	 * hash递增 如果不存在,就会创建一个 并把新增后的值返回
-     *
+	 * 
 	 * @param key  键
 	 * @param item 项
 	 * @param by   要增加几(大于0)
@@ -298,7 +299,7 @@ public class RedisUtil {
 
 	/**
 	 * hash递减
-     *
+	 * 
 	 * @param key  键
 	 * @param item 项
 	 * @param by   要减少记(小于0)
@@ -311,7 +312,7 @@ public class RedisUtil {
 	// ============================set=============================
 	/**
 	 * 根据key获取Set中的所有值
-     *
+	 * 
 	 * @param key 键
 	 * @return
 	 */
@@ -326,7 +327,7 @@ public class RedisUtil {
 
 	/**
 	 * 根据value从一个set中查询,是否存在
-     *
+	 * 
 	 * @param key   键
 	 * @param value 值
 	 * @return true 存在 false不存在
@@ -342,7 +343,7 @@ public class RedisUtil {
 
 	/**
 	 * 将数据放入set缓存
-     *
+	 * 
 	 * @param key    键
 	 * @param values 值 可以是多个
 	 * @return 成功个数
@@ -358,7 +359,7 @@ public class RedisUtil {
 
 	/**
 	 * 将set数据放入缓存
-     *
+	 * 
 	 * @param key    键
 	 * @param time   时间(秒)
 	 * @param values 值 可以是多个
@@ -379,7 +380,7 @@ public class RedisUtil {
 
 	/**
 	 * 获取set缓存的长度
-     *
+	 * 
 	 * @param key 键
 	 * @return
 	 */
@@ -394,7 +395,7 @@ public class RedisUtil {
 
 	/**
 	 * 移除值为value的
-     *
+	 * 
 	 * @param key    键
 	 * @param values 值 可以是多个
 	 * @return 移除的个数
@@ -412,7 +413,7 @@ public class RedisUtil {
 
 	/**
 	 * 获取list缓存的内容
-     *
+	 * 
 	 * @param key   键
 	 * @param start 开始
 	 * @param end   结束 0 到 -1代表所有值
@@ -429,7 +430,7 @@ public class RedisUtil {
 
 	/**
 	 * 获取list缓存的长度
-     *
+	 * 
 	 * @param key 键
 	 * @return
 	 */
@@ -444,7 +445,7 @@ public class RedisUtil {
 
 	/**
 	 * 通过索引 获取list中的值
-     *
+	 * 
 	 * @param key   键
 	 * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
 	 * @return
@@ -460,7 +461,7 @@ public class RedisUtil {
 
 	/**
 	 * 将list放入缓存
-     *
+	 * 
 	 * @param key   键
 	 * @param value 值
 	 * @param time  时间(秒)
@@ -478,7 +479,7 @@ public class RedisUtil {
 
 	/**
 	 * 将list放入缓存
-     *
+	 * 
 	 * @param key   键
 	 * @param value 值
 	 * @param time  时间(秒)
@@ -499,7 +500,7 @@ public class RedisUtil {
 
 	/**
 	 * 将list放入缓存
-     *
+	 * 
 	 * @param key   键
 	 * @param value 值
 	 * @param time  时间(秒)
@@ -517,7 +518,7 @@ public class RedisUtil {
 
 	/**
 	 * 将list放入缓存
-     *
+	 * 
 	 * @param key   键
 	 * @param value 值
 	 * @param time  时间(秒)
@@ -538,7 +539,7 @@ public class RedisUtil {
 
 	/**
 	 * 根据索引修改list中的某条数据
-     *
+	 * 
 	 * @param key   键
 	 * @param index 索引
 	 * @param value 值
@@ -556,7 +557,7 @@ public class RedisUtil {
 
 	/**
 	 * 移除N个值为value
-     *
+	 * 
 	 * @param key   键
 	 * @param count 移除多少个
 	 * @param value 值

+ 121 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/RestDesformUtil.java

@@ -0,0 +1,121 @@
+package org.jeecg.common.util;
+
+import com.alibaba.fastjson.JSONObject;
+import org.jeecg.common.api.vo.Result;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+
+/**
+ * 通过 RESTful 风格的接口操纵 desform 里的数据
+ *
+ * @author sunjianlei
+ */
+public class RestDesformUtil {
+
+    private static String domain = null;
+    private static String path = null;
+
+    static {
+        domain = SpringContextUtils.getDomain();
+        path = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("server.servlet.context-path");
+    }
+
+    /**
+     * 查询数据
+     *
+     * @param desformCode
+     * @param dataId
+     * @param token
+     * @return
+     */
+    public static Result queryOne(String desformCode, String dataId, String token) {
+        String url = getBaseUrl(desformCode, dataId).toString();
+        HttpHeaders headers = getHeaders(token);
+        ResponseEntity<JSONObject> result = RestUtil.request(url, HttpMethod.GET, headers, null, null, JSONObject.class);
+        return packageReturn(result);
+    }
+
+    /**
+     * 新增数据
+     *
+     * @param desformCode
+     * @param formData
+     * @param token
+     * @return
+     */
+    public static Result addOne(String desformCode, JSONObject formData, String token) {
+        return addOrEditOne(desformCode, formData, token, HttpMethod.POST);
+    }
+
+    /**
+     * 修改数据
+     *
+     * @param desformCode
+     * @param formData
+     * @param token
+     * @return
+     */
+    public static Result editOne(String desformCode, JSONObject formData, String token) {
+        return addOrEditOne(desformCode, formData, token, HttpMethod.PUT);
+    }
+
+    private static Result addOrEditOne(String desformCode, JSONObject formData, String token, HttpMethod method) {
+        String url = getBaseUrl(desformCode).toString();
+        HttpHeaders headers = getHeaders(token);
+        ResponseEntity<JSONObject> result = RestUtil.request(url, method, headers, null, formData, JSONObject.class);
+        return packageReturn(result);
+    }
+
+    /**
+     * 删除数据
+     *
+     * @param desformCode
+     * @param dataId
+     * @param token
+     * @return
+     */
+    public static Result removeOne(String desformCode, String dataId, String token) {
+        String url = getBaseUrl(desformCode, dataId).toString();
+        HttpHeaders headers = getHeaders(token);
+        ResponseEntity<JSONObject> result = RestUtil.request(url, HttpMethod.DELETE, headers, null, null, JSONObject.class);
+        return packageReturn(result);
+    }
+
+    private static Result packageReturn(ResponseEntity<JSONObject> result) {
+        if (result.getBody() != null) {
+            return result.getBody().toJavaObject(Result.class);
+        }
+        return Result.error("操作失败");
+    }
+
+    private static StringBuilder getBaseUrl() {
+        StringBuilder builder = new StringBuilder(domain).append(path);
+        builder.append("/desform/api");
+        return builder;
+    }
+
+    private static StringBuilder getBaseUrl(String desformCode, String dataId) {
+        StringBuilder builder = getBaseUrl();
+        builder.append("/").append(desformCode);
+        if (dataId != null) {
+            builder.append("/").append(dataId);
+        }
+        return builder;
+    }
+
+    private static StringBuilder getBaseUrl(String desformCode) {
+        return getBaseUrl(desformCode, null);
+    }
+
+    private static HttpHeaders getHeaders(String token) {
+        HttpHeaders headers = new HttpHeaders();
+        String mediaType = MediaType.APPLICATION_JSON_UTF8_VALUE;
+        headers.setContentType(MediaType.parseMediaType(mediaType));
+        headers.set("Accept", mediaType);
+        headers.set("X-Access-Token", token);
+        return headers;
+    }
+
+}

+ 247 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/RestUtil.java

@@ -0,0 +1,247 @@
+package org.jeecg.common.util;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.http.*;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * 调用 Restful 接口 Util
+ *
+ * @author sunjianlei
+ */
+public class RestUtil {
+
+    private static String domain = null;
+
+    public static String getDomain() {
+        if (domain == null) {
+            domain = SpringContextUtils.getDomain();
+        }
+        return domain;
+    }
+
+    public static String path = null;
+
+    public static String getPath() {
+        if (path == null) {
+            path = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("server.servlet.context-path");
+        }
+        return path;
+    }
+
+    public static String getBaseUrl() {
+        return getDomain() + getPath();
+    }
+
+    /**
+     * RestAPI 调用器
+     */
+    private final static RestTemplate RT;
+
+    static {
+        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
+        requestFactory.setConnectTimeout(3000);
+        requestFactory.setReadTimeout(3000);
+        RT = new RestTemplate(requestFactory);
+        // 解决乱码问题
+        RT.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
+    }
+
+    public static RestTemplate getRestTemplate() {
+        return RT;
+    }
+
+    /**
+     * 发送 get 请求
+     */
+    public static JSONObject get(String url) {
+        return getNative(url, null, null).getBody();
+    }
+
+    /**
+     * 发送 get 请求
+     */
+    public static JSONObject get(String url, JSONObject variables) {
+        return getNative(url, variables, null).getBody();
+    }
+
+    /**
+     * 发送 get 请求
+     */
+    public static JSONObject get(String url, JSONObject variables, JSONObject params) {
+        return getNative(url, variables, params).getBody();
+    }
+
+    /**
+     * 发送 get 请求,返回原生 ResponseEntity 对象
+     */
+    public static ResponseEntity<JSONObject> getNative(String url, JSONObject variables, JSONObject params) {
+        return request(url, HttpMethod.GET, variables, params);
+    }
+
+    /**
+     * 发送 Post 请求
+     */
+    public static JSONObject post(String url) {
+        return postNative(url, null, null).getBody();
+    }
+
+    /**
+     * 发送 Post 请求
+     */
+    public static JSONObject post(String url, JSONObject params) {
+        return postNative(url, null, params).getBody();
+    }
+
+    /**
+     * 发送 Post 请求
+     */
+    public static JSONObject post(String url, JSONObject variables, JSONObject params) {
+        return postNative(url, variables, params).getBody();
+    }
+
+    /**
+     * 发送 POST 请求,返回原生 ResponseEntity 对象
+     */
+    public static ResponseEntity<JSONObject> postNative(String url, JSONObject variables, JSONObject params) {
+        return request(url, HttpMethod.POST, variables, params);
+    }
+
+    /**
+     * 发送 put 请求
+     */
+    public static JSONObject put(String url) {
+        return putNative(url, null, null).getBody();
+    }
+
+    /**
+     * 发送 put 请求
+     */
+    public static JSONObject put(String url, JSONObject params) {
+        return putNative(url, null, params).getBody();
+    }
+
+    /**
+     * 发送 put 请求
+     */
+    public static JSONObject put(String url, JSONObject variables, JSONObject params) {
+        return putNative(url, variables, params).getBody();
+    }
+
+    /**
+     * 发送 put 请求,返回原生 ResponseEntity 对象
+     */
+    public static ResponseEntity<JSONObject> putNative(String url, JSONObject variables, JSONObject params) {
+        return request(url, HttpMethod.PUT, variables, params);
+    }
+
+    /**
+     * 发送 delete 请求
+     */
+    public static JSONObject delete(String url) {
+        return deleteNative(url, null, null).getBody();
+    }
+
+    /**
+     * 发送 delete 请求
+     */
+    public static JSONObject delete(String url, JSONObject variables, JSONObject params) {
+        return deleteNative(url, variables, params).getBody();
+    }
+
+    /**
+     * 发送 delete 请求,返回原生 ResponseEntity 对象
+     */
+    public static ResponseEntity<JSONObject> deleteNative(String url, JSONObject variables, JSONObject params) {
+        return request(url, HttpMethod.DELETE, null, variables, params, JSONObject.class);
+    }
+
+    /**
+     * 发送请求
+     */
+    public static ResponseEntity<JSONObject> request(String url, HttpMethod method, JSONObject variables, JSONObject params) {
+        return request(url, method, getHeaderApplicationJson(), variables, params, JSONObject.class);
+    }
+
+    /**
+     * 发送请求
+     *
+     * @param url          请求地址
+     * @param method       请求方式
+     * @param headers      请求头  可空
+     * @param variables    请求url参数 可空
+     * @param params       请求body参数 可空
+     * @param responseType 返回类型
+     * @return ResponseEntity<responseType>
+     */
+    public static <T> ResponseEntity<T> request(String url, HttpMethod method, HttpHeaders headers, JSONObject variables, JSONObject params, Class<T> responseType) {
+        if (StringUtils.isEmpty(url)) {
+            throw new RuntimeException("url 不能为空");
+        }
+        if (method == null) {
+            throw new RuntimeException("method 不能为空");
+        }
+        if (headers == null) {
+            headers = new HttpHeaders();
+        }
+        // 请求体
+        String body = "";
+        if (params != null) {
+            body = params.toJSONString();
+        }
+        // 拼接 url 参数
+        if (variables != null) {
+            url += ("?" + asUrlVariables(variables));
+        }
+        // 发送请求
+        HttpEntity<String> request = new HttpEntity<>(body, headers);
+        return RT.exchange(url, method, request, responseType);
+    }
+
+    /**
+     * 获取JSON请求头
+     */
+    private static HttpHeaders getHeaderApplicationJson() {
+        return getHeader(MediaType.APPLICATION_JSON_UTF8_VALUE);
+    }
+
+    /**
+     * 获取请求头
+     */
+    private static HttpHeaders getHeader(String mediaType) {
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.parseMediaType(mediaType));
+        headers.add("Accept", mediaType);
+        return headers;
+    }
+
+    /**
+     * 将 JSONObject 转为 a=1&b=2&c=3...&n=n 的形式
+     */
+    public static String asUrlVariables(JSONObject variables) {
+        Map<String, Object> source = variables.getInnerMap();
+        Iterator<String> it = source.keySet().iterator();
+        StringBuilder urlVariables = new StringBuilder();
+        while (it.hasNext()) {
+            String key = it.next();
+            String value = "";
+            Object object = source.get(key);
+            if (object != null) {
+                if (!StringUtils.isEmpty(object.toString())) {
+                    value = object.toString();
+                }
+            }
+            urlVariables.append("&").append(key).append("=").append(value);
+        }
+        // 去掉第一个&
+        return urlVariables.substring(1);
+    }
+
+}

+ 63 - 67
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/SpringContextUtils.java

@@ -1,5 +1,7 @@
 package org.jeecg.common.util;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
@@ -7,82 +9,76 @@ import org.springframework.stereotype.Component;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
 
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * @author jeecg-boot
- * 2019年12月5日19:57:58
- */
 @Component
 public class SpringContextUtils implements ApplicationContextAware {
 
-    /**
-     * 上下文对象实例
-     */
-    private static ApplicationContext applicationContext;
+	/**
+	 * 上下文对象实例
+	 */
+	private static ApplicationContext applicationContext;
 
-    @Override
-    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
-        SpringContextUtils.applicationContext = applicationContext;
-    }
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+		SpringContextUtils.applicationContext = applicationContext;
+	}
 
-    /**
-     * 获取applicationContext
-     *
-     * @return
-     */
-    public static ApplicationContext getApplicationContext() {
-        return applicationContext;
-    }
+	/**
+	 * 获取applicationContext
+	 *
+	 * @return
+	 */
+	public static ApplicationContext getApplicationContext() {
+		return applicationContext;
+	}
 
-    /**
-     * 获取HttpServletRequest
-     */
-    public static HttpServletRequest getHttpServletRequest() {
-        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
-    }
+	/**
+	  * 获取HttpServletRequest
+	 */
+	public static HttpServletRequest getHttpServletRequest() {
+		return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+	}
 
-    public static String getDomain(){
-        HttpServletRequest request = getHttpServletRequest();
-        StringBuffer url = request.getRequestURL();
-        return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
-    }
+	public static String getDomain(){
+		HttpServletRequest request = getHttpServletRequest();
+		StringBuffer url = request.getRequestURL();
+		return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
+	}
 
-    public static String getOrigin(){
-        HttpServletRequest request = getHttpServletRequest();
-        return request.getHeader("Origin");
-    }
+	public static String getOrigin(){
+		HttpServletRequest request = getHttpServletRequest();
+		return request.getHeader("Origin");
+	}
 
-    /**
-     * 通过name获取 Bean.
-     *
-     * @param name
-     * @return
-     */
-    public static Object getBean(String name) {
-        return getApplicationContext().getBean(name);
-    }
+	/**
+	 * 通过name获取 Bean.
+	 *
+	 * @param name
+	 * @return
+	 */
+	public static Object getBean(String name) {
+		return getApplicationContext().getBean(name);
+	}
 
-    /**
-     * 通过class获取Bean.
-     *
-     * @param clazz
-     * @param       <T>
-     * @return
-     */
-    public static <T> T getBean(Class<T> clazz) {
-        return getApplicationContext().getBean(clazz);
-    }
+	/**
+	 * 通过class获取Bean.
+	 *
+	 * @param clazz
+	 * @param       <T>
+	 * @return
+	 */
+	public static <T> T getBean(Class<T> clazz) {
+		return getApplicationContext().getBean(clazz);
+	}
 
-    /**
-     * 通过name,以及Clazz返回指定的Bean
-     *
-     * @param name
-     * @param clazz
-     * @param       <T>
-     * @return
-     */
-    public static <T> T getBean(String name, Class<T> clazz) {
-        return getApplicationContext().getBean(name, clazz);
-    }
+	/**
+	 * 通过name,以及Clazz返回指定的Bean
+	 *
+	 * @param name
+	 * @param clazz
+	 * @param       <T>
+	 * @return
+	 */
+	public static <T> T getBean(String name, Class<T> clazz) {
+		return getApplicationContext().getBean(name, clazz);
+	}
 }

+ 69 - 13
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java

@@ -1,6 +1,9 @@
 package org.jeecg.common.util;
 
+import cn.hutool.crypto.SecureUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.exception.JeecgBootException;
+import javax.servlet.http.HttpServletRequest;
 
 /**
  * sql注入处理工具类
@@ -9,7 +12,32 @@ import lombok.extern.slf4j.Slf4j;
  */
 @Slf4j
 public class SqlInjectionUtil {
-    final static String XSS_STR = "'|and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|,";
+	/**
+	 * sign 用于表字典加签的盐值【SQL漏洞】
+	 * (上线修改值 20200501,同步修改前端的盐值)
+	 */
+	private final static String TABLE_DICT_SIGN_SALT = "20200501";
+	private final static String xssStr = "'|and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|,";
+
+	/*
+	* 针对表字典进行额外的sign签名校验(增加安全机制)
+	* @param dictCode:
+	* @param sign:
+	* @param request:
+	* @Return: void
+	*/
+	public static void checkDictTableSign(String dictCode, String sign, HttpServletRequest request) {
+		//表字典SQL注入漏洞,签名校验
+		String accessToken = request.getHeader("X-Access-Token");
+		String signStr = dictCode + SqlInjectionUtil.TABLE_DICT_SIGN_SALT + accessToken;
+		String javaSign = SecureUtil.md5(signStr);
+		if (!javaSign.equals(sign)) {
+			log.error("表字典,SQL注入漏洞签名校验失败 :" + sign + "!=" + javaSign+ ",dictCode=" + dictCode);
+			throw new JeecgBootException("无权限访问!");
+		}
+		log.info(" 表字典,SQL注入漏洞签名校验成功!sign=" + sign + ",dictCode=" + dictCode);
+	}
+
 
 	/**
 	 * sql注入过滤处理,遇到注入关键字抛异常
@@ -21,11 +49,12 @@ public class SqlInjectionUtil {
 		if (value == null || "".equals(value)) {
 			return;
 		}
-        // 统一转为小写
-        value = value.toLowerCase();
-        String[] xssArr = XSS_STR.split("\\|");
+		// 统一转为小写
+		value = value.toLowerCase();
+		String[] xssArr = xssStr.split("\\|");
 		for (int i = 0; i < xssArr.length; i++) {
 			if (value.indexOf(xssArr[i]) > -1) {
+				log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]);
 				log.error("请注意,值可能存在SQL注入风险!---> {}", value);
 				throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
 			}
@@ -35,20 +64,21 @@ public class SqlInjectionUtil {
 
 	/**
 	 * sql注入过滤处理,遇到注入关键字抛异常
-	 *
-     * @param values
+	 * 
+	 * @param values
 	 * @return
 	 */
 	public static void filterContent(String[] values) {
-        String[] xssArr = XSS_STR.split("\\|");
+		String[] xssArr = xssStr.split("\\|");
 		for (String value : values) {
 			if (value == null || "".equals(value)) {
 				return;
 			}
-            // 统一转为小写
-            value = value.toLowerCase();
+			// 统一转为小写
+			value = value.toLowerCase();
 			for (int i = 0; i < xssArr.length; i++) {
 				if (value.indexOf(xssArr[i]) > -1) {
+					log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]);
 					log.error("请注意,值可能存在SQL注入风险!---> {}", value);
 					throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
 				}
@@ -64,15 +94,41 @@ public class SqlInjectionUtil {
 	 */
 	@Deprecated
 	public static void specialFilterContent(String value) {
-		String specialXssStr = "exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|+|,";
+		String specialXssStr = " exec | insert | select | delete | update | drop | count | chr | mid | master | truncate | char | declare |;|+|";
 		String[] xssArr = specialXssStr.split("\\|");
 		if (value == null || "".equals(value)) {
 			return;
 		}
-        // 统一转为小写
-        value = value.toLowerCase();
+		// 统一转为小写
+		value = value.toLowerCase();
 		for (int i = 0; i < xssArr.length; i++) {
-			if (value.indexOf(xssArr[i]) > -1) {
+			if (value.indexOf(xssArr[i]) > -1 || value.startsWith(xssArr[i].trim())) {
+				log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]);
+				log.error("请注意,值可能存在SQL注入风险!---> {}", value);
+				throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
+			}
+		}
+		return;
+	}
+
+
+    /**
+     * @特殊方法(不通用) 仅用于Online报表SQL解析,注入过滤
+     * @param value
+     * @return
+     */
+	@Deprecated
+	public static void specialFilterContentForOnlineReport(String value) {
+		String specialXssStr = " exec | insert | delete | update | drop | chr | mid | master | truncate | char | declare |";
+		String[] xssArr = specialXssStr.split("\\|");
+		if (value == null || "".equals(value)) {
+			return;
+		}
+		// 统一转为小写
+		value = value.toLowerCase();
+		for (int i = 0; i < xssArr.length; i++) {
+			if (value.indexOf(xssArr[i]) > -1 || value.startsWith(xssArr[i].trim())) {
+				log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]);
 				log.error("请注意,值可能存在SQL注入风险!---> {}", value);
 				throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
 			}

+ 98 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/TokenUtils.java

@@ -0,0 +1,98 @@
+package org.jeecg.common.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.system.api.ISysBaseApi;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.system.vo.LoginUser;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @Author scott
+ * @Date 2019/9/23 14:12
+ * @Description: 编程校验token有效性
+ */
+@Slf4j
+public class TokenUtils {
+
+    /**
+     * 获取 request 里传递的 token
+     *
+     * @param request
+     * @return
+     */
+    public static String getTokenByRequest(HttpServletRequest request) {
+        String token = request.getParameter("token");
+        if (token == null) {
+            token = request.getHeader("X-Access-Token");
+        }
+        return token;
+    }
+
+    /**
+     * 验证Token
+     */
+    public static boolean verifyToken(HttpServletRequest request, ISysBaseApi sysBaseAPI, RedisUtil redisUtil) {
+        log.info(" -- url --" + request.getRequestURL());
+        String token = getTokenByRequest(request);
+
+        if (StringUtils.isBlank(token)) {
+            throw new AuthenticationException("token不能为空!");
+        }
+
+        // 解密获得username,用于和数据库进行对比
+        String username = JwtUtil.getUsername(token);
+        if (username == null) {
+            throw new AuthenticationException("token非法无效!");
+        }
+
+        // 查询用户信息
+        LoginUser user = sysBaseAPI.getUserByName(username);
+        if (user == null) {
+            throw new AuthenticationException("用户不存在!");
+        }
+        // 判断用户状态
+        if (user.getStatus() != 1) {
+            throw new AuthenticationException("账号已被锁定,请联系管理员!");
+        }
+        // 校验token是否超时失效 & 或者账号密码是否错误
+        if (!jwtTokenRefresh(token, username, user.getPassword(), redisUtil)) {
+            throw new AuthenticationException("Token失效,请重新登录!");
+        }
+        return true;
+    }
+
+    /**
+     * 刷新token(保证用户在线操作不掉线)
+     * @param token
+     * @param userName
+     * @param passWord
+     * @param redisUtil
+     * @return
+     */
+    private static boolean jwtTokenRefresh(String token, String userName, String passWord, RedisUtil redisUtil) {
+        String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token));
+        if (oConvertUtils.isNotEmpty(cacheToken)) {
+            // 校验token有效性
+            if (!JwtUtil.verify(cacheToken, userName, passWord)) {
+                String newAuthorization = JwtUtil.sign(userName, passWord);
+                // 设置Toekn缓存有效时间
+                redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, newAuthorization);
+                redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000);
+            }
+            //update-begin--Author:scott  Date:20191005  for:解决每次请求,都重写redis中 token缓存问题
+//            else {
+//                redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, cacheToken);
+//                // 设置超时时间
+//                redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
+//            }
+            //update-end--Author:scott  Date:20191005  for:解决每次请求,都重写redis中 token缓存问题
+            return true;
+        }
+        return false;
+    }
+
+}

+ 4 - 4
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/UUIDGenerator.java

@@ -18,8 +18,8 @@ public class UUIDGenerator {
 	 */
 
 	public static String generate() {
-        return new StringBuilder(32).append(format(getIp())).append(
-                format(getJvm())).append(format(getHiTime())).append(
+		return new StringBuilder(32).append(format(getIP())).append(
+				format(getJVM())).append(format(getHiTime())).append(
 				format(getLoTime())).append(format(getCount())).toString();
 		
 	}
@@ -53,7 +53,7 @@ public class UUIDGenerator {
 		return buf.toString();
 	}
 
-    private final static int getJvm() {
+	private final static int getJVM() {
 		return JVM;
 	}
 
@@ -69,7 +69,7 @@ public class UUIDGenerator {
 	/**
 	 * Unique in a local network
 	 */
-    private final static int getIp() {
+	private final static int getIP() {
 		return IP;
 	}
 

+ 161 - 152
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/YouBianCodeUtil.java

@@ -6,159 +6,168 @@ import io.netty.util.internal.StringUtil;
  * 流水号生成规则(按默认规则递增,数字从1-99开始递增,数字到99,递增字母;位数不够增加位数)
  * A001
  * A001A002
- *
  * @Author zhangdaihao
+ *
  */
 public class YouBianCodeUtil {
-    /**
-     * 代表数字位数
-     * 数字位数(默认生成3位的数字)
-     */
-    private static final int NUM_LENGTH = 2;
-
-    public static final int ZHANWEI_LENGTH = 1 + NUM_LENGTH;
-
-    /**
-     * 根据前一个code,获取同级下一个code
-     * 例如:当前最大code为D01A04,下一个code为:D01A05
-     *
-     * @param code
-     * @return
-     */
-    public static synchronized String getNextYouBianCode(String code) {
-        String newcode = "";
-        if (code == null || code == "") {
-            String zimu = "A";
-            String num = getStrNum(1);
-            newcode = zimu + num;
-        } else {
-            String beforeCode = code.substring(0, code.length() - 1 - NUM_LENGTH);
-            String afterCode = code.substring(code.length() - 1 - NUM_LENGTH, code.length());
-            char afterCodeZimu = afterCode.substring(0, 1).charAt(0);
-            Integer afterCodeNum = Integer.parseInt(afterCode.substring(1));
-
-            String nextNum = "";
-            char nextZimu = 'A';
-            // 先判断数字等于999*,则计数从1重新开始,递增
-            if (afterCodeNum == getMaxNumByLength(NUM_LENGTH)) {
-                nextNum = getNextStrNum(0);
-            } else {
-                nextNum = getNextStrNum(afterCodeNum);
-            }
-            // 先判断数字等于999*,则字母从A重新开始,递增
-            if (afterCodeNum == getMaxNumByLength(NUM_LENGTH)) {
-                nextZimu = getNextZiMu(afterCodeZimu);
-            } else {
-                nextZimu = afterCodeZimu;
-            }
-
-            // 例如Z99,下一个code就是Z99A01
-            if ('Z' == afterCodeZimu && getMaxNumByLength(NUM_LENGTH) == afterCodeZimu) {
-                newcode = code + (nextZimu + nextNum);
-            } else {
-                newcode = beforeCode + (nextZimu + nextNum);
-            }
-        }
-        return newcode;
-
-    }
-
-    /**
-     * 根据父亲code,获取下级的下一个code
-     * <p>
-     * 例如:父亲CODE:A01
-     * 当前CODE:A01B03
-     * 获取的code:A01B04
-     *
-     * @param parentCode 上级code
-     * @param localCode  同级code
-     * @return
-     */
-    public static synchronized String getSubYouBianCode(String parentCode, String localCode) {
-        if (localCode != null && localCode != "") {
-            return getNextYouBianCode(localCode);
-        } else {
-            parentCode = parentCode + "A" + getNextStrNum(0);
-        }
-        return parentCode;
-    }
-
-
-    /**
-     * 将数字前面位数补零
-     *
-     * @param num
-     * @return
-     */
-    private static String getNextStrNum(int num) {
-        return getStrNum(getNextNum(num));
-    }
-
-    /**
-     * 将数字前面位数补零
-     *
-     * @param num
-     * @return
-     */
-    private static String getStrNum(int num) {
-        String s = String.format("%0" + NUM_LENGTH + "d", num);
-        return s;
-    }
-
-    /**
-     * 递增获取下个数字
-     *
-     * @param num
-     * @return
-     */
-    private static int getNextNum(int num) {
-        num++;
-        return num;
-    }
-
-    /**
-     * 递增获取下个字母
-     *
-     * @param zimu
-     * @return
-     */
-    private static char getNextZiMu(char zimu) {
-        if (zimu == 'Z') {
-            return 'A';
-        }
-        zimu++;
-        return zimu;
-    }
-
-    /**
-     * 根据数字位数获取最大值
-     *
-     * @param length
-     * @return
-     */
-    private static int getMaxNumByLength(int length) {
-        if (length == 0) {
-            return 0;
-        }
-        String maxNum = "";
-        for (int i = 0; i < length; i++) {
-            maxNum = maxNum + "9";
-        }
-        return Integer.parseInt(maxNum);
-    }
-
-    public static String[] cutYouBianCode(String code) {
-        if (code == null || StringUtil.isNullOrEmpty(code)) {
-            return null;
-        } else {
-            //获取标准长度为numLength+1,截取的数量为code.length/numLength+1
-            int c = code.length() / (NUM_LENGTH + 1);
-            String[] cutcode = new String[c];
-            for (int i = 0; i < c; i++) {
-                cutcode[i] = code.substring(0, (i + 1) * (NUM_LENGTH + 1));
-            }
-            return cutcode;
-        }
-
-    }
+
+	// 数字位数(默认生成3位的数字)
+
+	private static final int numLength = 2;//代表数字位数
+
+	public static final int zhanweiLength = 1+numLength;
+
+	/**
+	 * 根据前一个code,获取同级下一个code
+	 * 例如:当前最大code为D01A04,下一个code为:D01A05
+	 *
+	 * @param code
+	 * @return
+	 */
+	public static synchronized String getNextYouBianCode(String code) {
+		String newcode = "";
+		if (code == null || code =="") {
+			String zimu = "A";
+			String num = getStrNum(1);
+			newcode = zimu + num;
+		} else {
+			String before_code = code.substring(0, code.length() - 1- numLength);
+			String after_code = code.substring(code.length() - 1 - numLength,code.length());
+			char after_code_zimu = after_code.substring(0, 1).charAt(0);
+			Integer after_code_num = Integer.parseInt(after_code.substring(1));
+//			org.jeecgframework.core.util.LogUtil.info(after_code);
+//			org.jeecgframework.core.util.LogUtil.info(after_code_zimu);
+//			org.jeecgframework.core.util.LogUtil.info(after_code_num);
+
+			String nextNum = "";
+			char nextZimu = 'A';
+			// 先判断数字等于999*,则计数从1重新开始,递增
+			if (after_code_num == getMaxNumByLength(numLength)) {
+				nextNum = getNextStrNum(0);
+			} else {
+				nextNum = getNextStrNum(after_code_num);
+			}
+			// 先判断数字等于999*,则字母从A重新开始,递增
+			if(after_code_num == getMaxNumByLength(numLength)) {
+				nextZimu = getNextZiMu(after_code_zimu);
+			}else{
+				nextZimu = after_code_zimu;
+			}
+
+			// 例如Z99,下一个code就是Z99A01
+			if ('Z' == after_code_zimu && getMaxNumByLength(numLength) == after_code_num) {
+				newcode = code + (nextZimu + nextNum);
+			} else {
+				newcode = before_code + (nextZimu + nextNum);
+			}
+		}
+		return newcode;
+
+	}
+
+	/**
+	 * 根据父亲code,获取下级的下一个code
+	 *
+	 * 例如:父亲CODE:A01
+	 *       当前CODE:A01B03
+	 *       获取的code:A01B04
+	 *
+	 * @param parentCode   上级code
+	 * @param localCode    同级code
+	 * @return
+	 */
+	public static synchronized String getSubYouBianCode(String parentCode,String localCode) {
+		if(localCode!=null && localCode!=""){
+
+//			return parentCode + getNextYouBianCode(localCode);
+			return getNextYouBianCode(localCode);
+
+		}else{
+			parentCode = parentCode + "A"+ getNextStrNum(0);
+		}
+		return parentCode;
+	}
+
+
+
+	/**
+	 * 将数字前面位数补零
+	 *
+	 * @param num
+	 * @return
+	 */
+	private static String getNextStrNum(int num) {
+		return getStrNum(getNextNum(num));
+	}
+
+	/**
+	 * 将数字前面位数补零
+	 *
+	 * @param num
+	 * @return
+	 */
+	private static String getStrNum(int num) {
+		String s = String.format("%0" + numLength + "d", num);
+		return s;
+	}
+
+	/**
+	 * 递增获取下个数字
+	 *
+	 * @param num
+	 * @return
+	 */
+	private static int getNextNum(int num) {
+		num++;
+		return num;
+	}
+
+	/**
+	 * 递增获取下个字母
+	 *
+	 * @param num
+	 * @return
+	 */
+	private static char getNextZiMu(char zimu) {
+		if (zimu == 'Z') {
+			return 'A';
+		}
+		zimu++;
+		return zimu;
+	}
+
+	/**
+	 * 根据数字位数获取最大值
+	 * @param length
+	 * @return
+	 */
+	private static int getMaxNumByLength(int length){
+		if(length==0){
+			return 0;
+		}
+		String max_num = "";
+		for (int i=0;i<length;i++){
+			max_num = max_num + "9";
+		}
+		return Integer.parseInt(max_num);
+	}
+	public static String[] cutYouBianCode(String code){
+		if(code==null || StringUtil.isNullOrEmpty(code)){
+			return null;
+		}else{
+			//获取标准长度为numLength+1,截取的数量为code.length/numLength+1
+			int c = code.length()/(numLength+1);
+			String[] cutcode = new String[c];
+			for(int i =0 ; i <c;i++){
+				cutcode[i] = code.substring(0,(i+1)*(numLength+1));
+			}
+			return cutcode;
+		}
+
+	}
+	public static void main(String[] args) {
+		// org.jeecgframework.core.util.LogUtil.info(getNextZiMu('C'));
+		// org.jeecgframework.core.util.LogUtil.info(getNextNum(8));
+	    // org.jeecgframework.core.util.LogUtil.info(cutYouBianCode("C99A01B01")[2]);
+	}
 }

+ 92 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/dynamic/db/DataSourceCachePool.java

@@ -0,0 +1,92 @@
+package org.jeecg.common.util.dynamic.db;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import org.jeecg.common.constant.CacheConstant;
+import org.jeecg.common.system.api.ISysBaseApi;
+import org.jeecg.common.system.vo.DynamicDataSourceModel;
+import org.jeecg.common.util.SpringContextUtils;
+import org.springframework.data.redis.core.RedisTemplate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * 数据源缓存池
+ */
+public class DataSourceCachePool {
+    /** 数据源连接池缓存【本地 class缓存 - 不支持分布式】 */
+    private static Map<String, DruidDataSource> dbSources = new HashMap<>();
+    private static RedisTemplate<String, Object> redisTemplate;
+
+    private static RedisTemplate<String, Object> getRedisTemplate() {
+        if (redisTemplate == null) {
+            redisTemplate = (RedisTemplate<String, Object>) SpringContextUtils.getBean("redisTemplate");
+        }
+        return redisTemplate;
+    }
+
+    /**
+     * 获取多数据源缓存
+     *
+     * @param dbKey
+     * @return
+     */
+    public static DynamicDataSourceModel getCacheDynamicDataSourceModel(String dbKey) {
+        String redisCacheKey = CacheConstant.SYS_DYNAMICDB_CACHE + dbKey;
+        if (getRedisTemplate().hasKey(redisCacheKey)) {
+            return (DynamicDataSourceModel) getRedisTemplate().opsForValue().get(redisCacheKey);
+        }
+        ISysBaseApi sysBaseAPI = SpringContextUtils.getBean(ISysBaseApi.class);
+        DynamicDataSourceModel dbSource = sysBaseAPI.getDynamicDbSourceByCode(dbKey);
+        if (dbSource != null) {
+            getRedisTemplate().opsForValue().set(redisCacheKey, dbSource);
+        }
+        return dbSource;
+    }
+
+    public static DruidDataSource getCacheBasicDataSource(String dbKey) {
+        return dbSources.get(dbKey);
+    }
+
+    /**
+     * put 数据源缓存
+     *
+     * @param dbKey
+     * @param db
+     */
+    public static void putCacheBasicDataSource(String dbKey, DruidDataSource db) {
+        dbSources.put(dbKey, db);
+    }
+
+    /**
+     * 清空数据源缓存
+     */
+    public static void cleanAllCache() {
+        //关闭数据源连接
+        for(Map.Entry<String, DruidDataSource> entry : dbSources.entrySet()){
+            String dbkey = entry.getKey();
+            DruidDataSource druidDataSource = entry.getValue();
+            if(druidDataSource!=null && druidDataSource.isEnable()){
+                druidDataSource.close();
+            }
+            //清空redis缓存
+            getRedisTemplate().delete(CacheConstant.SYS_DYNAMICDB_CACHE + dbkey);
+        }
+        //清空缓存
+        dbSources.clear();
+    }
+
+    public static void removeCache(String dbKey) {
+        //关闭数据源连接
+        DruidDataSource druidDataSource = dbSources.get(dbKey);
+        if(druidDataSource!=null && druidDataSource.isEnable()){
+            druidDataSource.close();
+        }
+        //清空redis缓存
+        getRedisTemplate().delete(CacheConstant.SYS_DYNAMICDB_CACHE + dbKey);
+        //清空缓存
+        dbSources.remove(dbKey);
+    }
+
+}

+ 31 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/dynamic/db/DbValidationQueryEnum.java

@@ -0,0 +1,31 @@
+package org.jeecg.common.util.dynamic.db;
+
+public enum DbValidationQueryEnum {
+    ORACLE("oracle", "SELECT 1 FROM DUAL"),
+    MYSQL("mysql", "select 1"),
+    SQLSERVER("sqlserver", "SELECT 1 FROM DUAL"),;
+
+    DbValidationQueryEnum(String dbType, String validationQuerySql) {
+        this.dbType = dbType;
+        this.validationQuerySql = validationQuerySql;
+    }
+
+    private String dbType;
+    private String validationQuerySql;
+
+    public String getDbType() {
+        return dbType;
+    }
+
+    public void setDbType(String dbType) {
+        this.dbType = dbType;
+    }
+
+    public String getValidationQuerySql() {
+        return validationQuerySql;
+    }
+
+    public void setValidationQuerySql(String validationQuerySql) {
+        this.validationQuerySql = validationQuerySql;
+    }
+}

+ 300 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/dynamic/db/DynamicDBUtil.java

@@ -0,0 +1,300 @@
+package org.jeecg.common.util.dynamic.db;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.ArrayUtils;
+import org.jeecg.common.exception.JeecgBootException;
+import org.jeecg.common.exception.JeecgBootException;
+import org.jeecg.common.system.vo.DynamicDataSourceModel;
+import org.jeecg.common.util.ReflectHelper;
+import org.jeecg.common.util.oConvertUtils;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+
+import javax.sql.DataSource;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Spring JDBC 实时数据库访问
+ *
+ * @author chenguobin
+ * @version 1.0
+ * @date 2014-09-05
+ */
+@Slf4j
+public class DynamicDBUtil {
+
+    /**
+     * 获取数据源【最底层方法,不要随便调用】
+     *
+     * @param dbSource
+     * @return
+     */
+    private static DruidDataSource getJdbcDataSource(final DynamicDataSourceModel dbSource) {
+        DruidDataSource dataSource = new DruidDataSource();
+
+        String driverClassName = dbSource.getDbDriver();
+        String url = dbSource.getDbUrl();
+        String dbUser = dbSource.getDbUsername();
+        String dbPassword = dbSource.getDbPassword();
+        dataSource.setDriverClassName(driverClassName);
+        dataSource.setUrl(url);
+        //dataSource.setValidationQuery("SELECT 1 FROM DUAL");
+        dataSource.setTestWhileIdle(true);
+        dataSource.setTestOnBorrow(false);
+        dataSource.setTestOnReturn(false);
+        dataSource.setBreakAfterAcquireFailure(true);
+        dataSource.setConnectionErrorRetryAttempts(0);
+        dataSource.setUsername(dbUser);
+        dataSource.setMaxWait(60000);
+        dataSource.setPassword(dbPassword);
+
+        log.info("******************************************");
+        log.info("*                                        *");
+        log.info("*====【"+dbSource.getCode()+"】=====Druid连接池已启用 ====*");
+        log.info("*                                        *");
+        log.info("******************************************");
+        return dataSource;
+    }
+
+    /**
+     * 通过 dbKey ,获取数据源
+     *
+     * @param dbKey
+     * @return
+     */
+    public static DruidDataSource getDbSourceByDbKey(final String dbKey) {
+        //获取多数据源配置
+        DynamicDataSourceModel dbSource = DataSourceCachePool.getCacheDynamicDataSourceModel(dbKey);
+        //先判断缓存中是否存在数据库链接
+        DruidDataSource cacheDbSource = DataSourceCachePool.getCacheBasicDataSource(dbKey);
+        if (cacheDbSource != null && !cacheDbSource.isClosed()) {
+            log.debug("--------getDbSourceBydbKey------------------从缓存中获取DB连接-------------------");
+            return cacheDbSource;
+        } else {
+            DruidDataSource dataSource = getJdbcDataSource(dbSource);
+            if(dataSource!=null && dataSource.isEnable()){
+                DataSourceCachePool.putCacheBasicDataSource(dbKey, dataSource);
+            }else{
+                throw new JeecgBootException("动态数据源连接失败,dbKey:"+dbKey);
+            }
+            log.info("--------getDbSourceBydbKey------------------创建DB数据库连接-------------------");
+            return dataSource;
+        }
+    }
+
+    /**
+     * 关闭数据库连接池
+     *
+     * @param dbKey
+     * @return
+     */
+    public static void closeDbKey(final String dbKey) {
+        DruidDataSource dataSource = getDbSourceByDbKey(dbKey);
+        try {
+            if (dataSource != null && !dataSource.isClosed()) {
+                dataSource.getConnection().commit();
+                dataSource.getConnection().close();
+                dataSource.close();
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    private static JdbcTemplate getJdbcTemplate(String dbKey) {
+        DruidDataSource dataSource = getDbSourceByDbKey(dbKey);
+        return new JdbcTemplate(dataSource);
+    }
+
+    /**
+     * Executes the SQL statement in this <code>PreparedStatement</code> object,
+     * which must be an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
+     * <code>DELETE</code>; or an SQL statement that returns nothing,
+     * such as a DDL statement.
+     */
+    public static int update(final String dbKey, String sql, Object... param) {
+        int effectCount;
+        JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
+        if (ArrayUtils.isEmpty(param)) {
+            effectCount = jdbcTemplate.update(sql);
+        } else {
+            effectCount = jdbcTemplate.update(sql, param);
+        }
+        return effectCount;
+    }
+
+    /**
+     * 支持miniDao语法操作的Update
+     *
+     * @param dbKey 数据源标识
+     * @param sql   执行sql语句,sql支持minidao语法逻辑
+     * @param data  sql语法中需要判断的数据及sql拼接注入中需要的数据
+     * @return
+     */
+    public static int updateByHash(final String dbKey, String sql, HashMap<String, Object> data) {
+        int effectCount;
+        JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
+        //根据模板获取sql
+        sql = FreemarkerParseFactory.parseTemplateContent(sql, data);
+        NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());
+        effectCount = namedParameterJdbcTemplate.update(sql, data);
+        return effectCount;
+    }
+
+    public static Object findOne(final String dbKey, String sql, Object... param) {
+        List<Map<String, Object>> list;
+        list = findList(dbKey, sql, param);
+        if (oConvertUtils.listIsEmpty(list)) {
+            log.error("Except one, but not find actually");
+        }
+        if (list.size() > 1) {
+            log.error("Except one, but more than one actually");
+        }
+        return list.get(0);
+    }
+
+    /**
+     * 支持miniDao语法操作的查询 返回HashMap
+     *
+     * @param dbKey 数据源标识
+     * @param sql   执行sql语句,sql支持minidao语法逻辑
+     * @param data  sql语法中需要判断的数据及sql拼接注入中需要的数据
+     * @return
+     */
+    public static Object findOneByHash(final String dbKey, String sql, HashMap<String, Object> data) {
+        List<Map<String, Object>> list;
+        list = findListByHash(dbKey, sql, data);
+        if (oConvertUtils.listIsEmpty(list)) {
+            log.error("Except one, but not find actually");
+        }
+        if (list.size() > 1) {
+            log.error("Except one, but more than one actually");
+        }
+        return list.get(0);
+    }
+
+    /**
+     * 直接sql查询 根据clazz返回单个实例
+     *
+     * @param dbKey 数据源标识
+     * @param sql   执行sql语句
+     * @param clazz 返回实例的Class
+     * @param param
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Object findOne(final String dbKey, String sql, Class<T> clazz, Object... param) {
+        Map<String, Object> map = (Map<String, Object>) findOne(dbKey, sql, param);
+        return ReflectHelper.setAll(clazz, map);
+    }
+
+    /**
+     * 支持miniDao语法操作的查询 返回单个实例
+     *
+     * @param dbKey 数据源标识
+     * @param sql   执行sql语句,sql支持minidao语法逻辑
+     * @param clazz 返回实例的Class
+     * @param data  sql语法中需要判断的数据及sql拼接注入中需要的数据
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Object findOneByHash(final String dbKey, String sql, Class<T> clazz, HashMap<String, Object> data) {
+        Map<String, Object> map = (Map<String, Object>) findOneByHash(dbKey, sql, data);
+        return ReflectHelper.setAll(clazz, map);
+    }
+
+    public static List<Map<String, Object>> findList(final String dbKey, String sql, Object... param) {
+        List<Map<String, Object>> list;
+        JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
+
+        if (ArrayUtils.isEmpty(param)) {
+            list = jdbcTemplate.queryForList(sql);
+        } else {
+            list = jdbcTemplate.queryForList(sql, param);
+        }
+        return list;
+    }
+
+    /**
+     * 支持miniDao语法操作的查询
+     *
+     * @param dbKey 数据源标识
+     * @param sql   执行sql语句,sql支持minidao语法逻辑
+     * @param data  sql语法中需要判断的数据及sql拼接注入中需要的数据
+     * @return
+     */
+    public static List<Map<String, Object>> findListByHash(final String dbKey, String sql, HashMap<String, Object> data) {
+        List<Map<String, Object>> list;
+        JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
+        //根据模板获取sql
+        sql = FreemarkerParseFactory.parseTemplateContent(sql, data);
+        NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());
+        list = namedParameterJdbcTemplate.queryForList(sql, data);
+        return list;
+    }
+
+    //此方法只能返回单列,不能返回实体类
+    public static <T> List<T> findList(final String dbKey, String sql, Class<T> clazz, Object... param) {
+        List<T> list;
+        JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
+
+        if (ArrayUtils.isEmpty(param)) {
+            list = jdbcTemplate.queryForList(sql, clazz);
+        } else {
+            list = jdbcTemplate.queryForList(sql, clazz, param);
+        }
+        return list;
+    }
+
+    /**
+     * 支持miniDao语法操作的查询 返回单列数据list
+     *
+     * @param dbKey 数据源标识
+     * @param sql   执行sql语句,sql支持minidao语法逻辑
+     * @param clazz 类型Long、String等
+     * @param data  sql语法中需要判断的数据及sql拼接注入中需要的数据
+     * @return
+     */
+    public static <T> List<T> findListByHash(final String dbKey, String sql, Class<T> clazz, HashMap<String, Object> data) {
+        List<T> list;
+        JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
+        //根据模板获取sql
+        sql = FreemarkerParseFactory.parseTemplateContent(sql, data);
+        NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());
+        list = namedParameterJdbcTemplate.queryForList(sql, data, clazz);
+        return list;
+    }
+
+    /**
+     * 直接sql查询 返回实体类列表
+     *
+     * @param dbKey 数据源标识
+     * @param sql   执行sql语句,sql支持 minidao 语法逻辑
+     * @param clazz 返回实体类列表的class
+     * @param param sql拼接注入中需要的数据
+     * @return
+     */
+    public static <T> List<T> findListEntities(final String dbKey, String sql, Class<T> clazz, Object... param) {
+        List<Map<String, Object>> queryList = findList(dbKey, sql, param);
+        return ReflectHelper.transList2Entrys(queryList, clazz);
+    }
+
+    /**
+     * 支持miniDao语法操作的查询 返回实体类列表
+     *
+     * @param dbKey 数据源标识
+     * @param sql   执行sql语句,sql支持minidao语法逻辑
+     * @param clazz 返回实体类列表的class
+     * @param data  sql语法中需要判断的数据及sql拼接注入中需要的数据
+     * @return
+     */
+    public static <T> List<T> findListEntitiesByHash(final String dbKey, String sql, Class<T> clazz, HashMap<String, Object> data) {
+        List<Map<String, Object>> queryList = findListByHash(dbKey, sql, data);
+        return ReflectHelper.transList2Entrys(queryList, clazz);
+    }
+}

+ 173 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/dynamic/db/FreemarkerParseFactory.java

@@ -0,0 +1,173 @@
+package org.jeecg.common.util.dynamic.db;
+
+import freemarker.cache.StringTemplateLoader;
+import freemarker.core.ParseException;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jeecgframework.codegenerate.generate.util.SimpleFormat;
+
+import java.io.StringWriter;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * @author 赵俊夫
+ * @version V1.0
+ * @Title:FreemarkerHelper
+ * @description:Freemarker引擎协助类
+ * @date Jul 5, 2013 2:58:29 PM
+ */
+@Slf4j
+public class FreemarkerParseFactory {
+
+    private static final String ENCODE = "utf-8";
+    /**
+     * 参数格式化工具类
+     */
+    private static final String MINI_DAO_FORMAT = "DaoFormat";
+
+    /**
+     * 文件缓存
+     */
+    private static final Configuration _tplConfig = new Configuration();
+    /**
+     * SQL 缓存
+     */
+    private static final Configuration _sqlConfig = new Configuration();
+
+    private static StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
+
+    // 使用内嵌的(?ms)打开单行和多行模式
+    private final static Pattern p = Pattern
+            .compile("(?ms)/\\*.*?\\*/|^\\s*//.*?$");
+
+    static {
+        _tplConfig.setClassForTemplateLoading(
+                new FreemarkerParseFactory().getClass(), "/");
+        _tplConfig.setNumberFormat("0.#####################");
+        _sqlConfig.setTemplateLoader(stringTemplateLoader);
+        _sqlConfig.setNumberFormat("0.#####################");
+        //classic_compatible设置,解决报空指针错误
+        _sqlConfig.setClassicCompatible(true);
+    }
+
+    /**
+     * 判断模板是否存在
+     *
+     * @throws Exception
+     */
+    public static boolean isExistTemplate(String tplName) throws Exception {
+        try {
+            Template mytpl = _tplConfig.getTemplate(tplName, "UTF-8");
+            if (mytpl == null) {
+                return false;
+            }
+        } catch (Exception e) {
+            //update-begin--Author:scott  Date:20180320 for:解决问题 - 错误提示sql文件不存在,实际问题是sql freemarker用法错误-----
+            if (e instanceof ParseException) {
+                log.error(e.getMessage(), e.fillInStackTrace());
+                throw new Exception(e);
+            }
+            log.debug("----isExistTemplate----" + e.toString());
+            //update-end--Author:scott  Date:20180320 for:解决问题 - 错误提示sql文件不存在,实际问题是sql freemarker用法错误------
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 解析ftl模板
+     *
+     * @param tplName 模板名
+     * @param paras   参数
+     * @return
+     */
+    public static String parseTemplate(String tplName, Map<String, Object> paras) {
+        try {
+            log.debug(" minidao sql templdate : " + tplName);
+            StringWriter swriter = new StringWriter();
+            Template mytpl = _tplConfig.getTemplate(tplName, ENCODE);
+            if (paras.containsKey(MINI_DAO_FORMAT)) {
+                throw new RuntimeException("DaoFormat 是 minidao 保留关键字,不允许使用 ,请更改参数定义!");
+            }
+            paras.put(MINI_DAO_FORMAT, new SimpleFormat());
+            mytpl.process(paras, swriter);
+            String sql = getSqlText(swriter.toString());
+            paras.remove(MINI_DAO_FORMAT);
+            return sql;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e.fillInStackTrace());
+            log.error("发送一次的模板key:{ " + tplName + " }");
+            //System.err.println(e.getMessage());
+            //System.err.println("模板名:{ "+ tplName +" }");
+            throw new RuntimeException("解析SQL模板异常");
+        }
+    }
+
+    /**
+     * 解析ftl
+     *
+     * @param tplContent 模板内容
+     * @param paras      参数
+     * @return String 模板解析后内容
+     */
+    public static String parseTemplateContent(String tplContent,
+                                              Map<String, Object> paras) {
+        try {
+            StringWriter swriter = new StringWriter();
+            if (stringTemplateLoader.findTemplateSource("sql_" + tplContent.hashCode()) == null) {
+                stringTemplateLoader.putTemplate("sql_" + tplContent.hashCode(), tplContent);
+            }
+            Template mytpl = _sqlConfig.getTemplate("sql_" + tplContent.hashCode(), ENCODE);
+            if (paras.containsKey(MINI_DAO_FORMAT)) {
+                throw new RuntimeException("DaoFormat 是 minidao 保留关键字,不允许使用 ,请更改参数定义!");
+            }
+            paras.put(MINI_DAO_FORMAT, new SimpleFormat());
+            mytpl.process(paras, swriter);
+            String sql = getSqlText(swriter.toString());
+            paras.remove(MINI_DAO_FORMAT);
+            return sql;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e.fillInStackTrace());
+            log.error("发送一次的模板key:{ " + tplContent + " }");
+            //System.err.println(e.getMessage());
+            //System.err.println("模板内容:{ "+ tplContent +" }");
+            throw new RuntimeException("解析SQL模板异常");
+        }
+    }
+
+    /**
+     * 除去无效字段,去掉注释 不然批量处理可能报错 去除无效的等于
+     */
+    private static String getSqlText(String sql) {
+        // 将注释替换成""
+        sql = p.matcher(sql).replaceAll("");
+        sql = sql.replaceAll("\\n", " ").replaceAll("\\t", " ")
+                .replaceAll("\\s{1,}", " ").trim();
+        // 去掉 最后是 where这样的问题
+        if (sql.endsWith("where") || sql.endsWith("where ")) {
+            sql = sql.substring(0, sql.lastIndexOf("where"));
+        }
+        // 去掉where and 这样的问题
+        int index = 0;
+        while ((index = StringUtils.indexOfIgnoreCase(sql, "where and", index)) != -1) {
+            sql = sql.substring(0, index + 5)
+                    + sql.substring(index + 9, sql.length());
+        }
+        // 去掉 , where 这样的问题
+        index = 0;
+        while ((index = StringUtils.indexOfIgnoreCase(sql, ", where", index)) != -1) {
+            sql = sql.substring(0, index)
+                    + sql.substring(index + 1, sql.length());
+        }
+        // 去掉 最后是 ,这样的问题
+        if (sql.endsWith(",") || sql.endsWith(", ")) {
+            sql = sql.substring(0, sql.lastIndexOf(","));
+        }
+        return sql;
+    }
+}

+ 212 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/dynamic/db/SqlUtils.java

@@ -0,0 +1,212 @@
+package org.jeecg.common.util.dynamic.db;
+
+import org.apache.commons.lang.StringUtils;
+import org.jeecg.common.constant.DataBaseConstant;
+import org.jeecg.common.system.vo.DynamicDataSourceModel;
+
+import java.text.MessageFormat;
+import java.util.Map;
+
+/**
+ * 根据不同的数据库,动态生成SQL,例如分页
+ */
+public class SqlUtils {
+
+    public static final String DATABSE_TYPE_MYSQL = "mysql";
+    public static final String DATABSE_TYPE_POSTGRE = "postgresql";
+    public static final String DATABSE_TYPE_ORACLE = "oracle";
+    public static final String DATABSE_TYPE_SQLSERVER = "sqlserver";
+
+
+    /**
+     * 分页SQL
+     */
+    public static final String MYSQL_SQL = "select * from ( {0}) sel_tab00 limit {1},{2}";
+    public static final String POSTGRE_SQL = "select * from ( {0}) sel_tab00 limit {2} offset {1}";
+    public static final String ORACLE_SQL = "select * from (select row_.*,rownum rownum_ from ({0}) row_ where rownum <= {1}) where rownum_>{2}";
+    public static final String SQLSERVER_SQL = "select * from ( select row_number() over(order by tempColumn) tempRowNumber, * from (select top {1} tempColumn = 0, {0}) t ) tt where tempRowNumber > {2}";
+
+    /**
+     * 获取所有表的SQL
+     */
+    public static final String MYSQL_ALLTABLES_SQL = "select distinct table_name from information_schema.columns where table_schema = {0}";
+    public static final String POSTGRE__ALLTABLES_SQL = "SELECT distinct c.relname AS  table_name FROM pg_class c";
+    public static final String ORACLE__ALLTABLES_SQL = "select distinct colstable.table_name as  table_name from user_tab_cols colstable";
+    public static final String SQLSERVER__ALLTABLES_SQL = "select distinct c.name as  table_name from sys.objects c";
+
+    /**
+     * 获取指定表的所有列名
+     */
+    public static final String MYSQL_ALLCOLUMNS_SQL = "select column_name from information_schema.columns where table_name = {0} and table_schema = {1}";
+    public static final String POSTGRE_ALLCOLUMNS_SQL = "select table_name from information_schema.columns where table_name = {0}";
+    public static final String ORACLE_ALLCOLUMNS_SQL = "select column_name from all_tab_columns where table_name ={0}";
+    public static final String SQLSERVER_ALLCOLUMNS_SQL = "select name from syscolumns where id={0}";
+
+    /*
+     * 判断数据库类型
+     */
+
+    public static boolean dbTypeIsMySQL(String dbType) {
+        return dbTypeIf(dbType, DATABSE_TYPE_MYSQL, DataBaseConstant.DB_TYPE_MYSQL_NUM);
+    }
+
+    public static boolean dbTypeIsOracle(String dbType) {
+        return dbTypeIf(dbType, DATABSE_TYPE_ORACLE, DataBaseConstant.DB_TYPE_ORACLE_NUM);
+    }
+
+    public static boolean dbTypeIsSQLServer(String dbType) {
+        return dbTypeIf(dbType, DATABSE_TYPE_SQLSERVER, DataBaseConstant.DB_TYPE_SQLSERVER_NUM);
+    }
+
+    public static boolean dbTypeIsPostgre(String dbType) {
+        return dbTypeIf(dbType, DATABSE_TYPE_POSTGRE, DataBaseConstant.DB_TYPE_POSTGRESQL_NUM);
+    }
+
+    /**
+     * 判断数据库类型
+     */
+    public static boolean dbTypeIf(String dbType, String... correctTypes) {
+        for (String type : correctTypes) {
+            if (type.equalsIgnoreCase(dbType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 获取全 SQL
+     * 拼接 where 条件
+     *
+     * @param sql
+     * @param params
+     * @return
+     */
+    public static String getFullSql(String sql, Map params) {
+        return getFullSql(sql, params, null, null);
+    }
+
+    /**
+     * 获取全 SQL
+     * 拼接 where 条件
+     * 拼接 order 排序
+     *
+     * @param sql
+     * @param params
+     * @param orderColumn 排序字段
+     * @param orderBy     排序方式,只能是 DESC 或 ASC
+     * @return
+     */
+    public static String getFullSql(String sql, Map params, String orderColumn, String orderBy) {
+        StringBuilder sqlBuilder = new StringBuilder();
+        sqlBuilder.append("SELECT t.* FROM ( ").append(sql).append(" ) t ");
+        if (params != null && params.size() >= 1) {
+            sqlBuilder.append("WHERE 1=1 ");
+            for (Object key : params.keySet()) {
+                String value = String.valueOf(params.get(key));
+                if (StringUtils.isNotBlank(value)) {
+                    sqlBuilder.append(" AND (").append(key).append(" = N'").append(value).append("')");
+                }
+            }
+            if (StringUtils.isNotBlank(orderColumn) && StringUtils.isNotBlank(orderBy)) {
+                sqlBuilder.append("ORDER BY ").append(orderColumn).append(" ").append("DESC".equalsIgnoreCase(orderBy) ? "DESC" : "ASC");
+            }
+        }
+        return sqlBuilder.toString();
+    }
+
+    /**
+     * 获取求数量 SQL
+     *
+     * @param sql
+     * @return
+     */
+    public static String getCountSql(String sql) {
+        return String.format("SELECT COUNT(1) \"total\" FROM ( %s ) temp_count", sql);
+    }
+
+    /**
+     * 生成分页查询 SQL
+     *
+     * @param dbType 数据库类型
+     * @param sql
+     * @param page
+     * @param rows
+     * @return
+     */
+    public static String createPageSqlByDBType(String dbType, String sql, int page, int rows) {
+        int beginNum = (page - 1) * rows;
+        Object[] sqlParam = new Object[3];
+        sqlParam[0] = sql;
+        sqlParam[1] = String.valueOf(beginNum);
+        sqlParam[2] = String.valueOf(rows);
+        if (dbTypeIsMySQL(dbType)) {
+            sql = MessageFormat.format(MYSQL_SQL, sqlParam);
+        } else if (dbTypeIsPostgre(dbType)) {
+            sql = MessageFormat.format(POSTGRE_SQL, sqlParam);
+        } else {
+            int beginIndex = (page - 1) * rows;
+            int endIndex = beginIndex + rows;
+            sqlParam[2] = Integer.toString(beginIndex);
+            sqlParam[1] = Integer.toString(endIndex);
+            if (dbTypeIsOracle(dbType)) {
+                sql = MessageFormat.format(ORACLE_SQL, sqlParam);
+            } else if (dbTypeIsSQLServer(dbType)) {
+                sqlParam[0] = sql.substring(getAfterSelectInsertPoint(sql));
+                sql = MessageFormat.format(SQLSERVER_SQL, sqlParam);
+            }
+        }
+        return sql;
+    }
+
+    /**
+     * 生成分页查询 SQL
+     *
+     * @param sql
+     * @param page
+     * @param rows
+     * @return
+     */
+    public static String createPageSqlByDBKey(String dbKey, String sql, int page, int rows) {
+        DynamicDataSourceModel dynamicSourceEntity = DataSourceCachePool.getCacheDynamicDataSourceModel(dbKey);
+        String dbType = dynamicSourceEntity.getDbType();
+        return createPageSqlByDBType(dbType, sql, page, rows);
+    }
+
+    private static int getAfterSelectInsertPoint(String sql) {
+        int selectIndex = sql.toLowerCase().indexOf("select");
+        int selectDistinctIndex = sql.toLowerCase().indexOf("select distinct");
+        return selectIndex + (selectDistinctIndex == selectIndex ? 15 : 6);
+    }
+
+    public static String getAllTableSql(String dbType, Object... params) {
+        if (StringUtils.isNotEmpty(dbType)) {
+            if (dbTypeIsMySQL(dbType)) {
+                return MessageFormat.format(MYSQL_ALLTABLES_SQL, params);
+            } else if (dbTypeIsOracle(dbType)) {
+                return ORACLE__ALLTABLES_SQL;
+            } else if (dbTypeIsPostgre(dbType)) {
+                return POSTGRE__ALLTABLES_SQL;
+            } else if (dbTypeIsSQLServer(dbType)) {
+                return SQLSERVER__ALLTABLES_SQL;
+            }
+        }
+        return null;
+    }
+
+    public static String getAllColumnSQL(String dbType, Object... params) {
+        if (StringUtils.isNotEmpty(dbType)) {
+            if (dbTypeIsMySQL(dbType)) {
+                return MessageFormat.format(MYSQL_ALLCOLUMNS_SQL, params);
+            } else if (dbTypeIsOracle(dbType)) {
+                return MessageFormat.format(ORACLE_ALLCOLUMNS_SQL, params);
+            } else if (dbTypeIsPostgre(dbType)) {
+                return MessageFormat.format(POSTGRE_ALLCOLUMNS_SQL, params);
+            } else if (dbTypeIsSQLServer(dbType)) {
+                return MessageFormat.format(SQLSERVER_ALLCOLUMNS_SQL, params);
+            }
+        }
+        return null;
+    }
+
+}

+ 28 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/BaseColumn.java

@@ -0,0 +1,28 @@
+package org.jeecg.common.util.jsonschema;
+
+import lombok.Data;
+
+/**
+ * 列 配置基本信息
+ */
+@Data
+public class BaseColumn {
+
+    /**
+     * 列配置 描述 -对应数据库字段描述
+     */
+    private String title;
+
+    /**
+     * 列配置 名称 -对应数据库字段名
+     */
+    private String field;
+
+    public BaseColumn(){}
+
+    public BaseColumn(String title,String field){
+        this.title = title;
+        this.field = field;
+    }
+
+}

+ 98 - 27
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/CommonProperty.java

@@ -4,7 +4,7 @@ import java.io.Serializable;
 import java.util.List;
 import java.util.Map;
 
-import lombok.Data;
+import org.apache.commons.lang.StringUtils;
 import org.jeecg.common.system.vo.DictModel;
 
 import com.alibaba.fastjson.JSONObject;
@@ -12,30 +12,34 @@ import com.alibaba.fastjson.JSONObject;
 /**
  * 验证通用属性
  */
-@Data
 public abstract class CommonProperty implements Serializable{
+
 	private static final long serialVersionUID = -426159949502493187L;
+
+
 	protected String key;
+
+
 	/**
 	 * <p>此关键字的值必须是字符串或数组。如果它是一个数组,那么数组的元素必须是字符串,并且必须是唯一的。
 	 * <p>字符串值必须是六种基本类型之一(“null”,“boolean”,“object”,“array”,“number”或“string”),或“integer”,它匹配任何数字,零分数部分。
 	 * <p>当且仅当实例位于为此关键字列出的任何集合中时,实例才会验证。
-     *
+	 *
 	 */
 	protected String type;
-	
+
 	/**
 	 * 对应JsonSchema的enum
 	 * <p>该关键字的值必须是一个数组。这个数组应该至少有一个元素。数组中的元素应该是唯一的。如果实例的值等于此关键字的数组值中的某个元素,则实例将对此关键字成功验证。
 	 * 数组中的元素可以是任何值,包括null
-	 * 
+	 *
 	 *  {
 	 *   "type": "string",
 	 *   "enum": ["1", "2", "3"] 需要的话可以通过这个include转一下
 	 *	}
 	 */
 	protected List<DictModel> include;
-	
+
 	/**
 	 * 对应JsonSchema的const
 	 * <p>此关键字的值可以是任何类型,包括null。
@@ -43,25 +47,87 @@ public abstract class CommonProperty implements Serializable{
 	 */
 	protected Object constant;
 
-    /**
-     * 三个自定义 属性
-     */
-    /**
-     * 展示类型
-     */
-    protected String view;
-    /**
-     * 数据库字段备注
-     */
-    protected String title;
-    /**
-     * 字段显示排序
-     */
-    protected Integer order;
-    /**
-     * 是否禁用
-     */
-    protected boolean disabled;
+	//三个自定义 属性
+	protected String view;// 展示类型
+	protected String title;//数据库字段备注
+	protected Integer order;//字段显示排序
+
+	protected boolean disabled;//是否禁用
+
+	protected String defVal; // 字段默认值
+
+	public String getDefVal() {
+		return defVal;
+	}
+
+	public void setDefVal(String defVal) {
+		this.defVal = defVal;
+	}
+
+	public boolean isDisabled() {
+		return disabled;
+	}
+
+	public void setDisabled(boolean disabled) {
+		this.disabled = disabled;
+	}
+
+	public String getView() {
+		return view;
+	}
+
+	public void setView(String view) {
+		this.view = view;
+	}
+
+	public String getKey() {
+		return key;
+	}
+
+	public void setKey(String key) {
+		this.key = key;
+	}
+
+	public String getType() {
+		return type;
+	}
+
+	public void setType(String type) {
+		this.type = type;
+	}
+
+	public List<DictModel> getInclude() {
+		return include;
+	}
+
+	public void setInclude(List<DictModel> include) {
+		this.include = include;
+	}
+
+	public Object getConstant() {
+		return constant;
+	}
+
+	public void setConstant(Object constant) {
+		this.constant = constant;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public Integer getOrder() {
+		return order;
+	}
+
+	public void setOrder(Integer order) {
+		this.order = order;
+	}
+
 	/**
 	 * 返回一个map有两个key
 	 * <P>key ---> Property JSON的key
@@ -69,8 +135,8 @@ public abstract class CommonProperty implements Serializable{
 	 * @return
 	 */
 	public abstract Map<String,Object> getPropertyJson();
-	
-    public JSONObject getCommonJson() {
+
+	public JSONObject getCommonJson() {
 		JSONObject json = new JSONObject();
 		json.put("type", type);
 		if(include!=null && include.size()>0) {
@@ -95,6 +161,11 @@ public abstract class CommonProperty implements Serializable{
 			JSONObject ui = JSONObject.parseObject(str);
 			json.put("ui", ui);
 		}
+		if (StringUtils.isNotBlank(defVal)) {
+			json.put("defVal", defVal);
+		}
 		return json;
 	}
+
+
 }

+ 8 - 8
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/JsonSchemaDescrip.java

@@ -13,9 +13,9 @@ public class JsonSchemaDescrip implements Serializable{
 	 * 
 	 */
 	private static final long serialVersionUID = 7682073117441544718L;
-
-
-	private String schema = "http://json-schema.org/draft-07/schema#";
+	
+	
+	private String $schema = "http://json-schema.org/draft-07/schema#";
 	
 	/**
 	 * 用它给我们的模式提供了标题。
@@ -43,12 +43,12 @@ public class JsonSchemaDescrip implements Serializable{
 		this.required = required;
 	}
 
-    public String getSchema() {
-		return schema;
-    }
+	public String get$schema() {
+		return $schema;
+	}
 
-    public void setSchema(String schema) {
-		this.schema = schema;
+	public void set$schema(String $schema) {
+		this.$schema = $schema;
 	}
 
 	public String getTitle() {

+ 12 - 41
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/JsonschemaUtil.java

@@ -1,26 +1,27 @@
 package org.jeecg.common.util.jsonschema;
 
-import com.alibaba.fastjson.JSONObject;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.*;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import lombok.extern.slf4j.Slf4j;
+
 @Slf4j
 public class JsonschemaUtil {
-
+	
 	/**
 	 * 生成JsonSchema
-     *
+	 * 
 	 * @param descrip
 	 * @param propertyList
 	 * @return
 	 */
 	public static JSONObject getJsonSchema(JsonSchemaDescrip descrip, List<CommonProperty> propertyList) {
 		JSONObject obj = new JSONObject();
-        obj.put("$schema", descrip.getSchema());
+		obj.put("$schema", descrip.get$schema());
 		obj.put("type", descrip.getType());
 		obj.put("title", descrip.getTitle());
 
@@ -34,11 +35,11 @@ public class JsonschemaUtil {
 		}
 		obj.put("properties", properties);
 		//鬼知道这里为什么报错 org.jeecg.modules.system.model.DictModel cannot be cast to org.jeecg.modules.system.model.DictModel
-        log.info("---JSONSchema--->" + obj.toJSONString());
+		//log.info("---JSONSchema--->"+obj.toJSONString());
 		return obj;
 	}
-
-    /**
+	
+	/**
 	 * 生成JsonSchema 用于子对象
 	 * @param title 子对象描述
 	 * @param requiredArr 子对象必填属性名集合
@@ -62,38 +63,8 @@ public class JsonschemaUtil {
 			properties.put(map.get("key").toString(), map.get("prop"));
 		}
 		obj.put("properties", properties);
-        log.info("---JSONSchema--->" + obj.toString());
+		//log.info("---JSONSchema--->"+obj.toString());
 		return obj;
 	}
 
-    /**
-     * 读取json文件,返回json串
-     *
-     * @param fileName
-     * @return
-     */
-	public static String readJsonFile(String fileName) throws IOException {
-        String jsonStr = "";
-		FileReader fileReader = null;
-		Reader reader = null;
-		try {
-            File jsonFile = new File(fileName);
-			fileReader = new FileReader(jsonFile);
-			reader = new InputStreamReader(new FileInputStream(jsonFile), "utf-8");
-            int ch = 0;
-            StringBuffer sb = new StringBuffer();
-            while ((ch = reader.read()) != -1) {
-                sb.append((char) ch);
-            }
-            jsonStr = sb.toString();
-            return jsonStr;
-		} catch (Exception e) {
-            e.printStackTrace();
-            return null;
-		} finally {
-			fileReader.close();
-			reader.close();
-		}
-    }
-
 }

+ 1 - 1
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/DictProperty.java

@@ -15,7 +15,7 @@ import com.alibaba.fastjson.JSONObject;
  */
 @Data
 public class DictProperty extends CommonProperty {
-	
+
 	private static final long serialVersionUID = 3786503639885610767L;
 
     /**

+ 38 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/HiddenProperty.java

@@ -0,0 +1,38 @@
+package org.jeecg.common.util.jsonschema.validate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jeecg.common.util.jsonschema.CommonProperty;
+
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * 字典属性
+ * @author 86729
+ *
+ */
+public class HiddenProperty extends CommonProperty {
+	
+	private static final long serialVersionUID = -8939298551502162479L;
+	
+	public HiddenProperty() {}
+	
+	public HiddenProperty(String key,String title) {
+		this.type = "string";
+		this.view = "hidden";
+		this.key = key;
+		this.title = title;
+	}
+	
+	@Override
+	public Map<String, Object> getPropertyJson() {
+		Map<String,Object> map = new HashMap<>();
+		map.put("key",getKey());
+		JSONObject prop = getCommonJson();
+		prop.put("hidden",true);
+		map.put("prop",prop);
+		return map;
+	}
+
+}

+ 66 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/LinkDownProperty.java

@@ -0,0 +1,66 @@
+package org.jeecg.common.util.jsonschema.validate;
+
+import com.alibaba.fastjson.JSONObject;
+import org.jeecg.common.util.jsonschema.BaseColumn;
+import org.jeecg.common.util.jsonschema.CommonProperty;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 级联下拉
+ */
+public class LinkDownProperty extends CommonProperty {
+
+    /**
+     * 配置信息
+     */
+    String dictTable;
+
+    /**
+     * 级联下拉组件 的其他级联列
+     */
+    List<BaseColumn> otherColumns;
+
+    public String getDictTable(){
+        return this.dictTable;
+    }
+
+    public void setDictTable(String dictTable){
+        this.dictTable = dictTable;
+    }
+
+    public List<BaseColumn> getOtherColumns(){
+        return this.otherColumns;
+    }
+
+    public void setOtherColumns(List<BaseColumn> otherColumns){
+        this.otherColumns = otherColumns;
+    }
+
+    public LinkDownProperty() {}
+
+    /**
+     *  构造器
+     */
+    public LinkDownProperty(String key,String title,String dictTable) {
+        this.type = "string";
+        this.view = "link_down";
+        this.key = key;
+        this.title = title;
+        this.dictTable= dictTable;
+    }
+
+    @Override
+    public Map<String, Object> getPropertyJson() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("key", getKey());
+        JSONObject prop = getCommonJson();
+        JSONObject temp = JSONObject.parseObject(this.dictTable);
+        prop.put("config", temp);
+        prop.put("others", otherColumns);
+        map.put("prop", prop);
+        return map;
+    }
+}

+ 0 - 3
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/NumberProperty.java

@@ -43,7 +43,6 @@ public class NumberProperty extends CommonProperty {
 	 * 大于等于
 	 */
 	private Integer exclusiveMinimum;
-
 	
 	private String pattern;
 
@@ -86,7 +85,6 @@ public class NumberProperty extends CommonProperty {
 	public void setExclusiveMinimum(Integer exclusiveMinimum) {
 		this.exclusiveMinimum = exclusiveMinimum;
 	}
-
 	
 	public String getPattern() {
 		return pattern;
@@ -149,7 +147,6 @@ public class NumberProperty extends CommonProperty {
 		if(pattern!=null) {
 			prop.put("pattern",pattern);
 		}
-
 		map.put("prop",prop);
 		return map;
 	}

+ 23 - 27
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/StringProperty.java

@@ -1,36 +1,32 @@
 package org.jeecg.common.util.jsonschema.validate;
 
-import com.alibaba.fastjson.JSONObject;
-import org.jeecg.common.system.vo.DictModel;
-import org.jeecg.common.util.jsonschema.CommonProperty;
-
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-/**
- * @author jeecg-boot
- * 2019年12月5日19:57:58
- */
-public class StringProperty extends CommonProperty {
+import org.jeecg.common.system.vo.DictModel;
+import org.jeecg.common.util.jsonschema.CommonProperty;
 
-	private static final long serialVersionUID = -3200493311633999539L;
+import com.alibaba.fastjson.JSONObject;
 
+public class StringProperty extends CommonProperty {
+	
+	private static final long serialVersionUID = -3200493311633999539L;
+	
 	private Integer maxLength;
-
-    private Integer minLength;
-
-    /**
+	
+	private Integer minLength;
+	
+	/**
 	 * 根据ECMA 262正则表达式方言,该字符串应该是有效的正则表达式。
 	 */
 	private String pattern;
-
-
-    /**
+	
+	/**
 	 * 错误提示信息
 	 */
 	private String errorInfo;
-
+	
 	public Integer getMaxLength() {
 		return maxLength;
 	}
@@ -55,9 +51,8 @@ public class StringProperty extends CommonProperty {
 	public void setPattern(String pattern) {
 		this.pattern = pattern;
 	}
-
-
-    public String getErrorInfo() {
+	
+	public String getErrorInfo() {
 		return errorInfo;
 	}
 
@@ -66,9 +61,10 @@ public class StringProperty extends CommonProperty {
 		this.errorInfo = errorInfo;
 	}
 
-	public StringProperty() {}
 
-    /**
+	public StringProperty() {}
+	
+	/**
 	 *  一般字符串类型走这个构造器
 	 * @param key 字段名
 	 * @param title 字段备注
@@ -82,11 +78,11 @@ public class StringProperty extends CommonProperty {
 		this.title = title;
 		this.type = "string";
 	}
-
-    /**
-     *  列表类型的走这个构造器
+	
+	/**
+         *  列表类型的走这个构造器  
 	 * @param key 字段名
-     * @param title 字段备注
+	 * @param title 字段备注 
 	 * @param view 展示控件 list-checkbox-radio
 	 * @param maxLength 数据库字段最大长度
 	 * @param include 数据字典

+ 46 - 0
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/SwitchProperty.java

@@ -0,0 +1,46 @@
+package org.jeecg.common.util.jsonschema.validate;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.jeecg.common.util.jsonschema.CommonProperty;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 开关 属性
+ */
+public class SwitchProperty extends CommonProperty {
+
+	//扩展参数配置信息
+	private String extendStr;
+
+	public SwitchProperty() {}
+
+	/**
+	 *  构造器
+	 */
+	public SwitchProperty(String key, String title, String extendStr) {
+		this.type = "string";
+		this.view = "switch";
+		this.key = key;
+		this.title = title;
+		this.extendStr = extendStr;
+	}
+	
+	@Override
+	public Map<String, Object> getPropertyJson() {
+		Map<String,Object> map = new HashMap<>();
+		map.put("key",getKey());
+		JSONObject prop = getCommonJson();
+		JSONArray array = new JSONArray();
+		if(extendStr!=null) {
+			array = JSONArray.parseArray(extendStr);
+			prop.put("extendOption",array);
+		}
+		map.put("prop",prop);
+		return map;
+	}
+
+	//TODO 重构问题:数据字典 只是字符串类的还是有存储的数值类型?只有字符串请跳过这个 只改前端
+}

+ 60 - 14
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/jsonschema/validate/TreeSelectProperty.java

@@ -15,19 +15,17 @@ import com.alibaba.fastjson.JSONObject;
 public class TreeSelectProperty extends CommonProperty {
 	
 	private static final long serialVersionUID = 3786503639885610767L;
-    /**
-     * 表名,文本,id
-     */
-    private String dict;
-    /**
-     * 父级字段 默认pid
-     */
-    private String pidField;
-    /**
-     * 父级节点的值 暂时没用到 默认为0
-     */
-    private String pidValue;
+
+	private String dict;//表名,文本,id
+	private String pidField;//父级字段 默认pid
+	private String pidValue;//父级节点的值 暂时没用到 默认为0
 	private String hasChildField;
+	private String textField;//树形下拉保存text值的字段名
+
+	/**
+	 * 是不是pid 组件 1是 0否
+	 */
+	private Integer pidComponent = 0;
 	
 	public String getDict() {
 		return dict;
@@ -62,9 +60,25 @@ public class TreeSelectProperty extends CommonProperty {
 	}
 
 	public TreeSelectProperty() {}
-	
+
+	public String getTextField() {
+		return textField;
+	}
+
+	public void setTextField(String textField) {
+		this.textField = textField;
+	}
+
+	public Integer getPidComponent() {
+		return pidComponent;
+	}
+
+	public void setPidComponent(Integer pidComponent) {
+		this.pidComponent = pidComponent;
+	}
+
 	/**
-	 *  构造器
+	 *  构造器 构造普通树形下拉
 	 */
 	public TreeSelectProperty(String key,String title,String dict,String pidField,String pidValue) {
 		this.type = "string";
@@ -75,6 +89,32 @@ public class TreeSelectProperty extends CommonProperty {
 		this.pidField= pidField;
 		this.pidValue= pidValue;
 	}
+
+	/**
+	 * 分类字典下拉专用
+	 * @param key
+	 * @param title
+	 * @param pidValue
+	 */
+	public TreeSelectProperty(String key,String title,String pidValue) {
+		this.type = "string";
+		this.view = "cat_tree";
+		this.key = key;
+		this.title = title;
+		this.pidValue = pidValue;
+	}
+
+	/**
+	 * 分类字典 支持存储text 下拉专用
+	 * @param key
+	 * @param title
+	 * @param pidValue
+	 * @param textField
+	 */
+	public TreeSelectProperty(String key,String title,String pidValue,String textField) {
+		this(key,title,pidValue);
+		this.textField = textField;
+	}
 	
 	@Override
 	public Map<String, Object> getPropertyJson() {
@@ -90,9 +130,15 @@ public class TreeSelectProperty extends CommonProperty {
 		if(pidValue!=null) {
 			prop.put("pidValue",pidValue);
 		}
+		if(textField!=null) {
+			prop.put("textField",textField);
+		}
 		if(hasChildField!=null) {
 			prop.put("hasChildField",hasChildField);
 		}
+		if(pidComponent!=null) {
+			prop.put("pidComponent",pidComponent);
+		}
 		map.put("prop",prop);
 		return map;
 	}

+ 1 - 1
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java

@@ -71,7 +71,7 @@ public class OssBootUtil {
      * @param fileDir 文件保存目录
      * @return oss 中的相对文件路径
      */
-    public static String upload(MultipartFile file, String fileDir, String customBucket) {
+    public static String upload(MultipartFile file, String fileDir,String customBucket) {
         String FILE_URL = null;
         initOSS(endPoint, accessKeyId, accessKeySecret);
         StringBuilder fileUrl = new StringBuilder();

+ 1 - 3
jeecg-boot-base-common/src/main/java/org/jeecg/common/util/superSearch/QueryRuleEnum.java

@@ -8,9 +8,7 @@ import org.jeecg.common.util.oConvertUtils;
  * @Date 2019年02月14日
  */
 public enum QueryRuleEnum {
-    /**
-     * Query 规则 常量
-     */
+
     GT(">","大于"),
     GE(">=","大于等于"),
     LT("<","小于"),

+ 0 - 78
jeecg-boot-base-common/src/main/java/org/jeecg/modules/system/entity/SysPermissionDataRule.java

@@ -1,78 +0,0 @@
-package org.jeecg.modules.system.entity;
-
-import java.io.Serializable;
-import java.util.Date;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.experimental.Accessors;
-
-/**
- * <p>
- * 菜单权限规则表
- * </p>
- *
- * @Author huangzhilin
- * @since 2019-03-29
- */
-@Data
-@EqualsAndHashCode(callSuper = false)
-@Accessors(chain = true)
-public class SysPermissionDataRule implements Serializable {
-	
-	private static final long serialVersionUID = 1L;
-	
-	/**
-	 * id
-	 */
-	@TableId(type = IdType.UUID)
-	private String id;
-	
-	/**
-	 * 对应的菜单id
-	 */
-	private String permissionId;
-	
-	/**
-	 * 规则名称
-	 */
-	private String ruleName;
-	
-	/**
-	 * 字段
-	 */
-	private String ruleColumn;
-	
-	/**
-	 * 条件
-	 */
-	private String ruleConditions;
-	
-	/**
-	 * 规则值
-	 */
-	private String ruleValue;
-	
-	/**
-	 * 创建时间
-	 */
-	private Date createTime;
-	
-	/**
-	 * 创建人
-	 */
-	private String createBy;
-	
-	/**
-	 * 修改时间
-	 */
-	private Date updateTime;
-	
-	/**
-	 * 修改人
-	 */
-	private String updateBy;
-}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 51 - 0
jeecg-boot-base-common/src/main/resources/static/pca.json


+ 18 - 9
jeecg-boot-module-activiti/pom.xml

@@ -1,15 +1,14 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-<modelVersion>4.0.0</modelVersion>
-<artifactId>jeecg-boot-module-activiti</artifactId>
-<version>2.0.2</version>
-
-<parent>
-    <groupId>org.jeecgframework.boot</groupId>
-    <artifactId>jeecg-boot-parent</artifactId>
-    <version>2.0.2</version>
-</parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>jeecg-boot-module-activiti</artifactId>
+    <version>2.2.0</version>
+    <parent>
+        <groupId>org.jeecgframework.boot</groupId>
+        <artifactId>jeecg-boot-parent</artifactId>
+        <version>2.0.2</version>
+    </parent>
 
 <repositories>
     <repository>
@@ -37,6 +36,16 @@
         <groupId>org.jeecgframework.boot</groupId>
         <artifactId>jeecg-boot-base-common</artifactId>
     </dependency>
+    <dependency>
+        <groupId>cn.com.ctop</groupId>
+        <artifactId>module-common</artifactId>
+        <version>2.0.2</version>
+    </dependency>
+    <dependency>
+        <groupId>org.eclipse.persistence</groupId>
+        <artifactId>org.eclipse.persistence.jpa</artifactId>
+        <version>2.6.0</version>
+    </dependency>
     <!--<dependency>
         <groupId>org.activiti</groupId>
         <artifactId>activiti-spring</artifactId>

+ 1 - 8
jeecg-boot-module-activiti/src/main/java/org/jeecg/modules/activiti/service/Impl/ActZprocessServiceImpl.java

@@ -32,8 +32,6 @@ import org.springframework.mail.SimpleMailMessage;
 import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.stereotype.Service;
 
-import javax.persistence.EntityManager;
-import javax.persistence.PersistenceContext;
 import java.util.Collection;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -63,8 +61,6 @@ public class ActZprocessServiceImpl extends ServiceImpl<ActZprocessMapper, ActZp
     private ActNodeServiceImpl actNodeService;
     @Autowired
     private ActBusinessServiceImpl actBusinessService;
-    @PersistenceContext
-    private EntityManager entityManager;
     @Autowired
     private ISysBaseApi sysBaseAPI;
 
@@ -77,9 +73,7 @@ public class ActZprocessServiceImpl extends ServiceImpl<ActZprocessMapper, ActZp
         if(list==null||list.size()==0){
             return;
         }
-        list.forEach(item -> {
-            item.setLatest(false);
-        });
+        list.forEach(item -> item.setLatest(false));
         this.updateBatchById(list);
     }
 
@@ -273,7 +267,6 @@ public class ActZprocessServiceImpl extends ServiceImpl<ActZprocessMapper, ActZp
         set.addAll(list);
         list.clear();
         list.addAll(set);
-        entityManager.clear();
         list.forEach(u -> {
             u.setPassword(null);
         });

+ 1 - 1
jeecg-boot-module-activiti/src/main/java/org/jeecg/modules/activiti/web/ActProcessInsController.java

@@ -12,7 +12,7 @@ import org.activiti.engine.runtime.ProcessInstance;
 import org.activiti.engine.runtime.ProcessInstanceQuery;
 import org.activiti.engine.task.Task;
 import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.system.api.ISysBaseApi;
+import org.jeecg.common.system.api.ISysBaseApi ;
 import org.jeecg.common.system.vo.ComboModel;
 import org.jeecg.modules.activiti.entity.*;
 import org.jeecg.modules.activiti.service.Impl.ActBusinessServiceImpl;

+ 4 - 0
jeecg-boot-module-system/.gitattributes

@@ -0,0 +1,4 @@
+*.js linguist-language=Java
+*.css linguist-language=Java
+*.html linguist-language=Java
+*.vue linguist-language=Java

+ 81 - 1
jeecg-boot-module-system/pom.xml

@@ -49,7 +49,16 @@
         <dependency>
             <groupId>org.jeecgframework.boot</groupId>
             <artifactId>jeecg-boot-module-activiti</artifactId>
-            <version>2.0.2</version>
+            <version>2.2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>me.zhyd.oauth</groupId>
+            <artifactId>JustAuth</artifactId>
+            <version>1.15.6</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
@@ -88,6 +97,17 @@
             <artifactId>aliyun-sdk-oss</artifactId>
             <version>3.5.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.crazycake</groupId>
+            <artifactId>shiro-redis</artifactId>
+            <version>3.1.0</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.shiro</groupId>
+                    <artifactId>shiro-core</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
         <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-csv -->
         <dependency>
             <groupId>org.apache.commons</groupId>
@@ -156,6 +176,66 @@
             <artifactId>pagehelper</artifactId>
             <version>5.1.11</version>
         </dependency>
+
+        <!--drools规则引擎-->
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-core</artifactId>
+            <version>7.6.0.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-compiler</artifactId>
+            <version>7.6.0.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-templates</artifactId>
+            <version>7.6.0.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.kie</groupId>
+            <artifactId>kie-api</artifactId>
+            <version>7.6.0.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.kie</groupId>
+            <artifactId>kie-spring</artifactId>
+            <version>7.6.0.Final</version>
+        </dependency>
+
+        <!--drools规则引擎-->
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-core</artifactId>
+            <version>7.6.0.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-compiler</artifactId>
+            <version>7.6.0.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-templates</artifactId>
+            <version>7.6.0.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.kie</groupId>
+            <artifactId>kie-api</artifactId>
+            <version>7.6.0.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.kie</groupId>
+            <artifactId>kie-spring</artifactId>
+            <version>7.6.0.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>com.ctop</groupId>
+            <artifactId>module-check</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
     <dependencyManagement>

+ 15 - 12
jeecg-boot-module-system/src/main/java/org/jeecg/JeecgApplication.java

@@ -1,18 +1,19 @@
 package org.jeecg;
 
 import cn.com.ctop.common.module.utils.SpringUtils;
-import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.catalina.Context;
+import org.apache.tomcat.util.scan.StandardJarScanner;
 import org.jeecg.common.constant.AccountReportConstants;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 import org.springframework.core.env.Environment;
-import org.springframework.web.client.RestTemplate;
 import springfox.documentation.swagger2.annotations.EnableSwagger2;
 
 import java.net.InetAddress;
@@ -43,19 +44,21 @@ public class JeecgApplication {
                 "----------------------------------------------------------");
     }
 
-    @Bean
-    public RestTemplate restTemplate() {
-        return new RestTemplate();
-    }
-
-    @Bean
-    public PaginationInterceptor paginationInterceptor() {
-        return new PaginationInterceptor();
-    }
     //加载数据字典
     @Bean
     public void instanceFiledDic(){
         AccountReportConstants.getInstance().init();
     }
-
+    /**
+     * tomcat-embed-jasper引用后提示jar找不到的问题
+     */
+    @Bean
+    public TomcatServletWebServerFactory tomcatFactory() {
+        return new TomcatServletWebServerFactory() {
+            @Override
+            protected void postProcessContext(Context context) {
+                ((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
+            }
+        };
+    }
 }

+ 8 - 8
jeecg-boot-module-system/src/main/java/org/jeecg/JeecgOneGui.java

@@ -3,18 +3,18 @@ package org.jeecg;
 import org.jeecgframework.codegenerate.window.CodeWindow;
 
 /**
- * @title: 单表代码生成器入口
+ * @Title: 单表代码生成器入口
+ * 【 GUI模式已弃用,请转移Online模式进行代码生成 】
  * @Author 张代浩
- * @site www.jeecg.org
+ * @site www.jeecg.com
  * @Version:V1.0.1
  */
 public class JeecgOneGui {
 
-    /**
-     * 详细使用手册: http://jeecg-boot.mydoc.io/?t=338140
-     */
+	/** 详细使用手册: http://doc.jeecg.com/1275846 */
     public static void main(String[] args) {
-        new CodeWindow().pack();
-    }
-
+    	new CodeWindow().pack();
+	}
 }
+
+

+ 30 - 23
jeecg-boot-module-system/src/main/java/org/jeecg/JeecgOneToMainUtil.java

@@ -9,9 +9,10 @@ import org.jeecgframework.codegenerate.generate.pojo.onetomany.SubTableVo;
 
 /**
  * 代码生成器入口【一对多】
+ * 【 GUI模式已弃用,请转移Online模式进行代码生成 】
  * @Author 张代浩
  * @site www.jeecg.org
- * 
+ *
  */
 public class JeecgOneToMainUtil {
 
@@ -22,40 +23,46 @@ public class JeecgOneToMainUtil {
 	public static void main(String[] args) {
 		//第一步:设置主表配置
 		MainTableVo mainTable = new MainTableVo();
-        //表名
-        mainTable.setTableName("ctop_material_info");
-        //实体名
-        mainTable.setEntityName("MaterialInfo");
-        //包名
-        mainTable.setEntityPackage("ctop");
-        //描述
-        mainTable.setFtlDescription("素材库");
-		
+		mainTable.setTableName("jeecg_order_main");//表名
+		mainTable.setEntityName("GuiTestOrderMain");	 //实体名
+		mainTable.setEntityPackage("gui");	 //包名
+		mainTable.setFtlDescription("GUI订单管理");	 //描述
+
 		//第二步:设置子表集合配置
 		List<SubTableVo> subTables = new ArrayList<SubTableVo>();
 		//[1].子表一
 		SubTableVo po = new SubTableVo();
-        //表名
-        po.setTableName("ctop_material_ascription");
-        //实体名
-        po.setEntityName("MaterialAscription");
-        //包名
-        po.setEntityPackage("ctop");
-        //描述
-        po.setFtlDescription("素材归属");
+		po.setTableName("jeecg_order_customer");//表名
+		po.setEntityName("GuiTestOrderCustom");	    //实体名
+		po.setEntityPackage("gui");	        //包名
+		po.setFtlDescription("客户明细");       //描述
 		//子表外键参数配置
-		/*说明: 
+		/*说明:
 		 * a) 子表引用主表主键ID作为外键,外键字段必须以_ID结尾;
 		 * b) 主表和子表的外键字段名字,必须相同(除主键ID外);
 		 * c) 多个外键字段,采用逗号分隔;
-		*/
-        po.setForeignKeys(new String[]{"material_id"});
+		 */
+		po.setForeignKeys(new String[]{"order_id"});
 		subTables.add(po);
+		//[2].子表二
+		SubTableVo po2 = new SubTableVo();
+		po2.setTableName("jeecg_order_ticket");		//表名
+		po2.setEntityName("GuiTestOrderTicket");			//实体名
+		po2.setEntityPackage("gui"); 				//包名
+		po2.setFtlDescription("产品明细");			//描述
+		//子表外键参数配置
+		/*说明:
+		 * a) 子表引用主表主键ID作为外键,外键字段必须以_ID结尾;
+		 * b) 主表和子表的外键字段名字,必须相同(除主键ID外);
+		 * c) 多个外键字段,采用逗号分隔;
+		 */
+		po2.setForeignKeys(new String[]{"order_id"});
+		subTables.add(po2);
 		mainTable.setSubTables(subTables);
-		
+
 		//第三步:一对多(父子表)数据模型,代码生成
 		try {
-			new CodeGenerateOneToMany(mainTable,subTables).generateCodeFile();
+			new CodeGenerateOneToMany(mainTable,subTables).generateCodeFile(null);
 		} catch (Exception e) {
 			e.printStackTrace();
 		}

+ 3 - 2
jeecg-boot-module-system/src/main/java/org/jeecg/config/AutoPoiConfig.java

@@ -9,10 +9,11 @@ import org.springframework.context.annotation.Configuration;
  * @Date: 2018/2/7
  * @description: autopoi 配置类
  */
+
 @Configuration
 public class AutoPoiConfig {
-
-    /**
+	
+	/**
 	 * excel注解字典参数支持(导入导出字典值,自动翻译)
 	 * 举例: @Excel(name = "性别", width = 15, dicCode = "sex")
 	 * 1、导出的时候会根据字典配置,把值1,2翻译成:男、女;

+ 38 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/config/MinioConfig.java

@@ -0,0 +1,38 @@
+package org.jeecg.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.util.MinioUtil;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Minio文件上传配置文件
+ */
+@Slf4j
+@Configuration
+public class MinioConfig {
+    @Value(value = "${jeecg.minio.minio_url}")
+    private String minioUrl;
+    @Value(value = "${jeecg.minio.minio_name}")
+    private String minioName;
+    @Value(value = "${jeecg.minio.minio_pass}")
+    private String minioPass;
+    @Value(value = "${jeecg.minio.bucketName}")
+    private String bucketName;
+
+    @Bean
+    public void initMinio(){
+        if(!minioUrl.startsWith("http")){
+            minioUrl = "http://" + minioUrl;
+        }
+        if(!minioUrl.endsWith("/")){
+            minioUrl = minioUrl.concat("/");
+        }
+        MinioUtil.setMinioUrl(minioUrl);
+        MinioUtil.setMinioName(minioName);
+        MinioUtil.setMinioPass(minioPass);
+        MinioUtil.setBucketName(bucketName);
+    }
+
+}

+ 10 - 9
jeecg-boot-module-system/src/main/java/org/jeecg/config/MybatisPlusConfig.java

@@ -1,10 +1,10 @@
 package org.jeecg.config;
 
-import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
 
 /**
  * 单数据源配置(jeecg.datasource.open = false时生效)
@@ -12,18 +12,18 @@ import org.springframework.context.annotation.Configuration;
  *
  */
 @Configuration
-@MapperScan(value = {"org.jeecg.modules.**.mapper*", "cn.com.ctop.**.mapper*"})
-
+@MapperScan(value={"org.jeecg.modules.**.mapper*","cn.com.ctop.**.mapper*"})
 public class MybatisPlusConfig {
 
     /**
          *  分页插件
      */
-    /*@Bean
+    @Bean
     public PaginationInterceptor paginationInterceptor() {
-        return new PaginationInterceptor();
-    }*/
-
+        // 设置sql的limit为无限制,默认是500
+        return new PaginationInterceptor().setLimit(-1);
+    }
+    
 //    /**
 //     * mybatis-plus SQL执行效率插件【生产环境可以关闭】
 //     */
@@ -31,5 +31,6 @@ public class MybatisPlusConfig {
 //    public PerformanceInterceptor performanceInterceptor() {
 //        return new PerformanceInterceptor();
 //    }
-
+    
+   
 }

+ 0 - 4
jeecg-boot-module-system/src/main/java/org/jeecg/config/RedisConfig.java

@@ -42,7 +42,6 @@ public class RedisConfig extends CachingConfigurerSupport {
 		return new KeyGenerator() {
 			@Override
 			public Object generate(Object target, Method method, Object... params) {
-
 				StringBuilder sb = new StringBuilder();
 				sb.append(target.getClass().getName());
 				sb.append(method.getDeclaringClass().getName());
@@ -97,11 +96,8 @@ public class RedisConfig extends CachingConfigurerSupport {
 		// RedisCacheConfiguration config =
 		// RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
 		// 创建默认缓存配置对象
-
-		// 创建默认缓存配置对象
         //设置缓存默认有效期3小时;
         RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(3));
-
 		RedisCacheManager cacheManager = new RedisCacheManager(writer, config);
 		return cacheManager;
 	}

+ 24 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/config/RestTemplateConfig.java

@@ -0,0 +1,24 @@
+package org.jeecg.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.ClientHttpRequestFactory;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.web.client.RestTemplate;
+
+@Configuration
+public class RestTemplateConfig {
+
+    @Bean
+    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
+        return new RestTemplate(factory);
+    }
+
+    @Bean
+    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
+        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
+        factory.setReadTimeout(5000);//ms
+        factory.setConnectTimeout(15000);//ms
+        return factory;
+    }
+}

+ 60 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/config/RuleEngineConfig.java

@@ -0,0 +1,60 @@
+package org.jeecg.config;
+
+import org.kie.api.KieBase;
+import org.kie.api.KieServices;
+import org.kie.api.builder.KieBuilder;
+import org.kie.api.builder.KieFileSystem;
+import org.kie.api.builder.KieRepository;
+import org.kie.api.runtime.KieContainer;
+import org.kie.api.runtime.KieSession;
+import org.kie.internal.io.ResourceFactory;
+import org.kie.spring.KModuleBeanFactoryPostProcessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+
+import java.io.IOException;
+
+@Configuration
+public class RuleEngineConfig {
+    private static final Logger LOGGER = LoggerFactory.getLogger(RuleEngineConfig.class) ;
+    private static final String RULES_PATH = "drools/";
+    private final KieServices kieServices = KieServices.Factory.get();
+    @Bean
+    public KieFileSystem kieFileSystem() throws IOException {
+        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
+        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
+        Resource[] files = resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*");
+        String path = null;
+        for (Resource file : files) {
+            path = RULES_PATH + file.getFilename();
+            LOGGER.info("path="+path);
+            kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8"));
+        }
+        return kieFileSystem;
+    }
+    @Bean
+    public KieContainer kieContainer() throws IOException {
+        KieRepository kieRepository = kieServices.getRepository();
+        kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
+        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());
+        kieBuilder.buildAll();
+        return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
+    }
+    @Bean
+    public KieBase kieBase() throws IOException {
+        return kieContainer().getKieBase();
+    }
+    @Bean
+    public KieSession kieSession() throws IOException {
+        return kieContainer().newKieSession();
+    }
+    @Bean
+    public KModuleBeanFactoryPostProcessor kiePostProcessor() {
+        return new KModuleBeanFactoryPostProcessor();
+    }
+}

+ 88 - 29
jeecg-boot-module-system/src/main/java/org/jeecg/config/ShiroConfig.java

@@ -7,12 +7,17 @@ import org.apache.shiro.spring.LifecycleBeanPostProcessor;
 import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
 import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.crazycake.shiro.RedisCacheManager;
+import org.crazycake.shiro.RedisManager;
+import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.shiro.authc.ShiroRealm;
 import org.jeecg.modules.shiro.authc.aop.JwtFilter;
 import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.DependsOn;
+import org.springframework.util.StringUtils;
 
 import javax.servlet.Filter;
 import java.util.HashMap;
@@ -27,7 +32,14 @@ import java.util.Map;
 
 @Configuration
 public class ShiroConfig {
+    @Value("${spring.redis.port}")
+    private String port;
 
+    @Value("${spring.redis.host}")
+    private String host;
+
+    @Value("${spring.redis.password}")
+    private String redisPassword;
     /**
      * Filter Chain定义说明
      * <p>
@@ -40,14 +52,14 @@ public class ShiroConfig {
         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
         shiroFilterFactoryBean.setSecurityManager(securityManager);
         // 拦截器
-        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
+        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
         // 配置不会被拦截的链接 顺序判断
         //登录接口排除
+        filterChainDefinitionMap.put("/sys/mLogin", "anon");
         filterChainDefinitionMap.put("/sys/login", "anon");
         filterChainDefinitionMap.put("/sys/wxlogin", "anon");
-        filterChainDefinitionMap.put("/activiti/**", "anon");
-        filterChainDefinitionMap.put("/diagram-viewer/**", "anon");
-        filterChainDefinitionMap.put("/editor-app/**", "anon");
+        //第三方登录
+        filterChainDefinitionMap.put("/thirdLogin/**", "anon");
         //获取加密串
         filterChainDefinitionMap.put("/sys/getEncryptedString", "anon");
         //短信验证码
@@ -75,11 +87,14 @@ public class ShiroConfig {
         filterChainDefinitionMap.put("/ctop/bytedanceAreaInfo/**", "anon");
         filterChainDefinitionMap.put("/ctop/bytedanceInterestCategory/**", "anon");
         filterChainDefinitionMap.put("/template/creative/words/get", "anon");
+        filterChainDefinitionMap.put("template/bytedance/industry/list", "anon");
+
+        filterChainDefinitionMap.put("/bytedance/batch/creative/words/get", "anon");
+        filterChainDefinitionMap.put("/bytedance/batch/action/text", "anon");
+        filterChainDefinitionMap.put("/bytedance/batch/industry/list", "anon");
         filterChainDefinitionMap.put("/appium/crawler/*", "anon");
 
         filterChainDefinitionMap.put("/ctop/kuaishouChannelRegInfo/*", "anon");
-
-
         filterChainDefinitionMap.put("/ctop/byteDance/homePage/report/*", "anon");
         filterChainDefinitionMap.put("/ctop/material/top/cost", "anon");
 
@@ -104,6 +119,12 @@ public class ShiroConfig {
         filterChainDefinitionMap.put("/kuaishou/report", "anon");
         filterChainDefinitionMap.put("/ctop/bindAccount/**", "anon");
         filterChainDefinitionMap.put("/**/*.mp4", "anon");
+        //activiti
+        filterChainDefinitionMap.put("/activiti/**", "anon");
+        filterChainDefinitionMap.put("/diagram-viewer/**", "anon");
+        filterChainDefinitionMap.put("/editor-app/**", "anon");
+        //大屏设计器排除
+        filterChainDefinitionMap.put("/big/screen/**", "anon");
 
         //性能监控
         filterChainDefinitionMap.put("/actuator/metrics/**", "anon");
@@ -116,18 +137,14 @@ public class ShiroConfig {
         //oauth接口
         filterChainDefinitionMap.put("/auth/**", "anon");
         filterChainDefinitionMap.put("/ctop/syncdata/**", "anon");
+        filterChainDefinitionMap.put("/sys/dictItem/list", "anon");
         //头条接口
         filterChainDefinitionMap.put("/bytedance", "anon");
-        filterChainDefinitionMap.put("/toutiao/dictitem/list", "anon");
         filterChainDefinitionMap.put("/toutiao/loadAllData", "anon");
         filterChainDefinitionMap.put("/toutiao/loadSingleData", "anon");
         filterChainDefinitionMap.put("/kuaishou/getReport/historyData", "anon");
         filterChainDefinitionMap.put("/toutiao/advertiser/**", "anon");
-        filterChainDefinitionMap.put("/toutiao/industry/list", "anon");
-        filterChainDefinitionMap.put("/template/bytedance/industry/list", "anon");
-        filterChainDefinitionMap.put("/template/convert/list", "anon");
-        filterChainDefinitionMap.put("/template/convert/list/url", "anon");
-        //文件上传接口
+        filterChainDefinitionMap.put("/template/convert/**", "anon");//文件上传接口
         filterChainDefinitionMap.put("/upload/**", "anon");
         filterChainDefinitionMap.put("/appium/appiumTask/run", "anon");
 
@@ -142,12 +159,15 @@ public class ShiroConfig {
 
         filterChainDefinitionMap.put("/appium/appiumTask/run/login", "anon");
         filterChainDefinitionMap.put("/zip/download", "anon");
+        //WebSocket
+        filterChainDefinitionMap.put("/websocket/*", "anon");
         //爬虫接口
         filterChainDefinitionMap.put("/graphql/video", "anon");
         filterChainDefinitionMap.put("/ks/web/test", "anon");
         filterChainDefinitionMap.put("/ureport/**", "anon");
-        //filterChainDefinitionMap.put("/ctop/performance/show/**", "anon");
         filterChainDefinitionMap.put("/job/test/*", "anon");
+        filterChainDefinitionMap.put("/rest/script/*", "anon");
+        filterChainDefinitionMap.put("/ctop/checkTaskList/*", "anon");
 
         // 添加自己的过滤器并且取名为jwt
         Map<String, Filter> filterMap = new HashMap<>(1);
@@ -182,29 +202,68 @@ public class ShiroConfig {
         return securityManager;
     }
 
+	/**
+	 * 下面的代码是添加注解支持
+	 * @return
+	 */
+	@Bean
+	@DependsOn("lifecycleBeanPostProcessor")
+	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
+		DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
+		defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
+		/**
+		* 解决重复代理问题 github#994
+		* 添加前缀判断 不匹配 任何Advisor
+		*/
+		defaultAdvisorAutoProxyCreator.setUsePrefix(true);
+		defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor");
+		return defaultAdvisorAutoProxyCreator;
+	}
+
+	@Bean
+	public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
+		return new LifecycleBeanPostProcessor();
+	}
+
+	@Bean
+	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
+		AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
+		advisor.setSecurityManager(securityManager);
+		return advisor;
+	}
+
     /**
-     * 下面的代码是添加注解支持
+     * cacheManager 缓存 redis实现
+     * 使用的是shiro-redis开源插件
      *
      * @return
      */
-    @Bean
-    @DependsOn("lifecycleBeanPostProcessor")
-    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
-        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
-        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
-        return defaultAdvisorAutoProxyCreator;
-    }
-
-    @Bean
-    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
-        return new LifecycleBeanPostProcessor();
+    public RedisCacheManager redisCacheManager() {
+        RedisCacheManager redisCacheManager = new RedisCacheManager();
+        redisCacheManager.setRedisManager(redisManager());
+        //redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识)
+        redisCacheManager.setPrincipalIdFieldName("id");
+        //用户权限信息缓存时间
+        redisCacheManager.setExpire(200000);
+        return redisCacheManager;
     }
 
+    /**
+     * 配置shiro redisManager
+     * 使用的是shiro-redis开源插件
+     *
+     * @return
+     */
     @Bean
-    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
-        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
-        advisor.setSecurityManager(securityManager);
-        return advisor;
+    public RedisManager redisManager() {
+        RedisManager redisManager = new RedisManager();
+		redisManager.setHost(host);
+		redisManager.setPort(oConvertUtils.getInt(port));
+		redisManager.setTimeout(0);
+        if (!StringUtils.isEmpty(redisPassword)) {
+            redisManager.setPassword(redisPassword);
+        }
+        return redisManager;
     }
 
 }

+ 31 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/config/StaticConfig.java

@@ -0,0 +1,31 @@
+package org.jeecg.config;
+
+import org.jeecg.common.util.DySmsHelper;
+import org.jeecg.modules.message.handle.impl.EmailSendMsgHandle;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 设置静态参数初始化
+ */
+@Configuration
+public class StaticConfig {
+
+    @Value("${jeecg.sms.accessKeyId}")
+    private String accessKeyId;
+
+    @Value("${jeecg.sms.accessKeySecret}")
+    private String accessKeySecret;
+
+    @Value(value = "${spring.mail.username}")
+    private String emailFrom;
+
+
+    @Bean
+    public void initStatic() {
+        DySmsHelper.setAccessKeyId(accessKeyId);
+        DySmsHelper.setAccessKeySecret(accessKeySecret);
+        EmailSendMsgHandle.setEmailFrom(emailFrom);
+    }
+}

+ 24 - 8
jeecg-boot-module-system/src/main/java/org/jeecg/config/Swagger2Config.java

@@ -4,6 +4,7 @@ import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrap
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.modules.shiro.vo.DefContants;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
@@ -14,12 +15,15 @@ import springfox.documentation.builders.PathSelectors;
 import springfox.documentation.builders.RequestHandlerSelectors;
 import springfox.documentation.schema.ModelRef;
 import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.ApiKey;
 import springfox.documentation.service.Parameter;
+import springfox.documentation.service.SecurityScheme;
 import springfox.documentation.spi.DocumentationType;
 import springfox.documentation.spring.web.plugins.Docket;
 import springfox.documentation.swagger2.annotations.EnableSwagger2;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -29,12 +33,13 @@ import java.util.List;
 @Configuration
 @EnableSwagger2
 @EnableSwaggerBootstrapUI
+@ConditionalOnProperty(name = "swagger.enable", havingValue = "true")
 public class Swagger2Config implements WebMvcConfigurer {
 
 	/**
 	 *
 	 * 显示swagger-ui.html文档展示页,还必须注入swagger资源:
-	 *
+	 * 
 	 * @param registry
 	 */
 	@Override
@@ -60,9 +65,20 @@ public class Swagger2Config implements WebMvcConfigurer {
 	            .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
 				.paths(PathSelectors.any())
 				.build()
-				.globalOperationParameters(setHeaderToken());
+				.securitySchemes(Collections.singletonList(securityScheme()));
+				//.globalOperationParameters(setHeaderToken());
 	}
 
+	/***
+	 * oauth2配置
+	 * 需要增加swagger授权回调地址
+	 * http://localhost:8888/webjars/springfox-swagger-ui/o2c.html
+	 * @return
+	 */
+	@Bean
+	SecurityScheme securityScheme() {
+		return new ApiKey(DefContants.X_ACCESS_TOKEN, DefContants.X_ACCESS_TOKEN, "header");
+	}
 	/**
 	 * JWT token
 	 * @return
@@ -83,16 +99,16 @@ public class Swagger2Config implements WebMvcConfigurer {
 	private ApiInfo apiInfo() {
 		return new ApiInfoBuilder()
 				// //大标题
-				.title("汇创助手后台服务API接口文档")
+				.title("Jeecg-Boot 后台服务API接口文档")
 				// 版本号
-				.version("2.0.2")
+				.version("1.0")
 //				.termsOfServiceUrl("NO terms of service")
 				// 描述
-				.description("restful 风格接口")
+				.description("后台API接口")
 				// 作者
-//				.contact(new Contact("scott", "http://jeecg.org", "jeecgos@163.com"))
-//                .license("The Apache License, Version 2.0")
-//                .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
+				.contact("JEECG团队")
+                .license("The Apache License, Version 2.0")
+                .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
 				.build();
 	}
 

+ 16 - 8
jeecg-boot-module-system/src/main/java/org/jeecg/config/WebMvcConfiguration.java

@@ -1,7 +1,7 @@
 package org.jeecg.config;
 
-import cn.com.ctop.common.module.utils.StringUtils;
 import org.jeecg.config.interceptors.BrowseLogHandelInterceptor;
+import org.jeecg.modules.shiro.authc.interceptor.OnlineInterceptor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
@@ -33,10 +33,11 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
 	@Value("${spring.resource.static-locations}")
 	private String staticLocations;
 
-//	@Override
-//	public void addInterceptors(InterceptorRegistry registry) {
-//		registry.addInterceptor(browseLogHandelInterceptor);
-//	}
+	@Bean
+	public OnlineInterceptor onlineInterceptor(){
+		return new OnlineInterceptor();
+	}
+
 
 	@Bean
 	public CorsFilter corsFilter() {
@@ -61,14 +62,21 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
 	public void addResourceHandlers(ResourceHandlerRegistry registry) {
 		registry.addResourceHandler("/**")
 		.addResourceLocations("file:" + upLoadPath + "//", "file:" + webAppPath + "//")
-				.addResourceLocations(staticLocations.split(StringUtils.COMMA));
+		.addResourceLocations(staticLocations.split(","));
 	}
 
 	/**
-	 * 访问根路径默认跳转 index.html页面 (简化部署方案: 可以把前端打包直接放到项目的 webapp,上面的配置)
+	 * 方案一: 默认访问根路径跳转 doc.html页面 (swagger文档页面)
+	 * 方案二: 访问根路径改成跳转 index.html页面 (简化部署方案: 可以把前端打包直接放到项目的 webapp,上面的配置)
 	 */
 	@Override
 	public void addViewControllers(ViewControllerRegistry registry) {
-		registry.addViewController("/").setViewName("index.html");
+		registry.addViewController("/").setViewName("doc.html");
+	}
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		String [] exculudes = new String[]{"/*.html","/html/**","/js/**","/css/**","/images/**"};
+		registry.addInterceptor(onlineInterceptor()).excludePathPatterns(exculudes).addPathPatterns("/online/cgform/api/**");
 	}
 }

+ 18 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/config/WebSocketConfig.java

@@ -0,0 +1,18 @@
+package org.jeecg.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+@Configuration
+public class WebSocketConfig {
+    /**
+     * 	注入ServerEndpointExporter,
+     * 	这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
+     */
+    @Bean
+    public ServerEndpointExporter serverEndpointExporter() {
+        return new ServerEndpointExporter();
+    }
+    
+}

+ 56 - 53
jeecg-boot-module-system/src/main/java/org/jeecg/config/mybatis/MybatisInterceptor.java

@@ -1,19 +1,24 @@
 package org.jeecg.config.mybatis;
 
-import lombok.extern.slf4j.Slf4j;
+import java.lang.reflect.Field;
+import java.util.Date;
+import java.util.Properties;
+
 import org.apache.ibatis.binding.MapperMethod.ParamMap;
 import org.apache.ibatis.executor.Executor;
 import org.apache.ibatis.mapping.MappedStatement;
 import org.apache.ibatis.mapping.SqlCommandType;
-import org.apache.ibatis.plugin.*;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Plugin;
+import org.apache.ibatis.plugin.Signature;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.oConvertUtils;
 import org.springframework.stereotype.Component;
 
-import java.lang.reflect.Field;
-import java.util.Date;
-import java.util.Properties;
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * mybatis拦截器,自动注入创建人、创建时间、修改人、修改时间
@@ -29,35 +34,25 @@ public class MybatisInterceptor implements Interceptor {
 	@Override
 	public Object intercept(Invocation invocation) throws Throwable {
 		MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
-		String sqlId = mappedStatement.getId();
-		log.debug("------sqlId------" + sqlId);
 		SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
 		Object parameter = invocation.getArgs()[1];
-		log.debug("------sqlCommandType------" + sqlCommandType);
-
 		if (parameter == null) {
 			return invocation.proceed();
 		}
 		if (SqlCommandType.INSERT == sqlCommandType) {
+			LoginUser sysUser = this.getLoginUser();
 			Field[] fields = oConvertUtils.getAllFields(parameter);
 			for (Field field : fields) {
-				log.debug("------field.name------" + field.getName());
 				try {
-					// 获取登录用户信息
-					LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
 					if ("createBy".equals(field.getName())) {
 						field.setAccessible(true);
-                        Object localCreateBy = field.get(parameter);
+						Object local_createBy = field.get(parameter);
 						field.setAccessible(false);
-                        if (localCreateBy == null || "".equals(localCreateBy)) {
-							String createBy = "jeecg";
+						if (local_createBy == null || local_createBy.equals("")) {
 							if (sysUser != null) {
-								// 登录账号
-								createBy = sysUser.getUsername();
-							}
-							if (oConvertUtils.isNotEmpty(createBy)) {
+								// 登录人账号
 								field.setAccessible(true);
-								field.set(parameter, createBy);
+								field.set(parameter, sysUser.getUsername());
 								field.setAccessible(false);
 							}
 						}
@@ -65,9 +60,9 @@ public class MybatisInterceptor implements Interceptor {
 					// 注入创建时间
 					if ("createTime".equals(field.getName())) {
 						field.setAccessible(true);
-                        Object localCreateDate = field.get(parameter);
+						Object local_createDate = field.get(parameter);
 						field.setAccessible(false);
-                        if (localCreateDate == null || "".equals(localCreateDate)) {
+						if (local_createDate == null || local_createDate.equals("")) {
 							field.setAccessible(true);
 							field.set(parameter, new Date());
 							field.setAccessible(false);
@@ -76,18 +71,13 @@ public class MybatisInterceptor implements Interceptor {
 					//注入部门编码
 					if ("sysOrgCode".equals(field.getName())) {
 						field.setAccessible(true);
-                        Object localSysOrgCode = field.get(parameter);
+						Object local_sysOrgCode = field.get(parameter);
 						field.setAccessible(false);
-                        if (localSysOrgCode == null || "".equals(localSysOrgCode)) {
-							String sysOrgCode = "";
+						if (local_sysOrgCode == null || local_sysOrgCode.equals("")) {
 							// 获取登录用户信息
 							if (sysUser != null) {
-								// 登录账号
-								sysOrgCode = sysUser.getOrgCode();
-							}
-							if (oConvertUtils.isNotEmpty(sysOrgCode)) {
 								field.setAccessible(true);
-								field.set(parameter, sysOrgCode);
+								field.set(parameter, sysUser.getOrgCode());
 								field.setAccessible(false);
 							}
 						}
@@ -97,10 +87,24 @@ public class MybatisInterceptor implements Interceptor {
 			}
 		}
 		if (SqlCommandType.UPDATE == sqlCommandType) {
+			LoginUser sysUser = this.getLoginUser();
 			Field[] fields = null;
 			if (parameter instanceof ParamMap) {
 				ParamMap<?> p = (ParamMap<?>) parameter;
-				parameter = p.get("param1");
+				//update-begin-author:scott date:20190729 for:批量更新报错issues/IZA3Q--
+				if (p.containsKey("et")) {
+					parameter = p.get("et");
+				} else {
+					parameter = p.get("param1");
+				}
+				//update-end-author:scott date:20190729 for:批量更新报错issues/IZA3Q-
+
+				//update-begin-author:scott date:20190729 for:更新指定字段时报错 issues/#516-
+				if (parameter == null) {
+					return invocation.proceed();
+				}
+				//update-end-author:scott date:20190729 for:更新指定字段时报错 issues/#516-
+
 				fields = oConvertUtils.getAllFields(parameter);
 			} else {
 				fields = oConvertUtils.getAllFields(parameter);
@@ -110,35 +114,21 @@ public class MybatisInterceptor implements Interceptor {
 				log.debug("------field.name------" + field.getName());
 				try {
 					if ("updateBy".equals(field.getName())) {
-						field.setAccessible(true);
-                        Object localUpdateBy = field.get(parameter);
-						field.setAccessible(false);
-                        if (localUpdateBy == null || "".equals(localUpdateBy)) {
-							String updateBy = "jeecg";
-							// 获取登录用户信息
-							LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-							if (sysUser != null) {
-								// 登录账号
-								updateBy = sysUser.getUsername();
-							}
-							if (oConvertUtils.isNotEmpty(updateBy)) {
-								field.setAccessible(true);
-								field.set(parameter, updateBy);
-								field.setAccessible(false);
-							}
+						//获取登录用户信息
+						if (sysUser != null) {
+							// 登录账号
+							field.setAccessible(true);
+							field.set(parameter, sysUser.getUsername());
+							field.setAccessible(false);
 						}
 					}
 					if ("updateTime".equals(field.getName())) {
 						field.setAccessible(true);
-                        Object localUpdateDate = field.get(parameter);
+						field.set(parameter, new Date());
 						field.setAccessible(false);
-                        if (localUpdateDate == null || "".equals(localUpdateDate)) {
-							field.setAccessible(true);
-							field.set(parameter, new Date());
-							field.setAccessible(false);
-						}
 					}
 				} catch (Exception e) {
+					e.printStackTrace();
 				}
 			}
 		}
@@ -155,4 +145,17 @@ public class MybatisInterceptor implements Interceptor {
 		// TODO Auto-generated method stub
 	}
 
+	//update-begin--Author:scott  Date:20191213 for:关于使用Quzrtz 开启线程任务, #465
+	private LoginUser getLoginUser() {
+		LoginUser sysUser = null;
+		try {
+			sysUser = SecurityUtils.getSubject().getPrincipal() != null ? (LoginUser) SecurityUtils.getSubject().getPrincipal() : null;
+		} catch (Exception e) {
+			//e.printStackTrace();
+			sysUser = null;
+		}
+		return sysUser;
+	}
+	//update-end--Author:scott  Date:20191213 for:关于使用Quzrtz 开启线程任务, #465
+
 }

+ 31 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/config/oss/OssBootConfiguration.java

@@ -0,0 +1,31 @@
+package org.jeecg.config.oss;
+
+import org.jeecg.common.util.oss.OssBootUtil;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class OssBootConfiguration {
+
+    @Value("${jeecg.oss.endpoint}")
+    private String endpoint;
+    @Value("${jeecg.oss.accessKey}")
+    private String accessKeyId;
+    @Value("${jeecg.oss.secretKey}")
+    private String accessKeySecret;
+    @Value("${jeecg.oss.bucketName}")
+    private String bucketName;
+    @Value("${jeecg.oss.staticDomain}")
+    private String staticDomain;
+
+
+    @Bean
+    public void initOssBootConfiguration() {
+        OssBootUtil.setEndPoint(endpoint);
+        OssBootUtil.setAccessKeyId(accessKeyId);
+        OssBootUtil.setAccessKeySecret(accessKeySecret);
+        OssBootUtil.setBucketName(bucketName);
+        OssBootUtil.setStaticDomain(staticDomain);
+    }
+}

+ 168 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/append/xd_schedule/controller/XdScheduleController.java

@@ -0,0 +1,168 @@
+package org.jeecg.modules.append.xd_schedule.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.append.xd_schedule.entity.XdSchedule;
+import org.jeecg.modules.append.xd_schedule.service.IXdScheduleService;
+import org.jeecg.modules.append.xd_schedule.service.impl.XdScheduleServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+
+ /**
+ * @Description: 时间表
+ * @Author: jeecg-boot
+ * @Date:   2019-10-29
+ * @Version: V1.0
+ */
+@Slf4j
+@Api(tags="时间表")
+@RestController
+@RequestMapping("/xd_schedule/xdSchedule")
+public class XdScheduleController extends JeecgController<XdSchedule, IXdScheduleService> {
+	@Autowired
+	private XdScheduleServiceImpl xdScheduleService;
+
+	/**
+	 * 分页列表查询
+	 *
+	 * @param xdSchedule
+	 * @param pageNo
+	 * @param pageSize
+	 * @param req
+	 * @return
+	 */
+	@ApiOperation(value="时间表-分页列表查询", notes="时间表-分页列表查询")
+	@GetMapping(value = "/list")
+	public Result<?> queryPageList(XdSchedule xdSchedule,
+								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+								   HttpServletRequest req) {
+		QueryWrapper<XdSchedule> queryWrapper = QueryGenerator.initQueryWrapper(xdSchedule, req.getParameterMap());
+		Page<XdSchedule> page = new Page<XdSchedule>(pageNo, pageSize);
+		queryWrapper.orderByAsc("DAY");
+		IPage<XdSchedule> pageList = xdScheduleService.page(page, queryWrapper);
+		return Result.ok(pageList);
+	}
+
+	/**
+	 * 添加
+	 *
+	 * @param xdSchedule
+	 * @return
+	 */
+	@ApiOperation(value="时间表-添加", notes="时间表-添加")
+	@PostMapping(value = "/add")
+	public Result<?> add(@RequestBody XdSchedule xdSchedule) {
+		xdScheduleService.save(xdSchedule);
+		return Result.ok("添加成功!");
+	}
+
+	/**
+	 * 编辑
+	 *
+	 * @param xdSchedule
+	 * @return
+	 */
+	@ApiOperation(value="时间表-编辑", notes="时间表-编辑")
+	@PutMapping(value = "/edit")
+	public Result<?> edit(@RequestBody XdSchedule xdSchedule) {
+		xdScheduleService.updateById(xdSchedule);
+		return Result.ok("编辑成功!");
+	}
+
+	/**
+	 * 通过id删除
+	 *
+	 * @param id
+	 * @return
+	 */
+	@ApiOperation(value="时间表-通过id删除", notes="时间表-通过id删除")
+	@DeleteMapping(value = "/delete")
+	public Result<?> delete(@RequestParam(name="id",required=true) String id) {
+		xdScheduleService.removeById(id);
+		return Result.ok("删除成功!");
+	}
+
+	/**
+	 * 批量删除
+	 *
+	 * @param ids
+	 * @return
+	 */
+	@ApiOperation(value="时间表-批量删除", notes="时间表-批量删除")
+	@DeleteMapping(value = "/deleteBatch")
+	public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+		this.xdScheduleService.removeByIds(Arrays.asList(ids.split(",")));
+		return Result.ok("批量删除成功!");
+	}
+
+	/**
+	 * 通过id查询
+	 *
+	 * @param id
+	 * @return
+	 */
+	@ApiOperation(value="时间表-通过id查询", notes="时间表-通过id查询")
+	@GetMapping(value = "/queryById")
+	public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
+		XdSchedule xdSchedule = xdScheduleService.getById(id);
+		return Result.ok(xdSchedule);
+	}
+
+  /**
+   * 导出excel
+   *
+   * @param request
+   * @param xdSchedule
+   */
+  @RequestMapping(value = "/exportXls")
+  public ModelAndView exportXls(HttpServletRequest request, XdSchedule xdSchedule) {
+      return super.exportXls(request, xdSchedule, XdSchedule.class, "时间表");
+  }
+
+  /**
+   * 通过excel导入数据
+   *
+   * @param request
+   * @param response
+   * @return
+   */
+  @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+  public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
+      return super.importExcel(request, response, XdSchedule.class);
+  }
+  /**
+   * 获取时间范围
+   *
+   * @param request
+   * @param response
+   * @return
+   */
+  @RequestMapping(value = "/getDateRange")
+  public Result<?> getDateRange(HttpServletRequest request, HttpServletResponse response) {
+	  String weeknum = request.getParameter("weeknum");
+	  String dateRange = xdScheduleService.getDateRange(weeknum, "yyyy/MM/dd", "--");
+	  return Result.ok(dateRange);
+  }
+  /**通过api同步国家法定节假日*/
+  @RequestMapping(value = "/aotuData")
+  public Result<?> aotuData(HttpServletRequest request, HttpServletResponse response) {
+	  String yyyy = request.getParameter("yyyy");
+	  String body = request.getParameter("body");
+	  xdScheduleService.aotuData(yyyy,body);
+	  return Result.ok();
+  }
+
+}

+ 100 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/append/xd_schedule/entity/XdSchedule.java

@@ -0,0 +1,100 @@
+package org.jeecg.modules.append.xd_schedule.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.apache.shiro.SecurityUtils;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * @Description: 时间表
+ * @Author: jeecg-boot
+ * @Date:   2019-10-29
+ * @Version: V1.0
+ */
+@Data
+@TableName("xd_schedule")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="xd_schedule对象", description="时间表")
+public class XdSchedule {
+	/**id*/
+	@TableId(type = IdType.ID_WORKER_STR)
+	@ApiModelProperty(value = "id")
+	private String id;
+	/**day*/
+	@Excel(name = "day", width = 15, format = "yyyy-MM-dd")
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @ApiModelProperty(value = "day")
+	private Date day;
+	/**week*/
+	@Excel(name = "week", width = 15)
+    @ApiModelProperty(value = "week")
+	private String week;
+	/**是否工作日*/
+	@Excel(name = "是否工作日", width = 15)
+    @ApiModelProperty(value = "是否工作日")
+	private String isworking;
+	/**周序号*/
+	@Excel(name = "周序号", width = 15)
+    @ApiModelProperty(value = "周序号")
+	private Integer weeknum;
+	/**年份*/
+	@Excel(name = "年份", width = 15)
+    @ApiModelProperty(value = "年份")
+	private Integer year;
+	/**周序号*/
+	@Excel(name = "月份", width = 15)
+    @ApiModelProperty(value = "月份")
+	private Integer month;
+	/**周序号*/
+	@Excel(name = "星期几", width = 15)
+    @ApiModelProperty(value = "星期几")
+	private Integer dayofweek;
+	/**范围 自设字段不一定有值*/
+	@TableField(exist = false)
+	private String weekround;
+
+	/**创建人*/
+	@Excel(name = "创建人", width = 15)
+	@ApiModelProperty(value = "创建人")
+	private String createBy;
+	/**创建时间*/
+	@Excel(name = "创建时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+	@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+	@ApiModelProperty(value = "创建时间")
+	private Date createTime;
+	/**修改人*/
+	@Excel(name = "修改人", width = 15)
+	@ApiModelProperty(value = "修改人")
+	private String updateBy;
+	/**修改时间*/
+	@Excel(name = "修改时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+	@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+	@ApiModelProperty(value = "修改时间")
+	private Date updateTime;
+	/**删除标识0-正常,1-已删除*/
+	@Excel(name = "删除标识0-正常,1-已删除", width = 15)
+	@ApiModelProperty(value = "删除标识0-正常,1-已删除")
+	private Integer delFlag;
+
+    public void init() {
+		LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+		this.createBy = user.getUsername();
+		this.delFlag = 0;
+    }
+}

+ 14 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/append/xd_schedule/mapper/XdScheduleMapper.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.append.xd_schedule.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.append.xd_schedule.entity.XdSchedule;
+
+/**
+ * @Description: 时间表
+ * @Author: jeecg-boot
+ * @Date:   2019-10-29
+ * @Version: V1.0
+ */
+public interface XdScheduleMapper extends BaseMapper<XdSchedule> {
+
+}

+ 2 - 2
module-common/src/main/java/cn/com/ctop/common/module/mapper/xml/VideoWatermarkTemplateMapper.xml

@@ -1,5 +1,5 @@
 <?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="cn.com.ctop.common.module.mapper.VideoWatermarkTemplateMapper">
+<mapper namespace="org.jeecg.modules.append.xd_schedule.mapper.XdScheduleMapper">
 
-</mapper>
+</mapper>

+ 14 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/append/xd_schedule/service/IXdScheduleService.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.append.xd_schedule.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.append.xd_schedule.entity.XdSchedule;
+
+/**
+ * @Description: 时间表
+ * @Author: jeecg-boot
+ * @Date:   2019-10-29
+ * @Version: V1.0
+ */
+public interface IXdScheduleService extends IService<XdSchedule> {
+
+}

+ 187 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/append/xd_schedule/service/impl/XdScheduleServiceImpl.java

@@ -0,0 +1,187 @@
+package org.jeecg.modules.append.xd_schedule.service.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.util.DateUtils;
+import org.jeecg.common.util.RedisUtil;
+import org.jeecg.modules.append.xd_schedule.entity.XdSchedule;
+import org.jeecg.modules.append.xd_schedule.mapper.XdScheduleMapper;
+import org.jeecg.modules.append.xd_schedule.service.IXdScheduleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 时间表
+ * @Author: jeecg-boot
+ * @Date:   2019-10-29
+ * @Version: V1.0
+ */
+@Service
+@Slf4j
+public class XdScheduleServiceImpl extends ServiceImpl<XdScheduleMapper, XdSchedule> implements IXdScheduleService {
+    @Autowired
+    RedisUtil redisUtil;
+    /**单例 缓存,避免多次重复查*/
+    private List<XdSchedule> ScheduleList;
+    /**有效期*/
+    private Date ScheduleListDate = new Date();
+
+    public List<XdSchedule> getDays() {
+        if (CollectionUtil.isEmpty(ScheduleList)||ScheduleListDate.getTime()<new Date().getTime()){
+            ScheduleList = this.list(new QueryWrapper<XdSchedule>().orderByAsc("day"));
+            ScheduleListDate = DateUtils.getDate(new Date().getTime()+60*1000);//缓存一分
+        }
+        return this.ScheduleList;
+    }
+
+    /**
+     * 获取weeknum 的日期
+     * @param weeknum
+     * @return
+     */
+    public List<XdSchedule> getDays(String weeknum) {
+        getDays();
+        List<XdSchedule> weekFilter = ScheduleList.stream().filter(o -> StrUtil.equals(o.getWeeknum().intValue() + "", weeknum)).collect(Collectors.toList());
+        return weekFilter;
+    }
+    /**
+     * 获取 yyyyMM 月的时间
+     */
+    public List<XdSchedule> getDays(Integer yyyyMM) {
+        getDays();
+        if (yyyyMM==null){
+            return ScheduleList;
+        }
+       return ScheduleList.stream().filter(d->{
+            String formatDate = DateUtils.formatDate(d.getDay(),"yyyyMM");
+            return formatDate.equals(yyyyMM+"");
+        }).collect(Collectors.toList());
+    }
+    /**
+     * 获取 weeknum 周的时间范围
+     * @param weeknum 周序号
+     * @param pattern 时间格式
+     * @param span 间隔字符
+     */
+    public String getDateRange(String weeknum, String pattern, String span) {
+        try {
+            List<XdSchedule> weekFilter = getDays(weeknum);
+            Date start = weekFilter.get(0).getDay();
+            Date end = weekFilter.get(weekFilter.size()-1).getDay();
+            return String.format("%s %s %s",DateUtils.formatDate(start,pattern),span,DateUtils.formatDate(end,pattern));
+        } catch (Exception e) {
+            log.warn("获取周时间范围 : "+e.getMessage());
+            return String.format("请检查时间表预设数据是否正确:%s 周",weeknum);
+        }
+
+
+    }
+/**
+ * 生成国家法定节假日
+ * */
+    public void aotuData(String yyyy,String body) {
+        if (StrUtil.isBlank(yyyy)){
+            throw new RuntimeException("年份不能为空");
+        }
+        /*包含所有节假日、休息日*/
+        log.info("请求获取到的body数据 : "+body);
+        JSONObject apiData = null;
+        if (StrUtil.isNotBlank(body)) {
+            try {
+                apiData = JSON.parseObject(body);
+            } catch (Exception e) {
+                throw new RuntimeException("节假日的数据有误!");
+            }
+        }
+
+
+        //生成该年的数据信息
+        int year = Convert.toInt(yyyy);//定义一个字段,接收输入的年份
+        Calendar calendar = new GregorianCalendar();//定义一个日历,变量作为年初
+        Calendar calendarEnd = new GregorianCalendar();//定义一个日历,变量作为年末
+        calendar.set(Calendar.YEAR, year);
+        calendar.set(Calendar.MONTH, 0);
+        calendar.set(Calendar.DAY_OF_MONTH, 1);//设置年初的日期为1月1日
+        calendarEnd.set(Calendar.YEAR, year);
+        calendarEnd.set(Calendar.MONTH, 11);
+        calendarEnd.set(Calendar.DAY_OF_MONTH, 31);//设置年末的日期为12月31日
+
+        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
+        ArrayList<XdSchedule> addDays = Lists.newArrayList();
+        while(calendar.getTime().getTime()<=calendarEnd.getTime().getTime()){//用一整年的日期循环
+            Date date = calendar.getTime();
+            String format = sf.format(date);
+
+            int weekOfYear = calendar.get(Calendar.WEEK_OF_YEAR);//第几周
+            int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);//第几天
+            int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);//一周中第几周
+            int month = calendar.get(Calendar.MONTH)+1;//月份
+            //是否工作日
+            boolean isworking = dayOfWeek!=1&&dayOfWeek!=7;//周末休息
+            if (StrUtil.isNotBlank(body)){
+                Integer dayType = apiData.getInteger(format);
+                if (dayType!=null){ //1法定调休,2法定放假
+                    if (dayType==1) isworking = true;
+                    if (dayType==2) isworking = false;
+                }
+            }
+            String weekNum;
+            String week;
+            if (dayOfWeek==1){
+                //星期天 按国内习惯,计入上一周
+                weekOfYear -= 1;
+            }
+            yyyy = year+"";//还原
+            //若选择的日期是月份12但是返回的周为1   计入下一年的第一周  yyyy+1
+            if (month==12&&weekOfYear==1){
+                yyyy = (year+1)+"";
+            }
+            //若选择的日期是月份1但是返回的周很大,一年有50多个周    计入上一年的最后一周 yyyy-1
+            if (month==1&&weekOfYear>50){
+                yyyy= (year-1)+"";
+            }
+            if (weekOfYear<10){
+                week = String.format("%s年0%s周",yyyy,weekOfYear);
+                weekNum = String.format("%s0%s",yyyy,weekOfYear);
+            }else {
+                week = String.format("%s年%s周",yyyy,weekOfYear);
+                weekNum = String.format("%s%s",yyyy,weekOfYear);
+            }
+            XdSchedule xdSchedule = new XdSchedule();
+            xdSchedule.init();
+            xdSchedule.setWeek(week);
+            xdSchedule.setWeeknum(Convert.toInt(weekNum));
+            xdSchedule.setYear(Convert.toInt(year));
+            xdSchedule.setMonth(Convert.toInt(month));
+            if (dayOfWeek==1){
+                xdSchedule.setDayofweek(Convert.toInt(7));
+            }else {
+                xdSchedule.setDayofweek(Convert.toInt(dayOfWeek-1));
+            }
+            xdSchedule.setDay(date);
+            xdSchedule.setCreateTime(new Date());
+            xdSchedule.setIsworking(isworking?"1":"0");
+            addDays.add(xdSchedule);
+
+            calendar.add(Calendar.DAY_OF_MONTH, 1);//日期+1
+        }
+        this.remove(new LambdaQueryWrapper<XdSchedule>().likeRight(XdSchedule::getYear,year));
+        this.saveBatch(addDays);
+
+    }
+
+
+
+}

+ 107 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/controller/CasClientController.java

@@ -0,0 +1,107 @@
+package org.jeecg.modules.cas.controller;
+
+import cn.com.ctop.common.module.entity.SysUser;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.util.RedisUtil;
+import org.jeecg.modules.cas.util.CASServiceUtil;
+import org.jeecg.modules.cas.util.XmlUtils;
+import org.jeecg.modules.system.entity.SysDepart;
+import org.jeecg.modules.system.service.ISysDepartService;
+import org.jeecg.modules.system.service.ISysUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * <p>
+ * CAS单点登录客户端登录认证
+ * </p>
+ *
+ * @Author zhoujf
+ * @since 2018-12-20
+ */
+@Slf4j
+@RestController
+@RequestMapping("/cas/client")
+public class CasClientController {
+
+	@Autowired
+	private ISysUserService sysUserService;
+	@Autowired
+    private ISysDepartService sysDepartService;
+	@Autowired
+    private RedisUtil redisUtil;
+
+	@Value("${cas.prefixUrl}")
+    private String prefixUrl;
+
+
+	@GetMapping("/validateLogin")
+	public Object validateLogin(@RequestParam(name="ticket") String ticket,
+								@RequestParam(name="service") String service,
+								HttpServletRequest request,
+								HttpServletResponse response) throws Exception {
+		Result<JSONObject> result = new Result<JSONObject>();
+		log.info("Rest api login.");
+		try {
+			String validateUrl = prefixUrl+"/p3/serviceValidate";
+			String res = CASServiceUtil.getSTValidate(validateUrl, ticket, service);
+			log.info("res."+res);
+			final String error = XmlUtils.getTextForElement(res, "authenticationFailure");
+			if(StringUtils.isNotEmpty(error)) {
+				throw new Exception(error);
+			}
+			final String principal = XmlUtils.getTextForElement(res, "user");
+			if (StringUtils.isEmpty(principal)) {
+	            throw new Exception("No principal was found in the response from the CAS server.");
+	        }
+			log.info("-------token----username---"+principal);
+		    //1. 校验用户是否有效
+	  		SysUser sysUser = sysUserService.getUserByName(principal);
+	  		result = sysUserService.checkUserIsEffective(sysUser);
+	  		if(!result.isSuccess()) {
+	  			return result;
+	  		}
+	 		String token = JwtUtil.sign(sysUser.getUsername(), sysUser.getPassword());
+	 		// 设置超时时间
+	 		redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
+	 		redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000);
+	  		//获取用户部门信息
+			JSONObject obj = new JSONObject();
+			List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
+			obj.put("departs", departs);
+			if (departs == null || departs.size() == 0) {
+				obj.put("multi_depart", 0);
+			} else if (departs.size() == 1) {
+				sysUserService.updateUserDepart(principal, departs.get(0).getOrgCode());
+				obj.put("multi_depart", 1);
+			} else {
+				obj.put("multi_depart", 2);
+			}
+			obj.put("token", token);
+			obj.put("userInfo", sysUser);
+			result.setResult(obj);
+			result.success("登录成功");
+
+		} catch (Exception e) {
+			//e.printStackTrace();
+			result.error500(e.getMessage());
+		}
+		return new HttpEntity<>(result);
+	}
+
+
+}

+ 103 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/CASServiceUtil.java

@@ -0,0 +1,103 @@
+package org.jeecg.modules.cas.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
+public class CASServiceUtil {
+	
+	public static void main(String[] args) {
+		String serviceUrl = "https://cas.8f8.com.cn:8443/cas/p3/serviceValidate";
+		String service = "http://localhost:3003/user/login";
+		String ticket = "ST-5-1g-9cNES6KXNRwq-GuRET103sm0-DESKTOP-VKLS8B3";
+		String res = getSTValidate(serviceUrl,ticket, service);
+		
+		System.out.println("---------res-----"+res);
+	}
+	
+	
+	/**
+     * 验证ST
+     */
+    public static String getSTValidate(String url,String st, String service){
+		try {
+			url = url+"?service="+service+"&ticket="+st;
+			CloseableHttpClient httpclient = createHttpClientWithNoSsl();
+			HttpGet httpget = new HttpGet(url);
+			HttpResponse response = httpclient.execute(httpget);
+	        String res = readResponse(response);
+	        return res == null ? null : (res == "" ? null : res);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return "";
+	}
+
+    
+    /**
+     * 读取 response body 内容为字符串
+     *
+     * @param response
+     * @return
+     * @throws IOException
+     */
+    private static String readResponse(HttpResponse response) throws IOException {
+        BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+        String result = new String();
+        String line;
+        while ((line = in.readLine()) != null) {
+            result += line;
+        }
+        return result;
+    }
+    
+    
+    /**
+     * 创建模拟客户端(针对 https 客户端禁用 SSL 验证)
+     *
+     * @param cookieStore 缓存的 Cookies 信息
+     * @return
+     * @throws Exception
+     */
+    private static CloseableHttpClient createHttpClientWithNoSsl() throws Exception {
+        // Create a trust manager that does not validate certificate chains
+        TrustManager[] trustAllCerts = new TrustManager[]{
+                new X509TrustManager() {
+                    @Override
+                    public X509Certificate[] getAcceptedIssuers() {
+                        return null;
+                    }
+
+                    @Override
+                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
+                        // don't check
+                    }
+
+                    @Override
+                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
+                        // don't check
+                    }
+                }
+        };
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        ctx.init(null, trustAllCerts, null);
+        LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(ctx);
+        return HttpClients.custom()
+                .setSSLSocketFactory(sslSocketFactory)
+                .build();
+    }
+
+}

+ 292 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/XmlUtils.java

@@ -0,0 +1,292 @@
+package org.jeecg.modules.cas.util;
+
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 解析cas,ST验证后的xml
+ *
+ */
+@Slf4j
+public final class XmlUtils {
+
+    /**
+     * Creates a new namespace-aware DOM document object by parsing the given XML.
+     *
+     * @param xml XML content.
+     *
+     * @return DOM document.
+     */
+    public static Document newDocument(final String xml) {
+        final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        final Map<String, Boolean> features = new HashMap<String, Boolean>();
+        features.put(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        features.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+        for (final Map.Entry<String, Boolean> entry : features.entrySet()) {
+            try {
+                factory.setFeature(entry.getKey(), entry.getValue());
+            } catch (ParserConfigurationException e) {
+                log.warn("Failed setting XML feature {}: {}", entry.getKey(), e);
+            }
+        }
+        factory.setNamespaceAware(true);
+        try {
+            return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
+        } catch (Exception e) {
+            throw new RuntimeException("XML parsing error: " + e);
+        }
+    }
+
+    /**
+     * Get an instance of an XML reader from the XMLReaderFactory.
+     *
+     * @return the XMLReader.
+     */
+    public static XMLReader getXmlReader() {
+        try {
+            final XMLReader reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
+            reader.setFeature("http://xml.org/sax/features/namespaces", true);
+            reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
+            reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+            return reader;
+        } catch (final Exception e) {
+            throw new RuntimeException("Unable to create XMLReader", e);
+        }
+    }
+
+
+    /**
+     * Retrieve the text for a group of elements. Each text element is an entry
+     * in a list.
+     * <p>This method is currently optimized for the use case of two elements in a list.
+     *
+     * @param xmlAsString the xml response
+     * @param element     the element to look for
+     * @return the list of text from the elements.
+     */
+    public static List<String> getTextForElements(final String xmlAsString, final String element) {
+        final List<String> elements = new ArrayList<String>(2);
+        final XMLReader reader = getXmlReader();
+
+        final DefaultHandler handler = new DefaultHandler() {
+
+            private boolean foundElement = false;
+
+            private StringBuilder buffer = new StringBuilder();
+
+            public void startElement(final String uri, final String localName, final String qName,
+                    final Attributes attributes) throws SAXException {
+                if (localName.equals(element)) {
+                    this.foundElement = true;
+                }
+            }
+
+            public void endElement(final String uri, final String localName, final String qName) throws SAXException {
+                if (localName.equals(element)) {
+                    this.foundElement = false;
+                    elements.add(this.buffer.toString());
+                    this.buffer = new StringBuilder();
+                }
+            }
+
+            public void characters(char[] ch, int start, int length) throws SAXException {
+                if (this.foundElement) {
+                    this.buffer.append(ch, start, length);
+                }
+            }
+        };
+
+        reader.setContentHandler(handler);
+        reader.setErrorHandler(handler);
+
+        try {
+            reader.parse(new InputSource(new StringReader(xmlAsString)));
+        } catch (final Exception e) {
+            log.error(e.getMessage(), e);
+            return null;
+        }
+
+        return elements;
+    }
+
+    /**
+     * Retrieve the text for a specific element (when we know there is only
+     * one).
+     *
+     * @param xmlAsString the xml response
+     * @param element     the element to look for
+     * @return the text value of the element.
+     */
+    public static String getTextForElement(final String xmlAsString, final String element) {
+        final XMLReader reader = getXmlReader();
+        final StringBuilder builder = new StringBuilder();
+
+        final DefaultHandler handler = new DefaultHandler() {
+
+            private boolean foundElement = false;
+
+            public void startElement(final String uri, final String localName, final String qName,
+                    final Attributes attributes) throws SAXException {
+                if (localName.equals(element)) {
+                    this.foundElement = true;
+                }
+            }
+
+            public void endElement(final String uri, final String localName, final String qName) throws SAXException {
+                if (localName.equals(element)) {
+                    this.foundElement = false;
+                }
+            }
+
+            public void characters(char[] ch, int start, int length) throws SAXException {
+                if (this.foundElement) {
+                    builder.append(ch, start, length);
+                }
+            }
+        };
+
+        reader.setContentHandler(handler);
+        reader.setErrorHandler(handler);
+
+        try {
+            reader.parse(new InputSource(new StringReader(xmlAsString)));
+        } catch (final Exception e) {
+            log.error(e.getMessage(), e);
+            return null;
+        }
+
+        return builder.toString();
+    }
+    
+    
+    public static Map<String, Object> extractCustomAttributes(final String xml) {
+        final SAXParserFactory spf = SAXParserFactory.newInstance();
+        spf.setNamespaceAware(true);
+        spf.setValidating(false);
+        try {
+            final SAXParser saxParser = spf.newSAXParser();
+            final XMLReader xmlReader = saxParser.getXMLReader();
+            final CustomAttributeHandler handler = new CustomAttributeHandler();
+            xmlReader.setContentHandler(handler);
+            xmlReader.parse(new InputSource(new StringReader(xml)));
+            return handler.getAttributes();
+        } catch (final Exception e) {
+        	log.error(e.getMessage(), e);
+            return Collections.emptyMap();
+        }
+    }
+    
+    private static class CustomAttributeHandler extends DefaultHandler {
+
+        private Map<String, Object> attributes;
+
+        private boolean foundAttributes;
+
+        private String currentAttribute;
+
+        private StringBuilder value;
+
+        @Override
+        public void startDocument() throws SAXException {
+            this.attributes = new HashMap<String, Object>();
+        }
+
+        @Override
+        public void startElement(final String namespaceURI, final String localName, final String qName,
+                final Attributes attributes) throws SAXException {
+            if ("attributes".equals(localName)) {
+                this.foundAttributes = true;
+            } else if (this.foundAttributes) {
+                this.value = new StringBuilder();
+                this.currentAttribute = localName;
+            }
+        }
+
+        @Override
+        public void characters(final char[] chars, final int start, final int length) throws SAXException {
+            if (this.currentAttribute != null) {
+                value.append(chars, start, length);
+            }
+        }
+
+        @Override
+        public void endElement(final String namespaceURI, final String localName, final String qName)
+                throws SAXException {
+            if ("attributes".equals(localName)) {
+                this.foundAttributes = false;
+                this.currentAttribute = null;
+            } else if (this.foundAttributes) {
+                final Object o = this.attributes.get(this.currentAttribute);
+
+                if (o == null) {
+                    this.attributes.put(this.currentAttribute, this.value.toString());
+                } else {
+                    final List<Object> items;
+                    if (o instanceof List) {
+                        items = (List<Object>) o;
+                    } else {
+                        items = new LinkedList<Object>();
+                        items.add(o);
+                        this.attributes.put(this.currentAttribute, items);
+                    }
+                    items.add(this.value.toString());
+                }
+            }
+        }
+
+        public Map<String, Object> getAttributes() {
+            return this.attributes;
+        }
+    }
+    
+    
+    public static void main(String[] args) {
+		String result = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\r\n" + 
+				"    <cas:authenticationSuccess>\r\n" + 
+				"        <cas:user>admin</cas:user>\r\n" + 
+				"        <cas:attributes>\r\n" + 
+				"            <cas:credentialType>UsernamePasswordCredential</cas:credentialType>\r\n" + 
+				"            <cas:isFromNewLogin>true</cas:isFromNewLogin>\r\n" + 
+				"            <cas:authenticationDate>2019-08-01T19:33:21.527+08:00[Asia/Shanghai]</cas:authenticationDate>\r\n" + 
+				"            <cas:authenticationMethod>RestAuthenticationHandler</cas:authenticationMethod>\r\n" + 
+				"            <cas:successfulAuthenticationHandlers>RestAuthenticationHandler</cas:successfulAuthenticationHandlers>\r\n" + 
+				"            <cas:longTermAuthenticationRequestTokenUsed>false</cas:longTermAuthenticationRequestTokenUsed>\r\n" + 
+				"        </cas:attributes>\r\n" + 
+				"    </cas:authenticationSuccess>\r\n" + 
+				"</cas:serviceResponse>";
+		
+		String errorRes = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\r\n" + 
+				"    <cas:authenticationFailure code=\"INVALID_TICKET\">未能够识别出目标 &#39;ST-5-1g-9cNES6KXNRwq-GuRET103sm0-DESKTOP-VKLS8B3&#39;票根</cas:authenticationFailure>\r\n" + 
+				"</cas:serviceResponse>";
+		
+		String error = XmlUtils.getTextForElement(errorRes, "authenticationFailure");
+		System.out.println("------"+error);
+		
+		String error2 = XmlUtils.getTextForElement(result, "authenticationFailure");
+		System.out.println("------"+error2);
+		String principal = XmlUtils.getTextForElement(result, "user");
+		System.out.println("---principal---"+principal);
+		Map<String, Object> attributes = XmlUtils.extractCustomAttributes(result);
+		System.out.println("---attributes---"+attributes);
+	}
+}

+ 0 - 3
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/ActorController.java

@@ -65,7 +65,6 @@ public class ActorController {
         QueryWrapper<Actor> queryWrapper = QueryGenerator.initQueryWrapper(actor, req.getParameterMap());
         Page<Actor> page = new Page<>(pageNo, pageSize);
         IPage<Actor> pageList = actorService.page(page, queryWrapper);
-
         result.setSuccess(true);
         result.setResult(pageList);
         return result;
@@ -77,7 +76,6 @@ public class ActorController {
                                                         @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                         HttpServletRequest req) {
         Result<IPage<ActorPhoto>> result = new Result<>();
-
         QueryWrapper<ActorPhoto> queryWrapper = QueryGenerator.initQueryWrapper(actorPhoto, req.getParameterMap());
         Page<ActorPhoto> page = new Page<>(pageNo, pageSize);
         IPage<ActorPhoto> pageList = actorPhotoService.page(page, queryWrapper);
@@ -92,7 +90,6 @@ public class ActorController {
                                                             @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                             HttpServletRequest req) {
         Result<IPage<ActorComment>> result = new Result<>();
-
         QueryWrapper<ActorComment> queryWrapper = QueryGenerator.initQueryWrapper(actorComment, req.getParameterMap());
         Page<ActorComment> page = new Page<>(pageNo, pageSize);
         IPage<ActorComment> pageList = actorCommentService.page(page, queryWrapper);

+ 16 - 15
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/AdvertiserController.java

@@ -1,11 +1,12 @@
 package org.jeecg.modules.ctop.controller;
 
+import cn.com.ctop.common.module.annotation.AutoLog;
 import cn.com.ctop.common.module.constant.CtopRoleCodeConstant;
 import cn.com.ctop.common.module.entity.Project;
 import cn.com.ctop.common.module.entity.UserAllocation;
 import cn.com.ctop.common.module.mapper.ProjectMapper;
 import cn.com.ctop.common.module.service.IProjectService;
-import cn.com.ctop.common.module.service.ISysRoleService;
+import cn.com.ctop.common.module.service.ISysRoleExtService;
 import cn.com.ctop.common.module.service.IUserAllocationService;
 import cn.com.ctop.common.module.utils.*;
 import com.alibaba.excel.EasyExcelFactory;
@@ -19,7 +20,6 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.aspect.annotation.AutoLog;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.util.DateUtils;
 import org.jeecg.modules.ctop.entity.Advertiser;
@@ -38,6 +38,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.text.ParseException;
 import java.util.*;
 
 /**
@@ -58,7 +59,7 @@ public class AdvertiserController {
     @Autowired
     private UserCompanyMapper userCompanyMapper;
     @Autowired
-    private ISysRoleService sysRoleService;
+    private ISysRoleExtService sysRoleService;
     @Autowired
     private ProjectMapper projectMapper;
     @Autowired
@@ -116,13 +117,13 @@ public class AdvertiserController {
         Result<IPage<Advertiser>> result = new Result<>();
         String roleCode = sysRoleService.getRoleCodeByUserId(advertiser.getUserId());
         String userId = advertiser.getUserId();
-        if (CtopRoleCodeConstant.COMMON_ROLE_CODE_ADMIN.equals(roleCode) || "kuaishouOperationManager".equals(roleCode) || "touTiaoOperationManager".equals(roleCode) || "sale".equals(roleCode) || "saleDirector".equals(roleCode)) {
+        if (CtopRoleCodeConstant.COMMON_ROLE_CODE_ADMIN.equals(roleCode) || "kuaishouOperationManager".equals(roleCode) || "touTiaoOperationManager".equals(roleCode) || roleCode.contains("sale") || "meidaManager".equals(roleCode)) {
             advertiser.setUserId(null);
         }
         String industryId = advertiser.getIndustryId();
         advertiser.setIndustryId(null);
         QueryWrapper<Advertiser> queryWrapper = QueryGenerator.initQueryWrapper(advertiser, req.getParameterMap());
-        if ("kuaishouOperationManager".equals(roleCode)) {
+        if ("kuaishouOperationManager".equals(roleCode) || "touTiaoOperationManager".equals(roleCode)) {
             QueryWrapper<UserCompany> userCompanyQueryWrapper = new QueryWrapper<>();
             userCompanyQueryWrapper.eq("user_id", userId);
             userCompanyQueryWrapper.orderByDesc("create_time");
@@ -132,10 +133,10 @@ public class AdvertiserController {
                 queryWrapper.eq("company_id", userCompany.getCompanyId());
             }
         }
-        if(null!=industryId&&!"".equals(industryId.trim())){
+        if (null != industryId && !"".equals(industryId.trim())) {
             SysCategory category = sysCategoryService.getById(industryId);
-            if(null!=category){
-                queryWrapper.likeRight("industry_code",category.getCode());
+            if (null != category) {
+                queryWrapper.likeRight("industry_code", category.getCode());
             }
         }
         Page<Advertiser> page = new Page<>(pageNo, pageSize);
@@ -179,9 +180,9 @@ public class AdvertiserController {
                 advertiser.setCompanyId(userCompany.getCompanyId());
             }
             String industryId = advertiser.getIndustryId();
-            if(null!=industryId&&!"".equals(industryId.trim())){
+            if (null != industryId && !"".equals(industryId.trim())) {
                 SysCategory category = sysCategoryService.getById(industryId);
-                if(null!=category){
+                if (null != category) {
                     advertiser.setIndustryId(category.getId());
                     advertiser.setIndustryCode(category.getCode());
                 }
@@ -214,9 +215,9 @@ public class AdvertiserController {
             result.error500("未找到对应实体");
         } else {
             String industryId = advertiser.getIndustryId();
-            if(null!=industryId&&!"".equals(industryId.trim())){
+            if (null != industryId && !"".equals(industryId.trim())) {
                 SysCategory category = sysCategoryService.getById(industryId);
-                if(null!=category){
+                if (null != category) {
                     advertiser.setIndustryId(category.getId());
                     advertiser.setIndustryCode(category.getCode());
                 }
@@ -323,7 +324,7 @@ public class AdvertiserController {
      * @return
      */
     @RequestMapping(value = "/ydWeekReportList")
-    public Map<String, Object> ydReportList(HttpServletRequest request, HttpServletResponse response, @RequestBody JSONObject data) {
+    public Map<String, Object> ydReportList(HttpServletRequest request, HttpServletResponse response, @RequestBody JSONObject data) throws ParseException {
         Map<String, Object> result = new HashMap<>();
         Long projectId = data.getLong("projectId");
         String startDate = data.getString("startDate");
@@ -385,7 +386,7 @@ public class AdvertiserController {
                 }
             }
         }
-        List<UserAllocation> allocations = userAllocationService.getByParams(projectId, systemType,null);
+        List<UserAllocation> allocations = userAllocationService.getByParams(projectId, systemType, null);
         if (null != allocations && !allocations.isEmpty()) {
             for (UserAllocation allocation : allocations) {
                 SheetInfoVo vo = advertiserService.getXxlStatisticInfo(projectId, systemType, allocation.getAccountId(), allocation.getAuthName());
@@ -420,7 +421,7 @@ public class AdvertiserController {
                 }
             }
         }
-        List<UserAllocation> allocations = userAllocationService.getByParams(projectId, systemType,null);
+        List<UserAllocation> allocations = userAllocationService.getByParams(projectId, systemType, null);
         if (null != allocations && !allocations.isEmpty()) {
             for (UserAllocation allocation : allocations) {
                 SheetInfoVo vo = advertiserService.getXxlStatisticInfo(projectId, systemType, allocation.getAccountId(), allocation.getAuthName());

+ 0 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/AgentInfoController.java


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác