ソースを参照

3.7.0大版本发布

JEECG 10 ヶ月 前
コミット
a6b6e7c9d4
100 ファイル変更2163 行追加173 行削除
  1. 2 2
      README-EN.md
  2. 2 8
      README.md
  3. 19 2
      jeecg-boot-base-core/pom.xml
  4. 14 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/api/CommonAPI.java
  5. 6 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/api/dto/LogDTO.java
  6. 5 2
      jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java
  7. 40 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
  8. 24 1
      jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java
  9. 15 10
      jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ServiceNameConstants.java
  10. 1 1
      jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/CgformEnum.java
  11. 23 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/ClientTerminalTypeEnum.java
  12. 27 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/DateRangeEnum.java
  13. 2 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/DySmsEnum.java
  14. 40 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootBizTipException.java
  15. 89 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java
  16. 19 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/system/enhance/UserFilterEnhance.java
  17. 64 10
      jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java
  18. 15 3
      jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryRuleEnum.java
  19. 30 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java
  20. 19 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/ResourceUtil.java
  21. 11 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/LoginUser.java
  22. 38 3
      jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/SysUserCacheInfo.java
  23. 242 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateRangeUtils.java
  24. 54 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateUtils.java
  25. 96 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DySmsLimit.java
  26. 50 8
      jeecg-boot-base-core/src/main/java/org/jeecg/common/util/IpUtils.java
  27. 12 4
      jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
  28. 4 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java
  29. 7 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DynamicDBUtil.java
  30. 91 4
      jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java
  31. 16 16
      jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/ConstAnalyzer.java
  32. 1 1
      jeecg-boot-base-core/src/main/java/org/jeecg/config/DruidWallConfigRegister.java
  33. 10 8
      jeecg-boot-base-core/src/main/java/org/jeecg/config/WebMvcConfiguration.java
  34. 1 1
      jeecg-boot-base-core/src/main/java/org/jeecg/config/firewall/interceptor/LowCodeModeInterceptor.java
  35. 13 1
      jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisInterceptor.java
  36. 1 1
      jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java
  37. 4 2
      jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/IgnoreAuth.java
  38. 20 2
      jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
  39. 1 1
      jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
  40. 1 0
      jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java
  41. 11 2
      jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ignore/IgnoreAuthPostProcessor.java
  42. 1 1
      jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ignore/InMemoryIgnoreAuth.java
  43. 4 2
      jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/HttpUtils.java
  44. 3 2
      jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/xml/BaseCommonMapper.xml
  45. 14 1
      jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/service/impl/BaseCommonServiceImpl.java
  46. 41 0
      jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlparse/TestIpUtil.java
  47. 1 1
      jeecg-module-demo/pom.xml
  48. 1 1
      jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/controller/ChatController.java
  49. 2 0
      jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java
  50. 1 1
      jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/pom.xml
  51. 43 1
      jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java
  52. 25 0
      jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java
  53. 1 1
      jeecg-module-system/jeecg-system-api/jeecg-system-local-api/pom.xml
  54. 20 1
      jeecg-module-system/jeecg-system-api/jeecg-system-local-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java
  55. 1 1
      jeecg-module-system/jeecg-system-api/pom.xml
  56. 3 4
      jeecg-module-system/jeecg-system-biz/pom.xml
  57. 4 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/init/CodeGenerateDbConfig.java
  58. 5 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/jimureport/JimuReportTokenService.java
  59. 3 2
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/aop/TenantPackUserLogAspect.java
  60. 52 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java
  61. 1 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/controller/SysMessageTemplateController.java
  62. 0 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/enums/RangeDateEnum.java
  63. 9 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/websocket/WebSocket.java
  64. 38 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/CustomActuatorConfig.java
  65. 44 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/httptrace/CustomHttpTraceEndpoint.java
  66. 94 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/httptrace/CustomInMemoryHttpTraceRepository.java
  67. 52 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ActuatorMemoryController.java
  68. 15 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ActuatorRedisController.java
  69. 8 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/RedisService.java
  70. 51 6
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java
  71. 7 7
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java
  72. 69 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/cache/AuthStateRedisCache.java
  73. 15 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/config/AuthStateConfiguration.java
  74. 1 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/CommonController.java
  75. 94 3
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java
  76. 66 17
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java
  77. 7 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
  78. 12 2
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java
  79. 40 4
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java
  80. 14 8
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
  81. 7 2
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java
  82. 2 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepart.java
  83. 6 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysLog.java
  84. 10 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysAnnouncementMapper.java
  85. 8 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDepartMapper.java
  86. 8 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysPackPermissionMapper.java
  87. 10 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java
  88. 7 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysTenantMapper.java
  89. 6 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysTenantPackMapper.java
  90. 13 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysTenantPackUserMapper.java
  91. 17 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java
  92. 8 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserRoleMapper.java
  93. 8 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserTenantMapper.java
  94. 11 2
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysAnnouncementMapper.xml
  95. 11 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDepartMapper.xml
  96. 11 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysPackPermissionMapper.xml
  97. 1 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysPermissionMapper.xml
  98. 10 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml
  99. 7 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysTenantMapper.xml
  100. 0 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysTenantPackMapper.xml

+ 2 - 2
README-EN.md

@@ -7,13 +7,13 @@
 JEECG BOOT Low Code Development Platform
 ===============
 
-当前最新版本: 3.6.3(发布日期:2024-03-11
+当前最新版本: 3.7.0(发布日期:2024-06-17
 
 
 [![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
 [![](https://img.shields.io/badge/Author-guojusoft-orange.svg)](http://www.jeecg.com)
 [![](https://img.shields.io/badge/Blog-blog-blue.svg)](https://jeecg.blog.csdn.net)
-[![](https://img.shields.io/badge/version-3.6.3-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
+[![](https://img.shields.io/badge/version-3.7.0-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
 [![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
 [![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)
 

+ 2 - 8
README.md

@@ -7,13 +7,13 @@
 JEECG BOOT 低代码开发平台
 ===============
 
-当前最新版本: 3.6.3(发布日期:2024-03-11
+当前最新版本: 3.7.0(发布日期:2024-06-17
 
 
 [![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
 [![](https://img.shields.io/badge/Author-北京国炬软件-orange.svg)](http://jeecg.com/aboutusIndex)
 [![](https://img.shields.io/badge/Blog-官方博客-blue.svg)](https://jeecg.blog.csdn.net)
-[![](https://img.shields.io/badge/version-3.6.3-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
+[![](https://img.shields.io/badge/version-3.7.0-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
 [![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
 [![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)
 
@@ -93,12 +93,6 @@ Docker快速启动项目
 > ` 提醒:【QQ群是自助服务群,建议给帮助您解决问题的同学发送指定红包,表示感谢!】 `
 
 
-大龄码农的思考
------------------------------------
-> 作为码农年纪大了写不动代码了怎么办??哎!!
-所以我们团队在追求不写代码也可实现复杂业务系统!目前已经做到了,不信你到敲敲云零代码试试(通过流程串联修改业务数据)
-
-- https://www.qiaoqiaoyun.com
 
 
 技术支持

+ 19 - 2
jeecg-boot-base-core/pom.xml

@@ -4,7 +4,7 @@
 	<parent>
 		<groupId>org.jeecgframework.boot</groupId>
 		<artifactId>jeecg-boot-parent</artifactId>
-		<version>3.6.3</version>
+		<version>3.7.0</version>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
 	<artifactId>jeecg-boot-base-core</artifactId>
@@ -145,6 +145,24 @@
 			<version>${postgresql.version}</version>
 			<scope>runtime</scope>
 		</dependency>
+		<!--人大金仓驱动 版本号V008R006C005B0013 -->
+		<dependency>
+			<groupId>org.jeecgframework</groupId>
+			<artifactId>kingbase8</artifactId>
+			<version>9.0.0</version>
+			<scope>runtime</scope>
+		</dependency>
+		<!--达梦数据库驱动 版本号1-3-26-2023.07.26-197096-20046-ENT -->
+		<dependency>
+			<groupId>com.dameng</groupId>
+			<artifactId>Dm8JdbcDriver18</artifactId>
+			<version>${dm8.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.dameng</groupId>
+			<artifactId>DmDialect-for-hibernate5.0</artifactId>
+			<version>${dm8.version}</version>
+		</dependency>
       
 		<!-- Quartz定时任务 -->
 		<dependency>
@@ -271,5 +289,4 @@
 			<artifactId>hutool-crypto</artifactId>
 		</dependency>
 	</dependencies>
-
 </project>

+ 14 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/api/CommonAPI.java

@@ -18,6 +18,13 @@ public interface CommonAPI {
      * @return
      */
     Set<String> queryUserRoles(String username);
+    
+    /**
+     * 1查询用户角色信息
+     * @param userId
+     * @return
+     */
+    Set<String> queryUserRolesById(String userId);
 
 
     /**
@@ -49,6 +56,13 @@ public interface CommonAPI {
      * @return
      */
     public LoginUser getUserByName(String username);
+    
+    /**
+     * 5根据用户账号查询用户Id
+     * @param username
+     * @return
+     */
+    public String getUserIdByName(String username);
 
 
     /**

+ 6 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/api/dto/LogDTO.java

@@ -1,5 +1,6 @@
 package org.jeecg.common.api.dto;
 import lombok.Data;
+import org.jeecg.common.aspect.annotation.Dict;
 import org.jeecg.common.system.vo.LoginUser;
 import java.io.Serializable;
 import java.util.Date;
@@ -55,6 +56,11 @@ public class LogDTO implements Serializable {
      */
     private Integer tenantId;
 
+    /**
+     * 客户终端类型 pc:电脑端 app:手机端 h5:移动网页端
+     */
+    private String clientType;
+    
     public LogDTO(){
 
     }

+ 5 - 2
jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java

@@ -52,7 +52,9 @@ public class DictAspect {
     /**
      * 定义切点Pointcut
      */
-    @Pointcut("execution(public * org.jeecg.modules..*.*Controller.*(..)) || @annotation(org.jeecg.common.aspect.annotation.AutoDict)")
+    @Pointcut("(@within(org.springframework.web.bind.annotation.RestController) || " +
+            "@within(org.springframework.stereotype.Controller) || @annotation(org.jeecg.common.aspect.annotation.AutoDict)) " +
+            "&& execution(public org.jeecg.common.api.vo.Result org.jeecg..*.*(..))")
     public void excudeService() {
     }
 
@@ -92,7 +94,8 @@ public class DictAspect {
      * @param result
      */
     private Object parseDictText(Object result) {
-        if (result instanceof Result) {
+        //if (result instanceof Result) {
+        if (true) {
             if (((Result) result).getResult() instanceof IPage) {
                 List<JSONObject> items = new ArrayList<>();
 

+ 40 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java

@@ -36,6 +36,16 @@ public interface CommonConstant {
 	 */
 	int LOG_TYPE_2 = 2;
 
+    /**
+     * 系统日志类型: 租户操作日志
+     */
+    int LOG_TYPE_3 = 3;
+
+    /**
+     * 系统日志类型: 异常
+     */
+    int LOG_TYPE_4 = 4;
+
 	/**
 	 * 操作日志类型: 查询
 	 */
@@ -286,6 +296,10 @@ public interface CommonConstant {
      * 在线聊天 用户好友缓存前缀
      */
     String IM_PREFIX_USER_FRIEND_CACHE = "sys:cache:im:im_prefix_user_friend_";
+    /**
+     * 缓存用户id与用户名关系
+     */
+    String SYS_USER_ID_MAPPING_CACHE = "sys:cache:user:id_mapping";
 
     /**
      * 考勤补卡业务状态 (1:同意  2:不同意)
@@ -577,4 +591,30 @@ public interface CommonConstant {
    public static final String SAAS_MODE_TENANT = "tenant";
    //update-end---author:scott ---date::2023-09-10  for:积木报表常量----
  
+   //update-begin---author:wangshuai---date:2024-04-07---for:修改手机号常量---
+   /**
+    * 修改手机号短信验证码redis-key的前缀
+    */
+   String CHANGE_PHONE_REDIS_KEY_PRE = "sys:cache:phone:change_phone_msg:";
+
+    /**
+     * 缓存用户最后一次收到消息通知的时间 KEY
+     */
+   String CACHE_KEY_USER_LAST_ANNOUNT_TIME_1HOUR = "sys:cache:userinfo:user_last_annount_time::%s";
+   
+   /**
+    * 验证原手机号
+    */
+   String VERIFY_ORIGINAL_PHONE = "verifyOriginalPhone";
+
+   /**
+    * 修改手机号
+    */
+   String UPDATE_PHONE = "updatePhone";
+   //update-end---author:wangshuai---date:2024-04-07---for:修改手机号常量---
+    
+   /**
+    * 修改手机号验证码请求次数超出
+    */
+   Integer PHONE_SMS_FAIL_CODE = 40002;
 }

+ 24 - 1
jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java

@@ -58,6 +58,22 @@ public interface DataBaseConstant {
 	 * 数据-所属机构编码
 	 */
 	public static final String SYS_MULTI_ORG_CODE_TABLE = "sys_multi_org_code";
+	/**
+	 * 数据-所属机构ID
+	 */
+	public static final String SYS_ORG_ID = "sysOrgId";
+	/**
+	 * 数据-所属机构ID
+	 */
+	public static final String SYS_ORG_ID_TABLE = "sys_org_id";
+	/**
+	 * 数据-所属角色code(多个逗号分割)
+	 */
+	public static final String SYS_ROLE_CODE = "sysRoleCode";
+	/**
+	 * 数据-所属角色code(多个逗号分割)
+	 */
+	public static final String SYS_ROLE_CODE_TABLE = "sys_role_code";
 	/**
 	 * 数据-系统用户编码(对应登录用户账号)
 	 */
@@ -66,7 +82,14 @@ public interface DataBaseConstant {
 	 * 数据-系统用户编码(对应登录用户账号)
 	 */
 	public static final String SYS_USER_CODE_TABLE = "sys_user_code";
-	
+	/**
+	 * 登录用户ID
+	 */
+	public static final String SYS_USER_ID = "sysUserId";
+	/**
+	 * 登录用户ID
+	 */
+	public static final String SYS_USER_ID_TABLE = "sys_user_id";
 	/**
 	 * 登录用户真实姓名
 	 */

+ 15 - 10
jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ServiceNameConstants.java

@@ -34,17 +34,22 @@ public interface ServiceNameConstants {
 	 */
 	String SERVICE_DEMO = "jeecg-demo";
 	/**
-	 * 微服务名:online在线模块
+	 * 微服务名:joa模块
 	 */
-	String SERVICE_ONLINE = "jeecg-online";
-	/**
-	 * 微服务名:OA模块
-	 */
-	String SERVICE_EOA = "jeecg-eoa";
-	/**
-	 * 微服务名:表单设计模块
-	 */
-	String SERVICE_FORM = "jeecg-desform";
+	String SERVICE_JOA = "jeecg-joa";
+	
+//	/**
+//	 * 微服务名:online在线模块
+//	 */
+//	String SERVICE_ONLINE = "jeecg-online";
+//	/**
+//	 * 微服务名:OA模块
+//	 */
+//	String SERVICE_EOA = "jeecg-eoa";
+//	/**
+//	 * 微服务名:表单设计模块
+//	 */
+//	String SERVICE_FORM = "jeecg-desform";
 
 	/**
 	 * gateway通过header传递根路径 basePath

+ 1 - 1
jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/CgformEnum.java

@@ -23,7 +23,7 @@ public enum CgformEnum {
     /**
      * 多表(jvxe风格)
      *  */
-    JVXE_TABLE(2, "jvxe", "/jeecg/code-template-online", "jvxe.onetomany", "JVXE风格" ,new String[]{"vue3","vue","vue3Native"}),
+    JVXE_TABLE(2, "jvxe", "/jeecg/code-template-online", "jvxe.onetomany", "默认风格" ,new String[]{"vue3","vue","vue3Native"}),
 
     /**
      * 多表 (erp风格)

+ 23 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/ClientTerminalTypeEnum.java

@@ -0,0 +1,23 @@
+package org.jeecg.common.constant.enums;
+
+/**
+ * 客户终端类型
+ */
+public enum ClientTerminalTypeEnum {
+
+    PC("pc", "电脑终端"),
+    H5("h5", "移动网页端"),
+    APP("app", "手机app端");
+
+    private String key;
+    private String text;
+
+    ClientTerminalTypeEnum(String value, String text) {
+        this.key = value;
+        this.text = text;
+    }
+
+    public String getKey() {
+        return this.key;
+    }
+}

+ 27 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/DateRangeEnum.java

@@ -0,0 +1,27 @@
+package org.jeecg.common.constant.enums;
+
+/**
+ * 日期预设范围枚举
+ */
+public enum DateRangeEnum {
+    // 今天
+    TODAY,
+    // 昨天
+    YESTERDAY,
+    // 明天
+    TOMORROW,
+    // 本周
+    THIS_WEEK,
+    // 上周
+    LAST_WEEK,
+    // 下周
+    NEXT_WEEK,
+    // 过去七天
+    LAST_7_DAYS,
+    // 本月
+    THIS_MONTH,
+    // 上月
+    LAST_MONTH,
+    // 下月
+    NEXT_MONTH,
+}

+ 2 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/DySmsEnum.java

@@ -12,6 +12,8 @@ public enum DySmsEnum {
 	LOGIN_TEMPLATE_CODE("SMS_175435174","敲敲云","code"),
     /**忘记密码短信模板编码*/
 	FORGET_PASSWORD_TEMPLATE_CODE("SMS_175435174","敲敲云","code"),
+	/**修改密码短信模板编码*/
+	CHANGE_PASSWORD_TEMPLATE_CODE("SMS_465391221","敲敲云","code"),
 	/**注册账号短信模板编码*/
 	REGISTER_TEMPLATE_CODE("SMS_175430166","敲敲云","code"),
 	/**会议通知*/

+ 40 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootBizTipException.java

@@ -0,0 +1,40 @@
+package org.jeecg.common.exception;
+
+import org.jeecg.common.constant.CommonConstant;
+
+/**
+ * @Description: 业务提醒异常(用于操作业务提醒)
+ * @date: 2024-04-26
+ * @author: scott
+ */
+public class JeecgBootBizTipException extends RuntimeException {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 返回给前端的错误code
+	 */
+	private int errCode = CommonConstant.SC_INTERNAL_SERVER_ERROR_500;
+
+	public JeecgBootBizTipException(String message){
+		super(message);
+	}
+
+	public JeecgBootBizTipException(String message, int errCode){
+		super(message);
+		this.errCode = errCode;
+	}
+
+	public int getErrCode() {
+		return errCode;
+	}
+
+	public JeecgBootBizTipException(Throwable cause)
+	{
+		super(cause);
+	}
+	
+	public JeecgBootBizTipException(String message, Throwable cause)
+	{
+		super(message,cause);
+	}
+}

+ 89 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java

@@ -2,14 +2,27 @@ package org.jeecg.common.exception;
 
 import cn.hutool.core.util.ObjectUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authz.AuthorizationException;
 import org.apache.shiro.authz.UnauthorizedException;
+import org.jeecg.common.api.dto.LogDTO;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.enums.ClientTerminalTypeEnum;
 import org.jeecg.common.enums.SentinelErrorInfoEnum;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.BrowserUtils;
+import org.jeecg.common.util.IpUtils;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.base.service.BaseCommonService;
+import org.springframework.beans.BeansException;
 import org.springframework.dao.DataIntegrityViolationException;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.data.redis.connection.PoolException;
 import org.springframework.http.HttpStatus;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.HttpRequestMethodNotSupportedException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.ResponseStatus;
@@ -17,6 +30,10 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
 import org.springframework.web.multipart.MaxUploadSizeExceededException;
 import org.springframework.web.servlet.NoHandlerFoundException;
 
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
 /**
  * 异常处理器
  * 
@@ -27,12 +44,25 @@ import org.springframework.web.servlet.NoHandlerFoundException;
 @Slf4j
 public class JeecgBootExceptionHandler {
 
+	@Resource
+	BaseCommonService baseCommonService;
+
 	/**
 	 * 处理自定义异常
 	 */
 	@ExceptionHandler(JeecgBootException.class)
 	public Result<?> handleJeecgBootException(JeecgBootException e){
 		log.error(e.getMessage(), e);
+		addSysLog(e);
+		return Result.error(e.getErrCode(), e.getMessage());
+	}
+	
+	/**
+	 * 处理自定义异常
+	 */
+	@ExceptionHandler(JeecgBootBizTipException.class)
+	public Result<?> handleJeecgBootBizTipException(JeecgBootBizTipException e){
+		log.error(e.getMessage());
 		return Result.error(e.getErrCode(), e.getMessage());
 	}
 
@@ -42,6 +72,7 @@ public class JeecgBootExceptionHandler {
 	@ExceptionHandler(JeecgCloudException.class)
 	public Result<?> handleJeecgCloudException(JeecgCloudException e){
 		log.error(e.getMessage(), e);
+		addSysLog(e);
 		return Result.error(e.getMessage());
 	}
 
@@ -52,18 +83,21 @@ public class JeecgBootExceptionHandler {
 	@ResponseStatus(HttpStatus.UNAUTHORIZED)
 	public Result<?> handleJeecgBoot401Exception(JeecgBoot401Exception e){
 		log.error(e.getMessage(), e);
+		addSysLog(e);
 		return new Result(401,e.getMessage());
 	}
 
 	@ExceptionHandler(NoHandlerFoundException.class)
 	public Result<?> handlerNoFoundException(Exception e) {
 		log.error(e.getMessage(), e);
+		addSysLog(e);
 		return Result.error(404, "路径不存在,请检查路径是否正确");
 	}
 
 	@ExceptionHandler(DuplicateKeyException.class)
 	public Result<?> handleDuplicateKeyException(DuplicateKeyException e){
 		log.error(e.getMessage(), e);
+		addSysLog(e);
 		return Result.error("数据库中已存在该记录");
 	}
 
@@ -83,6 +117,7 @@ public class JeecgBootExceptionHandler {
 			return Result.error(errorInfoEnum.getError());
 		}
 		//update-end---author:zyf ---date:20220411  for:处理Sentinel限流自定义异常
+		addSysLog(e);
 		return Result.error("操作失败,"+e.getMessage());
 	}
 	
@@ -107,6 +142,7 @@ public class JeecgBootExceptionHandler {
 		}
 		log.error(sb.toString(), e);
 		//return Result.error("没有权限,请联系管理员授权");
+		addSysLog(e);
 		return Result.error(405,sb.toString());
 	}
 	
@@ -116,12 +152,14 @@ public class JeecgBootExceptionHandler {
     @ExceptionHandler(MaxUploadSizeExceededException.class)
     public Result<?> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
     	log.error(e.getMessage(), e);
+		addSysLog(e);
         return Result.error("文件大小超出10MB限制, 请压缩或降低文件质量! ");
     }
 
     @ExceptionHandler(DataIntegrityViolationException.class)
     public Result<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
     	log.error(e.getMessage(), e);
+		addSysLog(e);
     	//【issues/3624】数据库执行异常handleDataIntegrityViolationException提示有误 #3624
         return Result.error("执行数据库异常,违反了完整性例如:违反惟一约束、违反非空限制、字段内容超出长度等");
     }
@@ -129,6 +167,7 @@ public class JeecgBootExceptionHandler {
     @ExceptionHandler(PoolException.class)
     public Result<?> handlePoolException(PoolException e) {
     	log.error(e.getMessage(), e);
+		addSysLog(e);
         return Result.error("Redis 连接异常!");
     }
 
@@ -149,7 +188,57 @@ public class JeecgBootExceptionHandler {
 			log.error("校验失败,存在SQL注入风险!{}", msg);
 			return Result.error("校验失败,存在SQL注入风险!");
 		}
+		addSysLog(exception);
 		return Result.error("校验失败,存在SQL注入风险!" + msg);
 	}
 
+	//update-begin---author:chenrui ---date:20240423  for:[QQYUN-8732]把错误的日志都抓取了 方便后续处理,单独弄个日志类型------------
+	/**
+	 * 添加异常新系统日志
+	 * @param e 异常
+	 * @author chenrui
+	 * @date 2024/4/22 17:16
+	 */
+    private void addSysLog(Throwable e) {
+        LogDTO log = new LogDTO();
+        log.setLogType(CommonConstant.LOG_TYPE_4);
+        log.setLogContent(e.getClass().getName()+":"+e.getMessage());
+		log.setRequestParam(ExceptionUtils.getStackTrace(e));
+        //获取request
+        HttpServletRequest request = null;
+        try {
+            request = SpringContextUtils.getHttpServletRequest();
+        } catch (NullPointerException | BeansException ignored) {
+        }
+        if (null != request) {
+			//请求的参数
+			Map<String, String[]> parameterMap = request.getParameterMap();
+			if(!CollectionUtils.isEmpty(parameterMap)){
+				log.setMethod(oConvertUtils.mapToString(request.getParameterMap()));
+			}
+            // 请求地址
+            log.setRequestUrl(request.getRequestURI());
+            //设置IP地址
+            log.setIp(IpUtils.getIpAddr(request));
+            //设置客户端
+			if(BrowserUtils.isDesktop(request)){
+				log.setClientType(ClientTerminalTypeEnum.PC.getKey());
+			}else{
+				log.setClientType(ClientTerminalTypeEnum.APP.getKey());
+			}
+        }
+
+       
+		//获取登录用户信息
+		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+		if(sysUser!=null){
+			log.setUserid(sysUser.getUsername());
+			log.setUsername(sysUser.getRealname());
+
+		}
+
+        baseCommonService.addLog(log);
+    }
+	//update-end---author:chenrui ---date:20240423  for:[QQYUN-8732]把错误的日志都抓取了 方便后续处理,单独弄个日志类型------------
+
 }

+ 19 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/system/enhance/UserFilterEnhance.java

@@ -0,0 +1,19 @@
+package org.jeecg.common.system.enhance;
+
+import java.util.List;
+
+/**
+ * 用户增强
+ */
+public interface UserFilterEnhance {
+    
+    /**
+     * 获取用户id
+     * @param loginUserId 当前登录的用户id
+     * 
+     * @return List<String> 返回多个用户id
+     */
+    default List<String> getUserIds(String loginUserId) {
+        return null;
+    }
+}

+ 64 - 10
jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java

@@ -2,7 +2,6 @@ package org.jeecg.common.system.query;
 
 import java.beans.PropertyDescriptor;
 import java.io.UnsupportedEncodingException;
-import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.net.URLDecoder;
 import java.text.ParseException;
@@ -15,7 +14,6 @@ import java.util.stream.Collectors;
 import org.apache.commons.beanutils.PropertyUtils;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.DataBaseConstant;
-import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.system.util.JeecgDataAutorUtils;
 import org.jeecg.common.system.util.JwtUtil;
@@ -25,7 +23,6 @@ import org.jeecg.common.util.*;
 import org.springframework.util.NumberUtils;
 
 import com.alibaba.fastjson.JSON;
-import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 
 import lombok.extern.slf4j.Slf4j;
@@ -94,10 +91,27 @@ public class QueryGenerator {
 	public static <T> QueryWrapper<T> initQueryWrapper(T searchObj,Map<String, String[]> parameterMap){
 		long start = System.currentTimeMillis();
 		QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
-		installMplus(queryWrapper, searchObj, parameterMap);
+		installMplus(queryWrapper, searchObj, parameterMap, null);
 		log.debug("---查询条件构造器初始化完成,耗时:"+(System.currentTimeMillis()-start)+"毫秒----");
 		return queryWrapper;
 	}
+	
+	//update-begin---author:chenrui ---date:20240527  for:[TV360X-378]增加自定义字段查询规则功能------------
+	/**
+	 * 获取查询条件构造器QueryWrapper实例 通用查询条件已被封装完成
+	 * @param searchObj 查询实体
+	 * @param parameterMap request.getParameterMap()
+	 * @param customRuleMap 自定义字段查询规则 {field:QueryRuleEnum}
+	 * @return QueryWrapper实例
+	 */
+	public static <T> QueryWrapper<T> initQueryWrapper(T searchObj,Map<String, String[]> parameterMap, Map<String, QueryRuleEnum> customRuleMap){
+		long start = System.currentTimeMillis();
+		QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
+		installMplus(queryWrapper, searchObj, parameterMap, customRuleMap);
+		log.debug("---查询条件构造器初始化完成,耗时:"+(System.currentTimeMillis()-start)+"毫秒----");
+		return queryWrapper;
+	}
+	//update-end---author:chenrui ---date:20240527  for:[TV360X-378]增加自定义字段查询规则功能------------
 
 	/**
 	 * 组装Mybatis Plus 查询条件
@@ -108,8 +122,7 @@ public class QueryGenerator {
 	 * <br>正确示例:QueryWrapper<JeecgDemo> queryWrapper = new QueryWrapper<JeecgDemo>();
 	 * <br>3.也可以不使用这个方法直接调用 {@link #initQueryWrapper}直接获取实例
 	 */
-	private static void installMplus(QueryWrapper<?> queryWrapper,Object searchObj,Map<String, String[]> parameterMap) {
-		
+	private static void installMplus(QueryWrapper<?> queryWrapper, Object searchObj, Map<String, String[]> parameterMap, Map<String, QueryRuleEnum> customRuleMap) {
 		/*
 		 * 注意:权限查询由前端配置数据规则 当一个人有多个所属部门时候 可以在规则配置包含条件 orgCode 包含 #{sys_org_code}
 		但是不支持在自定义SQL中写orgCode in #{sys_org_code} 
@@ -174,8 +187,16 @@ public class QueryGenerator {
 						queryWrapper.and(j -> j.like(field,vals[0]));
 					}
 				}else {
-					//根据参数值带什么关键字符串判断走什么类型的查询
-					QueryRuleEnum rule = convert2Rule(value);
+					//update-begin---author:chenrui ---date:20240527  for:[TV360X-378]增加自定义字段查询规则功能------------
+					QueryRuleEnum rule;
+					if(null != customRuleMap && customRuleMap.containsKey(name)) {
+						// 有自定义规则,使用自定义规则.
+						rule = customRuleMap.get(name);
+					}else {
+						//根据参数值带什么关键字符串判断走什么类型的查询
+						 rule = convert2Rule(value);
+					}
+					//update-end---author:chenrui ---date:20240527  for:[TV360X-378]增加自定义字段查询规则功能------------
 					value = replaceValue(rule,value);
 					// add -begin 添加判断为字符串时设为全模糊查询
 					//if( (rule==null || QueryRuleEnum.EQ.equals(rule)) && "class java.lang.String".equals(type)) {
@@ -274,7 +295,7 @@ public class QueryGenerator {
 			//update-end-author:scott date:2022-10-10 for:【jeecg-boot/issues/I5FJU6】doMultiFieldsOrder() 多字段排序方法存在问题
 
 			//SQL注入check
-			SqlInjectionUtil.filterContent(column);
+			SqlInjectionUtil.filterContentMulti(column);
 
 			//update-begin--Author:scott  Date:20210531 for:36 多条件排序无效问题修正-------
 			// 排序规则修改
@@ -678,9 +699,40 @@ public class QueryGenerator {
 		case LEFT_LIKE:
 			queryWrapper.likeLeft(name, value);
 			break;
+		case NOT_LEFT_LIKE:
+			queryWrapper.notLikeLeft(name, value);
+			break;
 		case RIGHT_LIKE:
 			queryWrapper.likeRight(name, value);
 			break;
+		case NOT_RIGHT_LIKE:
+			queryWrapper.notLikeRight(name, value);
+			break;
+		//update-begin---author:chenrui ---date:20240527  for:[TV360X-378]下拉多框根据条件查询不出来:增加自定义字段查询规则功能------------
+		case LIKE_WITH_OR:
+			final String nameFinal = name;
+			Object[] vals;
+			if (value instanceof String) {
+				vals = value.toString().split(COMMA);
+			} else if (value instanceof String[]) {
+				vals = (Object[]) value;
+			}
+			//update-begin-author:taoyan date:20200909 for:【bug】in 类型多值查询 不适配postgresql #1671
+			else if (value.getClass().isArray()) {
+				vals = (Object[]) value;
+			} else {
+				vals = new Object[]{value};
+			}
+			queryWrapper.and(j -> {
+				log.info("---查询过滤器,Query规则---field:{}, rule:{}, value:{}", nameFinal, "like", vals[0]);
+				j = j.like(nameFinal, vals[0]);
+				for (int k = 1; k < vals.length; k++) {
+					j = j.or().like(nameFinal, vals[k]);
+					log.info("---查询过滤器,Query规则 .or()---field:{}, rule:{}, value:{}", nameFinal, "like", vals[k]);
+				}
+			});
+			break;
+		//update-end---author:chenrui ---date:20240527  for:[TV360X-378]下拉多框根据条件查询不出来:增加自定义字段查询规则功能------------
 		default:
 			log.info("--查询规则未匹配到---");
 			break;
@@ -856,7 +908,9 @@ public class QueryGenerator {
 				Class propType = origDescriptors[i].getPropertyType();
 				boolean isString = propType.equals(String.class);
 				Object value;
-				if(isString) {
+				//update-begin---author:chenrui ---date:20240527  for:[TV360X-539]数据权限,配置日期等于条件时后端报转换错误------------
+				if(isString || Date.class.equals(propType)) {
+				//update-end---author:chenrui ---date:20240527  for:[TV360X-539]数据权限,配置日期等于条件时后端报转换错误------------
 					value = converRuleValue(dataRule.getRuleValue());
 				}else {
 					value = NumberUtils.parseNumber(dataRule.getRuleValue(),propType);

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

@@ -33,12 +33,21 @@ public enum QueryRuleEnum {
     RIGHT_LIKE("RIGHT_LIKE","right_like","右模糊"),
     /**查询规则 带加号等于*/
     EQ_WITH_ADD("EQWITHADD","eq_with_add","带加号等于"),
-    /**查询规则 多词模糊匹配*/
+    /**查询规则 多词模糊匹配(and)*/
     LIKE_WITH_AND("LIKEWITHAND","like_with_and","多词模糊匹配————暂时未用上"),
+    /**查询规则 多词模糊匹配(or)*/
+    LIKE_WITH_OR("LIKEWITHOR","like_with_or","多词模糊匹配(or)"),
     /**查询规则 自定义SQL片段*/
     SQL_RULES("USE_SQL_RULES","ext","自定义SQL片段"),
-    
+
+    /** 查询工作表 */
+    LINKAGE("LINKAGE","linkage","查询工作表"),
+
     // ------- 当前表单设计器内专用 -------
+    /**查询规则 不以…结尾*/
+    NOT_LEFT_LIKE("NOT_LEFT_LIKE","not_left_like","不以…结尾"),
+    /**查询规则 不以…开头*/
+    NOT_RIGHT_LIKE("NOT_RIGHT_LIKE","not_right_like","不以…开头"),
     /** 值为空 */
     EMPTY("EMPTY","empty","值为空"),
     /** 值不为空 */
@@ -49,7 +58,10 @@ public enum QueryRuleEnum {
     ELE_MATCH("ELE_MATCH","elemMatch","多词匹配"),
     /**查询规则 范围查询*/
     RANGE("RANGE","range","范围查询"),
-    NOT_RANGE("NOT_RANGE","not_range","不在范围查询");
+    /**查询规则 不在范围内查询*/
+    NOT_RANGE("NOT_RANGE","not_range","不在范围查询"),
+    /** 自定义mongodb查询语句 */
+    CUSTOM_MONGODB("CUSTOM_MONGODB","custom_mongodb","自定义mongodb查询语句");
     // ------- 当前表单设计器内专用 -------
 
     private String value;

+ 30 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java

@@ -221,6 +221,16 @@ public class JwtUtil {
 				returnValue = user.getSysUserCode();
 			}
 		}
+
+		// 替换为系统登录用户ID
+		else if (key.equals(DataBaseConstant.SYS_USER_ID) || key.equalsIgnoreCase(DataBaseConstant.SYS_USER_ID_TABLE)) {
+			if(user==null) {
+				returnValue = sysUser.getId();
+			}else {
+				returnValue = user.getSysUserId();
+			}
+		}
+
 		//替换为系统登录用户真实名字
 		else if (key.equals(DataBaseConstant.SYS_USER_NAME)|| key.toLowerCase().equals(DataBaseConstant.SYS_USER_NAME_TABLE)) {
 			if(user==null) {
@@ -238,6 +248,16 @@ public class JwtUtil {
 				returnValue = user.getSysOrgCode();
 			}
 		}
+
+		// 替换为系统用户登录所使用的机构ID
+		else if (key.equals(DataBaseConstant.SYS_ORG_ID) || key.equalsIgnoreCase(DataBaseConstant.SYS_ORG_ID_TABLE)) {
+			if (user == null) {
+				returnValue = sysUser.getOrgId();
+			} else {
+				returnValue = user.getSysOrgId();
+			}
+		}
+
 		//替换为系统用户所拥有的所有机构编码
 		else if (key.equals(DataBaseConstant.SYS_MULTI_ORG_CODE)|| key.toLowerCase().equals(DataBaseConstant.SYS_MULTI_ORG_CODE_TABLE)) {
 			if(user==null){
@@ -251,6 +271,16 @@ public class JwtUtil {
 				}
 			}
 		}
+
+		// 替换为当前登录用户的角色code(多个逗号分割)
+		else if (key.equals(DataBaseConstant.SYS_ROLE_CODE) || key.equalsIgnoreCase(DataBaseConstant.SYS_ROLE_CODE_TABLE)) {
+			if (user == null) {
+				returnValue = sysUser.getRoleCode();
+			} else {
+				returnValue = user.getSysRoleCode();
+			}
+		}
+
 		//update-begin-author:taoyan date:20210330 for:多租户ID作为系统变量
 		else if (key.equals(TenantConstant.TENANT_ID) || key.toLowerCase().equals(TenantConstant.TENANT_ID_TABLE)){
 			try {

+ 19 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/ResourceUtil.java

@@ -3,7 +3,9 @@ package org.jeecg.common.system.util;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.system.annotation.EnumDict;
 import org.jeecg.common.system.vo.DictModel;
+import org.jeecg.common.util.SpringContextUtils;
 import org.jeecg.common.util.oConvertUtils;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.core.io.Resource;
 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 import org.springframework.core.io.support.ResourcePatternResolver;
@@ -114,4 +116,21 @@ public class ResourceUtil {
         return map;
     }
 
+    /**
+     * 获取实现类
+     * 
+     * @param classPath 
+     */
+    public static Object getImplementationClass(String classPath){
+        try {
+            Class<?> aClass = Class.forName(classPath);
+            return SpringContextUtils.getBean(aClass);
+        } catch (ClassNotFoundException e) {
+            log.error("类没有找到",e);
+            return null;
+        } catch (NoSuchBeanDefinitionException e){
+            log.error(classPath + "没有实现",e);
+            return null;
+        }
+    }
 }

+ 11 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/LoginUser.java

@@ -51,6 +51,17 @@ public class LoginUser {
       */
 	@SensitiveField
     private String orgCode;
+	/**
+	 * 当前登录部门id
+	 */
+	@SensitiveField
+	private String orgId;
+	/**
+	 * 当前登录角色code(多个逗号分割)
+	 */
+	@SensitiveField
+	private String roleCode;
+
 	/**
 	 * 头像
 	 */

+ 38 - 3
jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/SysUserCacheInfo.java

@@ -9,17 +9,29 @@ import org.jeecg.common.util.DateUtils;
  * @author: jeecg-boot
  */
 public class SysUserCacheInfo {
-	
+
+	private String sysUserId;
+
 	private String sysUserCode;
 	
 	private String sysUserName;
 	
 	private String sysOrgCode;
-	
+
+	/**
+	 * 当前用户部门ID
+	 */
+	private String sysOrgId;
+
 	private List<String> sysMultiOrgCode;
 	
 	private boolean oneDepart;
-	
+
+	/**
+	 * 当前用户角色code(多个逗号分割)
+	 */
+	private String sysRoleCode;
+
 	public boolean isOneDepart() {
 		return oneDepart;
 	}
@@ -68,4 +80,27 @@ public class SysUserCacheInfo {
 		this.sysMultiOrgCode = sysMultiOrgCode;
 	}
 
+	public String getSysUserId() {
+		return sysUserId;
+	}
+
+	public void setSysUserId(String sysUserId) {
+		this.sysUserId = sysUserId;
+	}
+
+	public String getSysOrgId() {
+		return sysOrgId;
+	}
+
+	public void setSysOrgId(String sysOrgId) {
+		this.sysOrgId = sysOrgId;
+	}
+
+	public String getSysRoleCode() {
+		return sysRoleCode;
+	}
+
+	public void setSysRoleCode(String sysRoleCode) {
+		this.sysRoleCode = sysRoleCode;
+	}
 }

+ 242 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateRangeUtils.java

@@ -0,0 +1,242 @@
+package org.jeecg.common.util;
+
+import cn.hutool.core.date.DateUtil;
+import org.jeecg.common.constant.enums.DateRangeEnum;
+
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * 日期范围工具类
+ *
+ * @author scott
+ * @date 20230801
+ */
+public class DateRangeUtils {
+
+    /**
+     * 根据日期范围枚举获取日期范围
+     *
+     * @param rangeEnum
+     * @return Date[]
+     */
+    public static Date[] getDateRangeByEnum(DateRangeEnum rangeEnum) {
+        if (rangeEnum == null) {
+            return null;
+        }
+        Date[] ranges = new Date[2];
+        switch (rangeEnum) {
+            case TODAY:
+                ranges[0] = getTodayStartTime();
+                ranges[1] = getTodayEndTime();
+                break;
+            case YESTERDAY:
+                ranges[0] = getYesterdayStartTime();
+                ranges[1] = getYesterdayEndTime();
+                break;
+            case TOMORROW:
+                ranges[0] = getTomorrowStartTime();
+                ranges[1] = getTomorrowEndTime();
+                break;
+            case THIS_WEEK:
+                ranges[0] = getThisWeekStartDay();
+                ranges[1] = getThisWeekEndDay();
+                break;
+            case LAST_WEEK:
+                ranges[0] = getLastWeekStartDay();
+                ranges[1] = getLastWeekEndDay();
+                break;
+            case NEXT_WEEK:
+                ranges[0] = getNextWeekStartDay();
+                ranges[1] = getNextWeekEndDay();
+                break;
+            case LAST_7_DAYS:
+                ranges[0] = getLast7DaysStartTime();
+                ranges[1] = getLast7DaysEndTime();
+                break;
+            case THIS_MONTH:
+                ranges[0] = getThisMonthStartDay();
+                ranges[1] = getThisMonthEndDay();
+                break;
+            case LAST_MONTH:
+                ranges[0] = getLastMonthStartDay();
+                ranges[1] = getLastMonthEndDay();
+                break;
+            case NEXT_MONTH:
+                ranges[0] = getNextMonthStartDay();
+                ranges[1] = getNextMonthEndDay();
+                break;
+            default:
+                return null;
+        }
+        return ranges;
+    }
+
+    /**
+     * 获得下月第一天 周日 00:00:00
+     */
+    public static Date getNextMonthStartDay() {
+        return DateUtil.beginOfMonth(DateUtil.nextMonth());
+    }
+
+    /**
+     * 获得下月最后一天 23:59:59
+     */
+    public static Date getNextMonthEndDay() {
+        return DateUtil.endOfMonth(DateUtil.nextMonth());
+    }
+
+    /**
+     * 获得本月第一天 周日 00:00:00
+     */
+    public static Date getThisMonthStartDay() {
+        return DateUtil.beginOfMonth(DateUtil.date());
+    }
+
+    /**
+     * 获得本月最后一天 23:59:59
+     */
+    public static Date getThisMonthEndDay() {
+        return DateUtil.endOfMonth(DateUtil.date());
+    }
+
+    /**
+     * 获得上月第一天 周日 00:00:00
+     */
+    public static Date getLastMonthStartDay() {
+        return DateUtil.beginOfMonth(DateUtil.lastMonth());
+    }
+
+    /**
+     * 获得上月最后一天 23:59:59
+     */
+    public static Date getLastMonthEndDay() {
+        return DateUtil.endOfMonth(DateUtil.lastMonth());
+    }
+
+    /**
+     * 获得上周第一天 周一 00:00:00
+     */
+    public static Date getLastWeekStartDay() {
+        return DateUtil.beginOfWeek(DateUtil.lastWeek());
+    }
+
+    /**
+     * 获得上周最后一天 周日 23:59:59
+     */
+    public static Date getLastWeekEndDay() {
+        return DateUtil.endOfWeek(DateUtil.lastWeek());
+    }
+
+    /**
+     * 获得本周第一天 周一 00:00:00
+     */
+    public static Date getThisWeekStartDay() {
+        Date today = new Date();
+        return DateUtil.beginOfWeek(today);
+    }
+
+    /**
+     * 获得本周最后一天 周日 23:59:59
+     */
+    public static Date getThisWeekEndDay() {
+        Date today = new Date();
+        return DateUtil.endOfWeek(today);
+    }
+
+    /**
+     * 获得下周第一天 周一 00:00:00
+     */
+    public static Date getNextWeekStartDay() {
+        return DateUtil.beginOfWeek(DateUtil.nextWeek());
+    }
+
+    /**
+     * 获得下周最后一天 周日 23:59:59
+     */
+    public static Date getNextWeekEndDay() {
+        return DateUtil.endOfWeek(DateUtil.nextWeek());
+    }
+
+    /**
+     * 过去七天开始时间(不含今天)
+     *
+     * @return
+     */
+    public static Date getLast7DaysStartTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(new Date());
+        calendar.add(Calendar.DATE, -7);
+        return DateUtil.beginOfDay(calendar.getTime());
+    }
+
+    /**
+     * 过去七天结束时间(不含今天)
+     *
+     * @return
+     */
+    public static Date getLast7DaysEndTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(getLast7DaysStartTime());
+        calendar.add(Calendar.DATE, 6);
+        return DateUtil.endOfDay(calendar.getTime());
+    }
+
+    /**
+     * 昨天开始时间
+     *
+     * @return
+     */
+    public static Date getYesterdayStartTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(new Date());
+        calendar.add(Calendar.DATE, -1);
+        return DateUtil.beginOfDay(calendar.getTime());
+    }
+
+    /**
+     * 昨天结束时间
+     *
+     * @return
+     */
+    public static Date getYesterdayEndTime() {
+        return DateUtil.endOfDay(getYesterdayStartTime());
+    }
+
+    /**
+     * 明天开始时间
+     *
+     * @return
+     */
+    public static Date getTomorrowStartTime() {
+        return DateUtil.beginOfDay(DateUtil.tomorrow());
+    }
+
+    /**
+     * 明天结束时间
+     *
+     * @return
+     */
+    public static Date getTomorrowEndTime() {
+        return DateUtil.endOfDay(DateUtil.tomorrow());
+    }
+
+    /**
+     * 今天开始时间
+     *
+     * @return
+     */
+    public static Date getTodayStartTime() {
+        return DateUtil.beginOfDay(new Date());
+    }
+
+    /**
+     * 今天结束时间
+     *
+     * @return
+     */
+    public static Date getTodayEndTime() {
+        return DateUtil.endOfDay(new Date());
+    }
+
+}

+ 54 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateUtils.java

@@ -8,6 +8,11 @@ import java.sql.Timestamp;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.temporal.ChronoUnit;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
@@ -116,6 +121,17 @@ public class DateUtils extends PropertyEditorSupport {
     public static Date getDate() {
         return new Date();
     }
+    
+    
+    /**
+     * 当前日期
+     *
+     * @return 系统当前日期(不带时分秒)
+     */
+    public static LocalDate getLocalDate() {
+        LocalDate today = LocalDate.now();
+        return today;
+    }
 
     /**
      * 指定毫秒数表示的日期
@@ -704,6 +720,44 @@ public class DateUtils extends PropertyEditorSupport {
         return isSameMonth && calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH);
     }
 
+    /**
+     * 计算与当前日期的时间差
+     *
+     * @param targetDate
+     * @return
+     */
+    public static long calculateTimeDifference(Date targetDate) {
+        // 获取当前时间
+        LocalDateTime currentTime = LocalDateTime.now();
+
+        // 将java.util.Date转换为java.time.LocalDateTime
+        LocalDateTime convertedTargetDate = targetDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+
+        // 计算时间差
+        Duration duration = Duration.between(currentTime, convertedTargetDate);
+
+        // 获取时间差的毫秒数
+        long timeDifferenceInMillis = duration.toMillis();
+
+        return timeDifferenceInMillis;
+    }
+
+    /**
+     * 计算与当前日期的日期天数差
+     *
+     * @param targetDate
+     * @return
+     */
+    public static long calculateDaysDifference(Date targetDate) {
+        // 获取当前日期
+        LocalDate currentDate = LocalDate.now();
+        // 将java.util.Date转换为java.time.LocalDate
+        LocalDate convertedTargetDate = targetDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+        // 计算日期差
+        long daysDifference = ChronoUnit.DAYS.between(currentDate, convertedTargetDate);
+        return daysDifference;
+    }
+
     /**
      * 判断两个时间是否是同一周
      *

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

@@ -0,0 +1,96 @@
+package org.jeecg.common.util;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 防止刷短信接口(只针对绑定手机号模板:SMS_175430166)
+ * 
+ * 1、同一IP,1分钟内发短信不允许超过5次(每一分钟重置每个IP请求次数)
+ * 2、同一IP,1分钟内发短信超过20次,进入黑名单,不让使用短信接口
+ * 
+ * 3、短信接口加签和时间戳
+ *  涉及接口:
+ *  /sys/sms
+ *  /desform/api/sendVerifyCode
+ *  /sys/sendChangePwdSms
+ */
+@Slf4j
+public class DySmsLimit {
+
+    // 1分钟内最大发短信数量(单一IP)
+    private static final int MAX_MESSAGE_PER_MINUTE = 5;
+    // 1分钟
+    private static final int MILLIS_PER_MINUTE = 60000;
+    // 一分钟内报警线最大短信数量,超了进黑名单(单一IP)
+    private static final int MAX_TOTAL_MESSAGE_PER_MINUTE = 20;
+
+    private static ConcurrentHashMap<String, Long> ipLastRequestTime = new ConcurrentHashMap<>();
+    private static ConcurrentHashMap<String, Integer> ipRequestCount = new ConcurrentHashMap<>();
+    private static ConcurrentHashMap<String, Boolean> ipBlacklist = new ConcurrentHashMap<>();
+
+    /**
+     * @param ip 请求发短信的IP地址
+     * @return
+     */
+    public static boolean canSendSms(String ip) {
+        long currentTime = System.currentTimeMillis();
+        long lastRequestTime = ipLastRequestTime.getOrDefault(ip, 0L);
+        int requestCount = ipRequestCount.getOrDefault(ip, 0);
+        log.info("IP:{}, Msg requestCount:{} ", ip, requestCount);
+
+        if (ipBlacklist.getOrDefault(ip, false)) {
+            // 如果IP在黑名单中,则禁止发送短信
+            log.error("IP:{}, 进入黑名单,禁止发送请求短信!", ip);
+            return false;
+        }
+
+        if (currentTime - lastRequestTime >= MILLIS_PER_MINUTE) {
+            // 如果距离上次请求已经超过一分钟,则重置计数
+            ipRequestCount.put(ip, 1);
+            ipLastRequestTime.put(ip, currentTime);
+            return true;
+        } else {
+            // 如果距离上次请求不到一分钟
+            ipRequestCount.put(ip, requestCount + 1);
+            if (requestCount < MAX_MESSAGE_PER_MINUTE) {
+                // 如果请求次数小于5次,允许发送短信
+                return true;
+            } else if (requestCount >= MAX_TOTAL_MESSAGE_PER_MINUTE) {
+                // 如果请求次数超过报警线短信数量,将IP加入黑名单
+                ipBlacklist.put(ip, true);
+                return false;
+            } else {
+                log.error("IP:{}, 1分钟内请求短信超过5次,请稍后重试!", ip);
+                return false;
+            }
+        }
+    }
+
+    /**
+     * 图片二维码验证成功之后清空数量
+     * 
+     * @param ip IP地址
+     */
+    public static void clearSendSmsCount(String ip) {
+        long currentTime = System.currentTimeMillis();
+        ipRequestCount.put(ip, 0);
+        ipLastRequestTime.put(ip, currentTime);
+    }
+    
+//    public static void main(String[] args) {
+//        String ip = "192.168.1.1";
+//        for (int i = 1; i < 50; i++) {
+//            if (canSendSms(ip)) {
+//                System.out.println("Send SMS successfully");
+//            } else {
+//                //System.out.println("Exceed SMS limit for IP " + ip);
+//            }
+//        }
+//
+//        System.out.println(ipLastRequestTime);
+//        System.out.println(ipRequestCount);
+//        System.out.println(ipBlacklist);
+//    }
+}

+ 50 - 8
jeecg-boot-base-core/src/main/java/org/jeecg/common/util/IpUtils.java

@@ -7,6 +7,11 @@ import org.jeecg.common.constant.CommonConstant;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 /**
  * IP地址
  * 
@@ -45,15 +50,52 @@ public class IpUtils {
         } catch (Exception e) {
         	logger.error("IPUtils ERROR ", e);
         }
-        
-//        //使用代理,则获取第一个IP地址
-//        if(StringUtils.isEmpty(ip) && ip.length() > 15) {
-//			if(ip.indexOf(",") > 0) {
-//				ip = ip.substring(0, ip.indexOf(","));
-//			}
-//		}
+
+        //logger.info("获取客户端 ip:{} ", ip);
+        // 使用代理,则获取第一个IP地址
+        if (StringUtils.isNotEmpty(ip) && ip.length() > 15) {
+            if (ip.indexOf(",") > 0) {
+                //ip = ip.substring(0, ip.indexOf(","));
+                String[] ipAddresses = ip.split(",");
+                for (String ipAddress : ipAddresses) {
+                    ipAddress = ipAddress.trim();
+                    if (isValidIpAddress(ipAddress)) {
+                        return ipAddress;
+                    }
+                }
+            }
+        }
         
         return ip;
     }
-	
+
+
+    /**
+     * 判断是否是IP格式
+     * @param ipAddress
+     * @return
+     */
+    public static boolean isValidIpAddress(String ipAddress) {
+        String ipPattern = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
+        Pattern pattern = Pattern.compile(ipPattern);
+        Matcher matcher = pattern.matcher(ipAddress);
+        return matcher.matches();
+    }
+    
+    /**
+     * 获取服务器上的ip
+     * @return
+     */
+    public static String getServerIp(){
+        InetAddress inetAddress = null;
+        try {
+            inetAddress = InetAddress.getLocalHost();
+            String ipAddress = inetAddress.getHostAddress();
+            //System.out.println("IP地址: " + ipAddress);
+            return ipAddress;
+        } catch (UnknownHostException e) {
+            logger.error("获取ip地址失败", e);
+        }
+        return "";
+    }
 }

+ 12 - 4
jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java

@@ -75,7 +75,7 @@ public class SqlInjectionUtil {
 	 * sql注入过滤处理,遇到注入关键字抛异常
 	 * @param values
 	 */
-	public static void filterContent(String... values) {
+	public static void filterContentMulti(String... values) {
 		filterContent(values, null);
 	}
 
@@ -291,7 +291,15 @@ public class SqlInjectionUtil {
 		if(oConvertUtils.isEmpty(table)){
 			return table;
 		}
-		
+
+		//update-begin---author:scott ---date:2024-05-28  for:表单设计器列表翻译存在表名带条件,导致翻译出问题----
+		int index = table.toLowerCase().indexOf(" where ");
+		if (index != -1) {
+			table = table.substring(0, index);
+			log.info("截掉where之后的新表名:" + table);
+		}
+		//update-end---author:scott ---date::2024-05-28  for:表单设计器列表翻译存在表名带条件,导致翻译出问题----
+
 		table = table.trim();
 		/**
 		 * 检验表名是否合法
@@ -308,7 +316,7 @@ public class SqlInjectionUtil {
 		}
 
 		//进一步验证是否存在SQL注入风险
-		filterContent(table);
+		filterContentMulti(table);
 		return table;
 	}
 
@@ -345,7 +353,7 @@ public class SqlInjectionUtil {
 		}
 
 		//进一步验证是否存在SQL注入风险
-		filterContent(field);
+		filterContentMulti(field);
 		return field;
 	}
 

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

@@ -28,6 +28,10 @@ public class TokenUtils {
      * @return
      */
     public static String getTokenByRequest(HttpServletRequest request) {
+        if (request == null) {
+            return null;
+        }
+        
         String token = request.getParameter("token");
         if (token == null) {
             token = request.getHeader("X-Access-Token");

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

@@ -38,6 +38,11 @@ public class DynamicDBUtil {
 
         String driverClassName = dbSource.getDbDriver();
         String url = dbSource.getDbUrl();
+        // url配置成 “123” 会触发Druid死循环,一直去重复尝试连接
+        if (oConvertUtils.isEmpty(url) || !url.toLowerCase().startsWith("jdbc:")) {
+            throw new JeecgBootException("数据源URL配置格式不正确!");
+        }
+        
         String dbUser = dbSource.getDbUsername();
         String dbPassword = dbSource.getDbPassword();
         dataSource.setDriverClassName(driverClassName);
@@ -47,6 +52,8 @@ public class DynamicDBUtil {
         dataSource.setTestOnBorrow(false);
         dataSource.setTestOnReturn(false);
         dataSource.setBreakAfterAcquireFailure(true);
+        //设置超时时间60秒
+        dataSource.setLoginTimeout(60);
         dataSource.setConnectionErrorRetryAttempts(0);
         dataSource.setUsername(dbUser);
         dataSource.setMaxWait(30000);

+ 91 - 4
jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java

@@ -2,7 +2,9 @@ package org.jeecg.common.util;
 
 import com.alibaba.fastjson.JSONArray;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.SymbolConstant;
 import org.springframework.beans.BeanUtils;
@@ -14,10 +16,7 @@ import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.net.UnknownHostException;
+import java.net.*;
 import java.sql.Date;
 import java.util.*;
 import java.util.regex.Matcher;
@@ -50,6 +49,27 @@ public class oConvertUtils {
 		return (false);
 	}
 
+	
+	/**
+	 * 返回decode解密字符串
+	 * 
+	 * @param inStr
+	 * @return
+	 */
+	public static String decodeString(String inStr) {
+		if (oConvertUtils.isEmpty(inStr)) {
+			return null;
+		}
+
+		try {
+			inStr = URLDecoder.decode(inStr, "UTF-8");
+		} catch (Exception e) {
+			// 解决:URLDecoder: Illegal hex characters in escape (%) pattern - For input string: "自动"
+			//e.printStackTrace();
+		}
+		return inStr;
+	}
+
 	public static String decode(String strIn, String sourceCode, String targetCode) {
 		String temp = code2code(strIn, sourceCode, targetCode);
 		return temp;
@@ -238,6 +258,20 @@ public class oConvertUtils {
 		return (String.valueOf(i));
 	}
 
+	/**
+	 * 返回常规字符串(只保留字符串中的数字、字母、中文)
+	 *
+	 * @param input
+	 * @return
+	 */
+	public static String getNormalString(String input) {
+		if (oConvertUtils.isEmpty(input)) {
+			return null;
+		}
+		String result = input.replaceAll("[^0-9a-zA-Z\\u4e00-\\u9fa5]", "");
+		return result;
+	}
+
 	public static String getString(String s, String defval) {
 		if (isEmpty(s)) {
 			return (defval);
@@ -287,6 +321,22 @@ public class oConvertUtils {
 		return (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class) || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class) || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class) || clazz.isPrimitive());
 	}
 
+	/**
+	 * 解码base64
+	 *
+	 * @param base64Str base64字符串
+	 * @return 被加密后的字符串
+	 */
+	public static String decodeBase64Str(String base64Str) {
+		byte[] byteContent = Base64.decodeBase64(base64Str);
+		if (byteContent == null) {
+			return null;
+		}
+		String decodedString = new String(byteContent);
+		return decodedString;
+	}
+	
+	
 	/**
 	 * @param request
 	 *            IP
@@ -750,6 +800,16 @@ public class oConvertUtils {
 		}
 		return obj.getClass().isArray();
 	}
+
+	/**
+	 * 获取集合的大小
+	 * 
+	 * @param collection
+	 * @return
+	 */
+	public static int getCollectionSize(Collection<?> collection) {
+		return collection != null ? collection.size() : 0;
+	}
 	
 	/**
 	 * 判断两个数组是否相等(数组元素不分顺序)
@@ -941,5 +1001,32 @@ public class oConvertUtils {
 		}
 		return count;
 	}
+
+	/**
+	 * map转str
+	 *
+	 * @param map
+	 * @return
+	 */
+	public static String mapToString(Map<String, String[]> map) {
+		if (map == null || map.size() == 0) {
+			return null;
+		}
+
+		StringBuilder sb = new StringBuilder();
+		for (Map.Entry<String, String[]> entry : map.entrySet()) {
+			String key = entry.getKey();
+			String[] values = entry.getValue();
+			sb.append(key).append("=");
+			sb.append(values != null ? StringUtils.join(values, ",") : "");
+			sb.append("&");
+		}
+
+		String result = sb.toString();
+		if (result.endsWith("&")) {
+			result = result.substring(0, sb.length() - 1);
+		}
+		return result;
+	}
 	
 }

+ 16 - 16
jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/ConstAnalyzer.java

@@ -166,22 +166,22 @@ public class ConstAnalyzer implements ExpressionVisitor, ItemsListVisitor {
         expr.getBetweenExpressionEnd().accept(this);
     }
 
-//    /**
-//     * 用于处理 OverlapsCondition 类型的表达式
-//     * @param overlapsCondition
-//     */
-//    @Override
-//    public void visit(OverlapsCondition overlapsCondition) {
-//        constFlag.set(false);
-//    }
-//    /**
-//     * 用于处理 SafeCastExpression 类型的表达式。
-//     * @param safeCastExpression
-//     */
-//    @Override
-//    public void visit(SafeCastExpression safeCastExpression) {
-//        constFlag.set(false);
-//    }
+    /**
+     * 用于处理 OverlapsCondition 类型的表达式
+     * @param overlapsCondition
+     */
+    @Override
+    public void visit(OverlapsCondition overlapsCondition) {
+        constFlag.set(false);
+    }
+    /**
+     * 用于处理 SafeCastExpression 类型的表达式。
+     * @param safeCastExpression
+     */
+    @Override
+    public void visit(SafeCastExpression safeCastExpression) {
+        constFlag.set(false);
+    }
 
     @Override
     public void visit(EqualsTo expr) {

+ 1 - 1
jeecg-boot-base-core/src/main/java/org/jeecg/config/DruidWallConfigRegister.java

@@ -14,7 +14,7 @@ import java.util.Map;
 /**
  * 启动程序修改DruidWallConfig配置
  * 允许SELECT语句的WHERE子句是一个永真条件
- * @author eightmonth@qq.com
+ * @author eightmonth
  * @date 2024/4/8 11:37
  */
 public class DruidWallConfigRegister implements SpringApplicationRunListener {

+ 10 - 8
jeecg-boot-base-core/src/main/java/org/jeecg/config/WebMvcConfiguration.java

@@ -128,14 +128,16 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
         return objectMapper;
     }
 
-    /**
-     * SpringBootAdmin的Httptrace不见了
-     * https://blog.csdn.net/u013810234/article/details/110097201
-     */
-    @Bean
-    public InMemoryHttpTraceRepository getInMemoryHttpTrace(){
-        return new InMemoryHttpTraceRepository();
-    }
+    //update-begin---author:chenrui ---date:20240514  for:[QQYUN-9247]系统监控功能优化------------
+//    /**
+//     * SpringBootAdmin的Httptrace不见了
+//     * https://blog.csdn.net/u013810234/article/details/110097201
+//     */
+//    @Bean
+//    public InMemoryHttpTraceRepository getInMemoryHttpTrace(){
+//        return new InMemoryHttpTraceRepository();
+//    }
+    //update-end---author:chenrui ---date:20240514  for:[QQYUN-9247]系统监控功能优化------------
 
 
     /**

+ 1 - 1
jeecg-boot-base-core/src/main/java/org/jeecg/config/firewall/interceptor/LowCodeModeInterceptor.java

@@ -71,7 +71,7 @@ public class LowCodeModeInterceptor implements HandlerInterceptor {
             if (loginUser == null) {
                 loginUser = commonAPI.getUserByName(JwtUtil.getUserNameByToken(SpringContextUtils.getHttpServletRequest()));
                 //当前登录人拥有的角色
-                hasRoles = commonAPI.queryUserRoles(loginUser.getUsername());
+                hasRoles = commonAPI.queryUserRolesById(loginUser.getId());
             }
             
             log.info("get loginUser info: {}", loginUser);

+ 13 - 1
jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisInterceptor.java

@@ -10,6 +10,8 @@ import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.config.TenantContext;
 import org.jeecg.common.constant.TenantConstant;
 import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.common.util.TokenUtils;
 import org.jeecg.common.util.oConvertUtils;
 import org.springframework.stereotype.Component;
 
@@ -94,7 +96,17 @@ public class MybatisInterceptor implements Interceptor {
 							field.setAccessible(false);
 							if (localTenantId == null) {
 								field.setAccessible(true);
-								field.set(parameter, oConvertUtils.getInt(TenantContext.getTenant(),0));
+
+								String tenantId = TenantContext.getTenant();
+								//如果通过线程获取租户ID为空,则通过当前请求的request获取租户(shiro排除拦截器的请求会获取不到租户ID)
+								if(oConvertUtils.isEmpty(tenantId) && MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
+									try {
+										tenantId = TokenUtils.getTenantIdByRequest(SpringContextUtils.getHttpServletRequest());
+									} catch (Exception e) {
+										//e.printStackTrace();
+									}
+								}
+								field.set(parameter, tenantId);
 								field.setAccessible(false);
 							}
 						}

+ 1 - 1
jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java

@@ -30,7 +30,7 @@ import net.sf.jsqlparser.expression.LongValue;
  *
  */
 @Configuration
-@MapperScan(value={"org.jeecg.modules.**.mapper*"})
+@MapperScan(value={"org.jeecg.**.mapper*"})
 public class MybatisPlusSaasConfig {
 
     /**

+ 4 - 2
jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/IgnoreAuth.java

@@ -6,8 +6,10 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * 免认证注解,认证系统结合spring MVC的@RequestMapping获取请求路径进行免登录配置
- * @author eightmonth@qq.com
+ * 免Token认证注解
+ * 
+ * 认证系统结合spring MVC的@RequestMapping获取请求路径进行免登录配置
+ * @author eightmonth
  * @date 2024/2/28 9:58
  */
 @Target(ElementType.METHOD)

+ 20 - 2
jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java

@@ -19,15 +19,14 @@ import org.jeecg.config.shiro.filters.JwtFilter;
 import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
 import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.*;
 import org.springframework.core.annotation.AnnotationUtils;
 import org.springframework.core.env.Environment;
 import org.springframework.core.type.filter.AnnotationTypeFilter;
 import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
 import org.springframework.util.CollectionUtils;
-import org.springframework.util.StopWatch;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.filter.DelegatingFilterProxy;
@@ -58,6 +57,7 @@ public class ShiroConfig {
     private JeecgBaseConfig jeecgBaseConfig;
     @Autowired(required = false)
     private RedisProperties redisProperties;
+    
     /**
      * Filter Chain定义说明
      *
@@ -87,6 +87,7 @@ public class ShiroConfig {
         filterChainDefinitionMap.put("/sys/cas/client/validateLogin", "anon"); //cas验证登录
         filterChainDefinitionMap.put("/sys/randomImage/**", "anon"); //登录验证码接口排除
         filterChainDefinitionMap.put("/sys/checkCaptcha", "anon"); //登录验证码接口排除
+        filterChainDefinitionMap.put("/sys/smsCheckCaptcha", "anon"); //短信次数发送太多验证码排除
         filterChainDefinitionMap.put("/sys/login", "anon"); //登录接口排除
         filterChainDefinitionMap.put("/sys/mLogin", "anon"); //登录接口排除
         filterChainDefinitionMap.put("/sys/logout", "anon"); //登出接口排除
@@ -270,6 +271,9 @@ public class ShiroConfig {
     }
 
     /**
+     * RedisConfig在项目starter项目中
+     * jeecg-boot-starter-github\jeecg-boot-common\src\main\java\org\jeecg\common\modules\redis\config\RedisConfig.java
+     * 
      * 配置shiro redisManager
      * 使用的是shiro-redis开源插件
      *
@@ -324,4 +328,18 @@ public class ShiroConfig {
         return manager;
     }
 
+    private List<String> rebuildUrl(String[] bases, String[] uris) {
+        List<String> urls = new ArrayList<>();
+        for (String base : bases) {
+            for (String uri : uris) {
+                urls.add(prefix(base)+prefix(uri));
+            }
+        }
+        return urls;
+    }
+
+    private String prefix(String seg) {
+        return seg.startsWith("/") ? seg : "/"+seg;
+    }
+
 }

+ 1 - 1
jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java

@@ -71,7 +71,7 @@ public class ShiroRealm extends AuthorizingRealm {
         SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
 
         // 设置用户拥有的角色集合,比如“admin,test”
-        Set<String> roleSet = commonApi.queryUserRoles(username);
+        Set<String> roleSet = commonApi.queryUserRolesById(userId);
         //System.out.println(roleSet.toString());
         info.setRoles(roleSet);
 

+ 1 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java

@@ -52,6 +52,7 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
             if (InMemoryIgnoreAuth.contains(((HttpServletRequest) request).getServletPath())) {
                 return true;
             }
+            
             executeLogin(request, response);
             return true;
         } catch (Exception e) {

+ 11 - 2
jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ignore/IgnoreAuthPostProcessor.java

@@ -1,6 +1,7 @@
 package org.jeecg.config.shiro.ignore;
 
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.jeecg.config.shiro.IgnoreAuth;
 import org.springframework.aop.framework.Advised;
 import org.springframework.context.ApplicationContext;
@@ -8,7 +9,6 @@ import org.springframework.context.ApplicationListener;
 import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
-import org.springframework.util.StopWatch;
 import org.springframework.web.bind.annotation.*;
 
 import java.lang.reflect.Method;
@@ -16,9 +16,10 @@ import java.util.*;
 
 /**
  * 在spring boot初始化时,根据@RestController注解获取当前spring容器中的bean
- * @author eightmonth@qq.com
+ * @author eightmonth
  * @date 2024/4/18 11:35
  */
+@Slf4j
 @Component
 @AllArgsConstructor
 public class IgnoreAuthPostProcessor implements ApplicationListener<ContextRefreshedEvent> {
@@ -27,6 +28,8 @@ public class IgnoreAuthPostProcessor implements ApplicationListener<ContextRefre
 
     @Override
     public void onApplicationEvent(ContextRefreshedEvent event) {
+        long startTime = System.currentTimeMillis();
+        
         List<String> ignoreAuthUrls = new ArrayList<>();
         if (event.getApplicationContext().getParent() == null) {
             // 只处理根应用上下文的事件,避免在子上下文中重复处理
@@ -39,9 +42,15 @@ public class IgnoreAuthPostProcessor implements ApplicationListener<ContextRefre
             }
         }
 
+        log.info("Init Token ignoreAuthUrls Config [ 集合 ]  :{}", ignoreAuthUrls);
         if (!CollectionUtils.isEmpty(ignoreAuthUrls)) {
             InMemoryIgnoreAuth.set(ignoreAuthUrls);
         }
+
+        // 计算方法的耗时
+        long endTime = System.currentTimeMillis();
+        long elapsedTime = endTime - startTime;
+        log.info("Init Token ignoreAuthUrls Config [ 耗时 ] :" + elapsedTime + "毫秒");
     }
 
     private List<String> postProcessRestController(Object restController) {

+ 1 - 1
jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ignore/InMemoryIgnoreAuth.java

@@ -6,7 +6,7 @@ import java.util.List;
 /**
  * 使用内存存储通过@IgnoreAuth注解的url,配合JwtFilter进行免登录校验
  * PS:无法使用ThreadLocal进行存储,因为ThreadLocal装载时,JwtFilter已经初始化完毕,导致该类获取ThreadLocal为空
- * @author eightmonth@qq.com
+ * @author eightmonth
  * @date 2024/4/18 15:02
  */
 public class InMemoryIgnoreAuth {

+ 4 - 2
jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/HttpUtils.java

@@ -59,7 +59,8 @@ public class HttpUtils {
         // 获取URL上的参数
         Map<String, String> urlParams = getUrlParams(request);
         for (Map.Entry entry : urlParams.entrySet()) {
-            result.put((String)entry.getKey(), (String)entry.getValue());
+            //不能直接转成String,否则会有类型转换错误
+            result.put((String)entry.getKey(), String.valueOf(entry.getValue()));
         }
         Map<String, String> allRequestParam = new HashMap<>(16);
         // get请求不需要拿body参数
@@ -69,7 +70,8 @@ public class HttpUtils {
         // 将URL的参数和body参数进行合并
         if (allRequestParam != null) {
             for (Map.Entry entry : allRequestParam.entrySet()) {
-                result.put((String)entry.getKey(), (String)entry.getValue());
+                //不能直接转成String,否则会有类型转换错误
+                result.put((String)entry.getKey(), String.valueOf(entry.getValue()));
             }
         }
         return result;

+ 3 - 2
jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/xml/BaseCommonMapper.xml

@@ -4,7 +4,7 @@
 
     <!-- 保存日志11 -->
     <insert id="saveLog" parameterType="Object">
-        insert into sys_log (id, log_type, log_content, method, operate_type, request_url, request_type, request_param, ip, userid, username, cost_time, create_time,create_by, tenant_id)
+        insert into sys_log (id, log_type, log_content, method, operate_type, request_url, request_type, request_param, ip, userid, username, cost_time, create_time,create_by, tenant_id, client_type)
         values(
             #{dto.id,jdbcType=VARCHAR},
             #{dto.logType,jdbcType=INTEGER},
@@ -20,7 +20,8 @@
             #{dto.costTime,jdbcType=BIGINT},
             #{dto.createTime,jdbcType=TIMESTAMP},
             #{dto.createBy,jdbcType=VARCHAR},
-            #{dto.tenantId,jdbcType=INTEGER}
+            #{dto.tenantId,jdbcType=INTEGER},
+            #{dto.clientType,jdbcType=VARCHAR}
         )
     </insert>
 

+ 14 - 1
jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/service/impl/BaseCommonServiceImpl.java

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.dto.LogDTO;
+import org.jeecg.common.constant.enums.ClientTerminalTypeEnum;
+import org.jeecg.common.util.BrowserUtils;
 import org.jeecg.modules.base.mapper.BaseCommonMapper;
 import org.jeecg.modules.base.service.BaseCommonService;
 import org.jeecg.common.system.vo.LoginUser;
@@ -33,7 +35,7 @@ public class BaseCommonServiceImpl implements BaseCommonService {
             logDTO.setId(String.valueOf(IdWorker.getId()));
         }
         //保存日志(异常捕获处理,防止数据太大存储失败,导致业务失败)JT-238
-        try {
+        try {   
             logDTO.setCreateTime(new Date());
             baseCommonMapper.saveLog(logDTO);
         } catch (Exception e) {
@@ -55,6 +57,17 @@ public class BaseCommonServiceImpl implements BaseCommonService {
             HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
             //设置IP地址
             sysLog.setIp(IpUtils.getIpAddr(request));
+
+            try {
+                //设置客户端
+                if(BrowserUtils.isDesktop(request)){
+                    sysLog.setClientType(ClientTerminalTypeEnum.PC.getKey());
+                }else{
+                    sysLog.setClientType(ClientTerminalTypeEnum.APP.getKey());
+                }
+            } catch (Exception e) {
+                //e.printStackTrace();
+            }
         } catch (Exception e) {
             sysLog.setIp("127.0.0.1");
         }

+ 41 - 0
jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlparse/TestIpUtil.java

@@ -0,0 +1,41 @@
+package org.jeecg.test.sqlparse;
+
+import net.sf.jsqlparser.JSQLParserException;
+import org.jeecg.common.util.IpUtils;
+import org.jeecg.common.util.oConvertUtils;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author: scott
+ * @date: 2024年04月29日 16:48
+ */
+public class TestIpUtil {
+    public static void main(String[] args) {
+        Map<String, String[]> map = new HashMap<>();
+        map.put("key1", new String[]{"value1", "value2", "value3"});
+        map.put("key4", null);
+        map.put("key2", new String[]{"value4", "value5"});
+        map.put("key3", new String[]{"value6"});
+        System.out.println(oConvertUtils.mapToString(map));
+    }
+
+    @Test
+    public void test() {
+        String ip = "2408:8207:1851:10e0:50bd:1a50:60c8:b030, 115.231.101.180";
+        String[] ipAddresses = ip.split(",");
+        for (String ipAddress : ipAddresses) {
+            System.out.println(ipAddress);
+            ipAddress = ipAddress.trim();
+            if (IpUtils.isValidIpAddress(ipAddress)) {
+                System.out.println("ipAddress= " + ipAddress);
+            }
+        }
+    }
+}

+ 1 - 1
jeecg-module-demo/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-parent</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.6.3</version>
+        <version>3.7.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/controller/ChatController.java

@@ -16,7 +16,7 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
  * @Date: 2024/1/9 16:30
  */
 @Controller
-@RequestMapping("/ai/chat")
+@RequestMapping("/test/ai/chat")
 public class ChatController {
 
     @Autowired

+ 2 - 0
jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java

@@ -23,6 +23,7 @@ import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.util.DateUtils;
 import org.jeecg.common.util.RedisUtil;
 import org.jeecg.common.util.UUIDGenerator;
+import org.jeecg.config.shiro.IgnoreAuth;
 import org.jeecg.modules.demo.test.entity.JeecgDemo;
 import org.jeecg.modules.demo.test.service.IJeecgDemoService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -232,6 +233,7 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
      * @param modelAndView
      * @return
      */
+    @IgnoreAuth
     @RequestMapping("/html")
     public ModelAndView ftl(ModelAndView modelAndView) {
         modelAndView.setViewName("demo3");

+ 1 - 1
jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-system-api</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.6.3</version>
+        <version>3.7.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 43 - 1
jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java

@@ -85,6 +85,14 @@ public interface ISysBaseAPI extends CommonAPI {
      */
     @GetMapping("/sys/api/getRolesByUsername")
     List<String> getRolesByUsername(@RequestParam("username") String username);
+    
+    /**
+     * 7通过用户账号查询角色集合
+     * @param userId
+     * @return
+     */
+    @GetMapping("/sys/api/getRolesByUserId")
+    List<String> getRolesByUserId(@RequestParam("userId") String userId);
 
     /**
      * 8通过用户账号查询部门集合
@@ -93,6 +101,14 @@ public interface ISysBaseAPI extends CommonAPI {
      */
     @GetMapping("/sys/api/getDepartIdsByUsername")
     List<String> getDepartIdsByUsername(@RequestParam("username") String username);
+    
+    /**
+     * 8通过用户账号查询部门集合
+     * @param userId
+     * @return 部门 id
+     */
+    @GetMapping("/sys/api/getDepartIdsByUserId")
+    List<String> getDepartIdsByUserId(@RequestParam("userId") String userId);
 
     /**
      * 8.2 通过用户账号查询部门父ID集合
@@ -304,6 +320,14 @@ public interface ISysBaseAPI extends CommonAPI {
      */
     @GetMapping("/sys/api/getUserRoleSet")
     Set<String> getUserRoleSet(@RequestParam("username")String username);
+    
+    /**
+     * 30获取用户的角色集合
+     * @param userId
+     * @return
+     */
+    @GetMapping("/sys/api/getUserRoleSetById")
+    Set<String> getUserRoleSetById(@RequestParam("userId")String userId);
 
     /**
      * 31获取用户的权限集合
@@ -348,6 +372,15 @@ public interface ISysBaseAPI extends CommonAPI {
     @Override
     @GetMapping("/sys/api/queryUserRoles")
     Set<String> queryUserRoles(@RequestParam("username")String username);
+    
+    /**
+     * 35查询用户角色信息
+     * @param userId
+     * @return
+     */
+    @Override
+    @GetMapping("/sys/api/queryUserRolesById")
+    Set<String> queryUserRolesById(@RequestParam("userId")String userId);
 
     /**
      * 36查询用户权限信息
@@ -387,6 +420,15 @@ public interface ISysBaseAPI extends CommonAPI {
     @SensitiveDecode
     @GetMapping("/sys/api/getUserByName")
     LoginUser getUserByName(@RequestParam("username") String username);
+    
+    /**
+     * 39根据用户账号查询用户ID CommonAPI中定义
+     * @param username
+     * @return 用户ID
+     */
+    @Override
+    @GetMapping("/sys/api/getUserIdByName")
+    String getUserIdByName(@RequestParam("username") String username);
 
     /**
      * 40字典表的 翻译
@@ -609,7 +651,7 @@ public interface ISysBaseAPI extends CommonAPI {
      * @param dataLogDto
      */
     @PostMapping("/sys/api/saveDataLog")
-    void saveDataLog(DataLogDTO dataLogDto);
+    void saveDataLog(@RequestBody DataLogDTO dataLogDto);
 
     /**
      * 更新头像

+ 25 - 0
jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java

@@ -60,11 +60,21 @@ public class SysBaseAPIFallback implements ISysBaseAPI {
         return null;
     }
 
+    @Override
+    public List<String> getRolesByUserId(String userId) {
+        return null;
+    }
+
     @Override
     public List<String> getDepartIdsByUsername(String username) {
         return null;
     }
 
+    @Override
+    public List<String> getDepartIdsByUserId(String userId) {
+        return null;
+    }
+
     @Override
     public Set<String> getDepartParentIdsByUsername(String username) {
         return null;
@@ -193,6 +203,11 @@ public class SysBaseAPIFallback implements ISysBaseAPI {
         return null;
     }
 
+    @Override
+    public Set<String> getUserRoleSetById(String userId) {
+        return null;
+    }
+
     @Override
     public Set<String> getUserPermissionSet(String userId) {
         return null;
@@ -218,6 +233,11 @@ public class SysBaseAPIFallback implements ISysBaseAPI {
         return null;
     }
 
+    @Override
+    public Set<String> queryUserRolesById(String userId) {
+        return null;
+    }
+
     @Override
     public Set<String> queryUserAuths(String userId) {
         return null;
@@ -239,6 +259,11 @@ public class SysBaseAPIFallback implements ISysBaseAPI {
         return null;
     }
 
+    @Override
+    public String getUserIdByName(String username) {
+        return null;
+    }
+
     @Override
     public String translateDictFromTable(String table, String text, String code, String key) {
         return null;

+ 1 - 1
jeecg-module-system/jeecg-system-api/jeecg-system-local-api/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-system-api</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.6.3</version>
+        <version>3.7.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 20 - 1
jeecg-module-system/jeecg-system-api/jeecg-system-local-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java

@@ -81,6 +81,13 @@ public interface ISysBaseAPI extends CommonAPI {
      * @return
      */
     List<String> getRolesByUsername(String username);
+    
+    /**
+     * 7通过用户账号查询角色集合
+     * @param userId
+     * @return
+     */
+    List<String> getRolesByUserId(String userId);
 
     /**
      * 8通过用户账号查询部门集合
@@ -88,6 +95,12 @@ public interface ISysBaseAPI extends CommonAPI {
      * @return 部门 id
      */
     List<String> getDepartIdsByUsername(String username);
+    /**
+     * 8通过用户账号查询部门集合
+     * @param userId
+     * @return 部门 id
+     */
+    List<String> getDepartIdsByUserId(String userId);
 
     /**
      * 8.2 通过用户账号查询部门父ID集合
@@ -299,7 +312,13 @@ public interface ISysBaseAPI extends CommonAPI {
      * @return
      */
     Set<String> getUserRoleSet(String username);
-
+    /**
+     * 31获取用户的角色集合
+     * @param useId
+     * @return
+     */
+    Set<String> getUserRoleSetById(String useId);
+    
     /**
      * 32获取用户的权限集合
      * @param userId

+ 1 - 1
jeecg-module-system/jeecg-system-api/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-module-system</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.6.3</version>
+        <version>3.7.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 3 - 4
jeecg-module-system/jeecg-system-biz/pom.xml

@@ -4,7 +4,7 @@
 	<parent>
 		<groupId>org.jeecgframework.boot</groupId>
 		<artifactId>jeecg-module-system</artifactId>
-		<version>3.6.3</version>
+		<version>3.7.0</version>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
 
@@ -29,17 +29,16 @@
 			<groupId>org.jeecgframework</groupId>
 			<artifactId>jeewx-api</artifactId>
 		</dependency>
-		<!-- 积木报表设计 -->
+		<!-- 积木报表 -->
 		<dependency>
 			<groupId>org.jeecgframework.jimureport</groupId>
 			<artifactId>jimureport-spring-boot-starter</artifactId>
 		</dependency>
-		<!-- 积木仪表盘 -->
 		<dependency>
 			<groupId>org.jeecgframework.jimureport</groupId>
 			<artifactId>jimureport-drag</artifactId>
 		</dependency>
-		<!-- 积木报表 mongo redis 支持包 
+	<!-- 积木报表 mongo redis 支持包 
 		<dependency>
 			<groupId>org.jeecgframework.jimureport</groupId>
 			<artifactId>jimureport-nosql-starter</artifactId>

+ 4 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/init/CodeGenerateDbConfig.java

@@ -15,6 +15,10 @@ import org.springframework.context.annotation.Configuration;
  *  提醒: 达梦数据库需要修改下面的参数${spring.datasource.dynamic.datasource.master.url:}配置
  * @author: scott
  * @date: 2021年02月18日 16:30
+ * 
+ * 重要说明:此类改路径或者名称,需要同步修改
+ *  org/jeecg/interceptor/OnlineRepairCodeGenerateDbConfig.java里面的注解
+ *  @ConditionalOnMissingClass("org.jeecg.config.init.CodeGenerateDbConfig")
  */
 @Slf4j
 @Configuration

+ 5 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/jimureport/JimuReportTokenService.java

@@ -36,7 +36,11 @@ public class JimuReportTokenService implements JmReportTokenServiceI {
 
     @Override
     public String getToken(HttpServletRequest request) {
-        return TokenUtils.getTokenByRequest(request);
+        try {
+            return TokenUtils.getTokenByRequest(request);
+        } catch (Exception e) {
+            return null;
+        }
     }
 
     @Override

+ 3 - 2
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/aop/TenantPackUserLogAspect.java

@@ -8,6 +8,7 @@ import org.aspectj.lang.annotation.Aspect;
 import org.aspectj.lang.annotation.Pointcut;
 import org.aspectj.lang.reflect.MethodSignature;
 import org.jeecg.common.api.dto.LogDTO;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.modules.base.service.BaseCommonService;
 import org.jeecg.modules.system.entity.SysTenantPack;
@@ -52,7 +53,7 @@ public class TenantPackUserLogAspect {
                 for(Object obj: args){
                     if(obj instanceof SysTenantPack){
                         // logType=3 租户操作日志
-                        logType = 3;
+                        logType = CommonConstant.LOG_TYPE_3;
                         SysTenantPack pack = (SysTenantPack)obj;
                         if(opType==2){
                             content = "创建了角色权限 "+ pack.getPackName();
@@ -60,7 +61,7 @@ public class TenantPackUserLogAspect {
                         tenantId = pack.getTenantId();
                         break;
                     }else if(obj instanceof SysTenantPackUser){
-                        logType = 3;
+                        logType = CommonConstant.LOG_TYPE_3;
                         SysTenantPackUser packUser = (SysTenantPackUser)obj;
                         if(opType==2){
                             content = "将 "+packUser.getRealname()+" 添加到角色 "+ packUser.getPackName();

+ 52 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java

@@ -102,6 +102,17 @@ public class SystemApiController {
         }
         return loginUser;
     }
+    
+    /**
+     * 根据用户账号查询用户ID
+     * @param username
+     * @return
+     */
+    @GetMapping("/getUserIdByName")
+    public String getUserIdByName(@RequestParam("username") String username){
+        String userId = sysBaseApi.getUserIdByName(username);
+        return userId;
+    }
 
     /**
      * 根据用户id查询用户信息
@@ -129,6 +140,16 @@ public class SystemApiController {
     List<String> getRolesByUsername(@RequestParam("username") String username){
         return sysBaseApi.getRolesByUsername(username);
     }
+    
+    /**
+     * 通过用户账号查询角色集合
+     * @param userId
+     * @return
+     */
+    @GetMapping("/getRolesByUserId")
+    List<String> getRolesByUserId(@RequestParam("userId") String userId){
+        return sysBaseApi.getRolesByUserId(userId);
+    }
 
     /**
      * 通过用户账号查询部门集合
@@ -139,6 +160,16 @@ public class SystemApiController {
     List<String> getDepartIdsByUsername(@RequestParam("username") String username){
         return sysBaseApi.getDepartIdsByUsername(username);
     }
+    
+    /**
+     * 通过用户账号查询部门集合
+     * @param userId
+     * @return 部门 id
+     */
+    @GetMapping("/getDepartIdsByUserId")
+    List<String> getDepartIdsByUserId(@RequestParam("userId") String userId){
+        return sysBaseApi.getDepartIdsByUserId(userId);
+    }
 
     /**
      * 通过用户账号查询部门父ID集合
@@ -383,6 +414,16 @@ public class SystemApiController {
     public Set<String> getUserRoleSet(@RequestParam("username")String username){
         return sysBaseApi.getUserRoleSet(username);
     }
+    
+    /**
+     * 获取用户的角色集合
+     * @param userId
+     * @return
+     */
+    @GetMapping("/getUserRoleSetById")
+    public Set<String> getUserRoleSetById(@RequestParam("userId")String userId){
+        return sysBaseApi.getUserRoleSetById(userId);
+    }
 
     /**
      * 获取用户的权限集合
@@ -415,6 +456,16 @@ public class SystemApiController {
     public Set<String> queryUserRoles(@RequestParam("username") String username){
         return sysUserService.getUserRolesSet(username);
     }
+    
+    /**
+     * 查询用户角色信息
+     * @param userId
+     * @return
+     */
+    @GetMapping("/queryUserRolesById")
+    public Set<String> queryUserRolesById(@RequestParam("userId") String userId){
+        return sysUserService.getUserRoleSetById(userId);
+    }
 
 
     /**
@@ -893,7 +944,7 @@ public class SystemApiController {
      * @return
      */
     @GetMapping("/getUserAccountsByDepCode")
-    public List<String> getUserAccountsByDepCode(String orgCode){
+    public List<String> getUserAccountsByDepCode(@RequestParam("orgCode") String orgCode){
         return sysBaseApi.getUserAccountsByDepCode(orgCode);
     }
 

+ 1 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/controller/SysMessageTemplateController.java

@@ -173,7 +173,7 @@ public class SysMessageTemplateController extends JeecgController<SysMessageTemp
 			sysBaseApi.sendTemplateMessage(md);
 			return result.success("消息发送成功!");
 		} catch (Exception e) {
-			log.error("发送消息出错", e.getMessage());
+			log.error("发送消息出错:" + e.getMessage(), e);
 			return result.error500("发送消息出错!");
 		}
 	}

+ 0 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/enums/RangeDateEnum.java

@@ -79,7 +79,6 @@ public enum RangeDateEnum {
             //本周
             calendar1.set(Calendar.DAY_OF_WEEK, 2);
 
-            calendar2.set(Calendar.DAY_OF_WEEK,2);
             calendar2.add(Calendar.WEEK_OF_MONTH,1);
             calendar2.add(Calendar.DAY_OF_WEEK,-1);
         } else if(SZ.key.equals(key)){

+ 9 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/websocket/WebSocket.java

@@ -31,8 +31,13 @@ public class WebSocket {
      * Redis触发监听名字
      */
     public static final String REDIS_TOPIC_NAME = "socketHandler";
+
+    //避免初次调用出现空指针的情况
+    private static JeecgRedisClient jeecgRedisClient;
     @Autowired
-    private JeecgRedisClient jeecgRedisClient;
+    private void setJeecgRedisClient(JeecgRedisClient jeecgRedisClient){
+        WebSocket.jeecgRedisClient = jeecgRedisClient;
+    }
 
 
     //==========【websocket接受、推送消息等方法 —— 具体服务节点推送ws消息】========================================================================================
@@ -109,6 +114,9 @@ public class WebSocket {
             log.debug("【系统 WebSocket】收到客户端消息:" + message);
         }else{
             log.debug("【系统 WebSocket】收到客户端消息:" + message);
+            //update-begin---author:wangshuai---date:2024-05-07---for:【issues/1161】前端websocket因心跳导致监听不起作用---
+            this.sendMessage(userId, "ping");
+            //update-end---author:wangshuai---date:2024-05-07---for:【issues/1161】前端websocket因心跳导致监听不起作用---
         }
         
 //        //------------------------------------------------------------------------------

+ 38 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/CustomActuatorConfig.java

@@ -0,0 +1,38 @@
+package org.jeecg.modules.monitor.actuator;
+
+import org.jeecg.modules.monitor.actuator.httptrace.CustomInMemoryHttpTraceRepository;
+import org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceAutoConfiguration;
+import org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceProperties;
+import org.springframework.boot.actuate.trace.http.HttpTraceRepository;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 自定义健康监控配置类
+ *
+ * @Author: chenrui
+ * @Date: 2024/5/13 17:20
+ */
+@Configuration
+@EnableConfigurationProperties(HttpTraceProperties.class)
+@AutoConfigureBefore(HttpTraceAutoConfiguration.class)
+public class CustomActuatorConfig {
+
+    /**
+     * 请求追踪
+     * @return
+     * @author chenrui
+     * @date 2024/5/14 14:52
+     */
+    @Bean
+    @ConditionalOnProperty(prefix = "management.trace.http", name = "enabled", matchIfMissing = true)
+    @ConditionalOnMissingBean(HttpTraceRepository.class)
+    public CustomInMemoryHttpTraceRepository traceRepository() {
+        return new CustomInMemoryHttpTraceRepository();
+    }
+
+}

+ 44 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/httptrace/CustomHttpTraceEndpoint.java

@@ -0,0 +1,44 @@
+package org.jeecg.modules.monitor.actuator.httptrace;
+
+import lombok.Getter;
+import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
+import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
+import org.springframework.boot.actuate.endpoint.annotation.Selector;
+import org.springframework.boot.actuate.trace.http.HttpTrace;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+
+import java.util.List;
+
+import static org.springframework.boot.actuate.endpoint.annotation.Selector.Match.ALL_REMAINING;
+
+/**
+ * @Description: ENDPOINT: 请求追踪(新),支持通过responseCode筛选
+ * @Author: chenrui
+ * @Date: 2024/5/13 17:02
+ */
+@Component
+@Endpoint(id = "httptrace-new")
+public class CustomHttpTraceEndpoint{
+    private final CustomInMemoryHttpTraceRepository repository;
+
+    public CustomHttpTraceEndpoint(CustomInMemoryHttpTraceRepository repository) {
+        Assert.notNull(repository, "Repository must not be null");
+        this.repository = repository;
+    }
+
+    @ReadOperation
+    public HttpTraceDescriptor traces(@Selector(match = ALL_REMAINING) String query) {
+        return new CustomHttpTraceEndpoint.HttpTraceDescriptor(this.repository.findAll(query));
+    }
+
+    @Getter
+    public static final class HttpTraceDescriptor {
+        private final List<HttpTrace> traces;
+
+        private HttpTraceDescriptor(List<HttpTrace> traces) {
+            this.traces = traces;
+        }
+
+    }
+}

+ 94 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/httptrace/CustomInMemoryHttpTraceRepository.java

@@ -0,0 +1,94 @@
+package org.jeecg.modules.monitor.actuator.httptrace;
+
+import org.springframework.boot.actuate.trace.http.HttpTrace;
+import org.springframework.boot.actuate.trace.http.InMemoryHttpTraceRepository;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @Description: 自定义内存请求追踪存储
+ * @Author: chenrui
+ * @Date: 2024/5/13 17:02
+ */
+public class CustomInMemoryHttpTraceRepository extends InMemoryHttpTraceRepository {
+
+    @Override
+    public List<HttpTrace> findAll() {
+        return super.findAll();
+    }
+
+    public List<HttpTrace> findAll(String query) {
+        List<HttpTrace> allTrace = super.findAll();
+        if (null != allTrace && !allTrace.isEmpty()) {
+            Stream<HttpTrace> stream = allTrace.stream();
+            String[] params = query.split(",");
+            stream = filter(params, stream);
+            stream = sort(params, stream);
+            allTrace = stream.collect(Collectors.toList());
+        }
+        return allTrace;
+    }
+
+    private Stream<HttpTrace> sort(String[] params, Stream<HttpTrace> stream) {
+        if (params.length < 2) {
+            return stream;
+        }
+        String sortBy = params[1];
+        String order;
+        if (params.length > 2) {
+            order = params[2];
+        } else {
+            order = "desc";
+        }
+        return stream.sorted((o1, o2) -> {
+            int i = 0;
+            if("timeTaken".equalsIgnoreCase(sortBy)) {
+                i = o1.getTimeTaken().compareTo(o2.getTimeTaken());
+            }else if("timestamp".equalsIgnoreCase(sortBy)){
+                i = o1.getTimestamp().compareTo(o2.getTimestamp());
+            }
+            if("desc".equalsIgnoreCase(order)){
+                i *=-1;
+            }
+            return i;
+        });
+    }
+
+    private static Stream<HttpTrace> filter(String[] params, Stream<HttpTrace> stream) {
+        if (params.length == 0) {
+            return stream;
+        }
+        String statusQuery = params[0];
+        if (null != statusQuery && !statusQuery.isEmpty()) {
+            statusQuery = statusQuery.toLowerCase().trim();
+            switch (statusQuery) {
+                case "error":
+                    stream = stream.filter(httpTrace -> {
+                        int status = httpTrace.getResponse().getStatus();
+                        return status >= 404 && status < 501;
+                    });
+                    break;
+                case "warn":
+                    stream = stream.filter(httpTrace -> {
+                        int status = httpTrace.getResponse().getStatus();
+                        return status >= 201 && status < 404;
+                    });
+                    break;
+                case "success":
+                    stream = stream.filter(httpTrace -> {
+                        int status = httpTrace.getResponse().getStatus();
+                        return status == 200;
+                    });
+                    break;
+                case "all":
+                default:
+                    break;
+            }
+            return stream;
+        }
+        return stream;
+    }
+
+}

+ 52 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ActuatorMemoryController.java

@@ -0,0 +1,52 @@
+package org.jeecg.modules.monitor.controller;
+
+import cn.hutool.core.util.NumberUtil;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Description: 内存健康检查
+ * @author: chenrui
+ */
+@Slf4j
+@RestController
+@RequestMapping("/sys/actuator/memory")
+public class ActuatorMemoryController {
+
+
+    /**
+     * 内存详情
+     * @return
+     * @throws Exception
+     */
+    @GetMapping("/info")
+    public Result<?> getRedisInfo() throws Exception {
+		OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
+		JSONObject operatingSystemJson = JSONObject.parseObject(JSONObject.toJSONString(operatingSystemMXBean));
+		long totalPhysicalMemory = operatingSystemJson.getLongValue("totalPhysicalMemorySize");
+		long freePhysicalMemory = operatingSystemJson.getLongValue("freePhysicalMemorySize");
+		long usedPhysicalMemory = totalPhysicalMemory - freePhysicalMemory;
+		Runtime runtime = Runtime.getRuntime();
+		Map<String,Number> result = new HashMap<>();
+		result.put("memory.physical.total", totalPhysicalMemory);
+		result.put("memory.physical.used", freePhysicalMemory);
+		result.put("memory.physical.free", usedPhysicalMemory);
+		result.put("memory.physical.usage", NumberUtil.div(usedPhysicalMemory, totalPhysicalMemory));
+		result.put("memory.runtime.total", runtime.totalMemory());
+		result.put("memory.runtime.used", runtime.freeMemory());
+		result.put("memory.runtime.max", runtime.totalMemory() - runtime.freeMemory());
+		result.put("memory.runtime.free", runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory());
+		result.put("memory.runtime.usage", NumberUtil.div(runtime.totalMemory() - runtime.freeMemory(), runtime.totalMemory()));
+        return Result.ok(result);
+    }
+
+}

+ 15 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ActuatorRedisController.java

@@ -43,6 +43,21 @@ public class ActuatorRedisController {
         return Result.ok(infoList);
     }
 
+	//update-begin---author:chenrui ---date:20240514  for:[QQYUN-9247]系统监控功能优化------------
+	/**
+	 * Redis历史性能指标查询(过去一小时)
+	 * @return
+	 * @throws Exception
+	 * @author chenrui
+	 * @date 2024/5/14 14:56
+	 */
+	@GetMapping(value = "/metrics/history")
+	public Result<?> getMetricsHistory() throws Exception {
+		Map<String,List<Map<String,Object>>> metricsHistory = this.redisService.getMetricsHistory();
+	    return Result.OK(metricsHistory);
+	}
+	//update-end---author:chenrui ---date:20240514  for:[QQYUN-9247]系统监控功能优化------------
+
     @GetMapping("/keysSize")
     public Map<String, Object> getKeysSize() throws Exception {
         return redisService.getKeysSize();

+ 8 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/RedisService.java

@@ -44,4 +44,12 @@ public interface RedisService {
      * @throws RedisConnectException
 	 */
 	Map<String, JSONArray> getMapForReport(String type) throws RedisConnectException ;
+
+	/**
+	 * 获取历史性能指标
+	 * @return
+	 * @author chenrui
+	 * @date 2024/5/14 14:57
+	 */
+	Map<String, List<Map<String, Object>>> getMetricsHistory();
 }

+ 51 - 6
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java

@@ -1,10 +1,6 @@
 package org.jeecg.modules.monitor.service.impl;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
+import java.util.*;
 
 import javax.annotation.Resource;
 
@@ -12,13 +8,13 @@ import cn.hutool.core.date.DateUtil;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.google.common.collect.Maps;
-import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.monitor.domain.RedisInfo;
 import org.jeecg.modules.monitor.exception.RedisConnectException;
 import org.jeecg.modules.monitor.service.RedisService;
 import org.springframework.cglib.beans.BeanMap;
 import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
 import lombok.extern.slf4j.Slf4j;
@@ -40,6 +36,11 @@ public class RedisServiceImpl implements RedisService {
      */
     private static final String REDIS_MESSAGE = "3";
 
+	/**
+	 * redis性能信息记录
+	 */
+	private static final Map<String,List<Map<String, Object>>> REDIS_METRICS = new HashMap<>(2);
+
 	/**
 	 * Redis详细信息
 	 */
@@ -126,4 +127,48 @@ public class RedisServiceImpl implements RedisService {
 		mapJson.put("data",json);
 		return mapJson;
 	}
+
+	//update-begin---author:chenrui ---date:20240514  for:[QQYUN-9247]系统监控功能优化------------
+	/**
+	 * 获取历史性能指标
+	 * @return
+	 * @author chenrui
+	 * @date 2024/5/14 14:57
+	 */
+	@Override
+	public Map<String, List<Map<String, Object>>> getMetricsHistory() {
+		return REDIS_METRICS;
+	}
+
+	/**
+	 * 记录近一小时redis监控数据 <br/>
+	 * 60s一次,,记录存储keysize和内存
+	 * @throws RedisConnectException
+	 * @author chenrui
+	 * @date 2024/5/14 14:09
+	 */
+	@Scheduled(fixedRate = 60000)
+	public void recordCustomMetric() throws RedisConnectException {
+		List<Map<String, Object>> list= new ArrayList<>();
+		if(REDIS_METRICS.containsKey("dbSize")){
+			list = REDIS_METRICS.get("dbSize");
+		}else{
+			REDIS_METRICS.put("dbSize",list);
+		}
+		if(list.size()>60){
+			list.remove(0);
+		}
+		list.add(getKeysSize());
+		list= new ArrayList<>();
+		if(REDIS_METRICS.containsKey("memory")){
+			list = REDIS_METRICS.get("memory");
+		}else{
+			REDIS_METRICS.put("memory",list);
+		}
+		if(list.size()>60){
+			list.remove(0);
+		}
+		list.add(getMemoryInfo());
+	}
+	//update-end---author:chenrui ---date:20240514  for:[QQYUN-9247]系统监控功能优化------------
 }

+ 7 - 7
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java

@@ -79,7 +79,7 @@ public class QuartzJobController {
 	 * @param quartzJob
 	 * @return
 	 */
-	@RequiresRoles("admin")
+	//@RequiresRoles("admin")
     @RequiresPermissions("system:quartzJob:add")
 	@RequestMapping(value = "/add", method = RequestMethod.POST)
 	public Result<?> add(@RequestBody QuartzJob quartzJob) {
@@ -93,7 +93,7 @@ public class QuartzJobController {
 	 * @param quartzJob
 	 * @return
 	 */
-	@RequiresRoles("admin")
+	//@RequiresRoles("admin")
     @RequiresPermissions("system:quartzJob:edit")
 	@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
 	public Result<?> eidt(@RequestBody QuartzJob quartzJob) {
@@ -112,7 +112,7 @@ public class QuartzJobController {
 	 * @param id
 	 * @return
 	 */
-	@RequiresRoles("admin")
+	//@RequiresRoles("admin")
     @RequiresPermissions("system:quartzJob:delete")
 	@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
 	public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
@@ -131,7 +131,7 @@ public class QuartzJobController {
 	 * @param ids
 	 * @return
 	 */
-	@RequiresRoles("admin")
+	//@RequiresRoles("admin")
     @RequiresPermissions("system:quartzJob:deleteBatch")
 	@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
 	public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
@@ -151,7 +151,7 @@ public class QuartzJobController {
 	 * @param id
 	 * @return
 	 */
-	@RequiresRoles("admin")
+	//@RequiresRoles("admin")
     @RequiresPermissions("system:quartzJob:pause")
 	@GetMapping(value = "/pause")
 	@ApiOperation(value = "停止定时任务")
@@ -170,7 +170,7 @@ public class QuartzJobController {
 	 * @param id
 	 * @return
 	 */
-	@RequiresRoles("admin")
+	//@RequiresRoles("admin")
     @RequiresPermissions("system:quartzJob:resume")
 	@GetMapping(value = "/resume")
 	@ApiOperation(value = "启动定时任务")
@@ -271,7 +271,7 @@ public class QuartzJobController {
 	 * @param id
 	 * @return
 	 */
-	@RequiresRoles("admin")
+	//@RequiresRoles("admin")
     @RequiresPermissions("system:quartzJob:execute")
 	@GetMapping("/execute")
 	public Result<?> execute(@RequestParam(name = "id", required = true) String id) {

+ 69 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/cache/AuthStateRedisCache.java

@@ -0,0 +1,69 @@
+package org.jeecg.modules.system.cache;
+
+import me.zhyd.oauth.cache.AuthCacheConfig;
+import me.zhyd.oauth.cache.AuthStateCache;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+
+import javax.annotation.PostConstruct;
+import java.util.concurrent.TimeUnit;
+
+
+public class AuthStateRedisCache implements AuthStateCache {
+
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
+    private ValueOperations<String, String> valueOperations;
+
+    @PostConstruct
+    public void init() {
+        valueOperations = redisTemplate.opsForValue();
+    }
+
+    /**
+     * 存入缓存,默认3分钟
+     *
+     * @param key   缓存key
+     * @param value 缓存内容
+     */
+    @Override
+    public void cache(String key, String value) {
+        valueOperations.set(key, value, AuthCacheConfig.timeout, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 存入缓存
+     *
+     * @param key     缓存key
+     * @param value   缓存内容
+     * @param timeout 指定缓存过期时间(毫秒)
+     */
+    @Override
+    public void cache(String key, String value, long timeout) {
+        valueOperations.set(key, value, timeout, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 获取缓存内容
+     *
+     * @param key 缓存key
+     * @return 缓存内容
+     */
+    @Override
+    public String get(String key) {
+        return valueOperations.get(key);
+    }
+
+    /**
+     * 是否存在key,如果对应key的value值已过期,也返回false
+     *
+     * @param key 缓存key
+     * @return true:存在key,并且value没过期;false:key不存在或者已过期
+     */
+    @Override
+    public boolean containsKey(String key) {
+        return redisTemplate.hasKey(key);
+    }
+}

+ 15 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/config/AuthStateConfiguration.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.system.config;
+
+import me.zhyd.oauth.cache.AuthStateCache;
+import org.jeecg.modules.system.cache.AuthStateRedisCache;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class AuthStateConfiguration {
+
+    @Bean
+    public AuthStateCache authStateCache() {
+        return new AuthStateRedisCache();
+    }
+}

+ 1 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/CommonController.java

@@ -10,6 +10,7 @@ import org.jeecg.common.util.CommonUtils;
 import org.jeecg.common.util.filter.SsrfFileTypeFilter;
 import org.jeecg.common.util.oConvertUtils;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.util.AntPathMatcher;
 import org.springframework.util.FileCopyUtils;
 import org.springframework.web.bind.annotation.*;

+ 94 - 3
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java

@@ -243,7 +243,7 @@ public class LoginController {
 	 * 获取访问量
 	 * @return
 	 */
-	@GetMapping("visitInfo")
+	@GetMapping("/visitInfo")
 	public Result<List<Map<String,Object>>> visitInfo() {
 		Result<List<Map<String,Object>>> result = new Result<List<Map<String,Object>>>();
 		Calendar calendar = new GregorianCalendar();
@@ -295,12 +295,14 @@ public class LoginController {
 	 * @return
 	 */
 	@PostMapping(value = "/sms")
-	public Result<String> sms(@RequestBody JSONObject jsonObject) {
+	public Result<String> sms(@RequestBody JSONObject jsonObject,HttpServletRequest request) {
 		Result<String> result = new Result<String>();
+		String clientIp = IpUtils.getIpAddr(request);
 		String mobile = jsonObject.get("mobile").toString();
 		//手机号模式 登录模式: "2"  注册模式: "1"
 		String smsmode=jsonObject.get("smsmode").toString();
-		log.info(mobile);
+		log.info("-------- IP:{}, 手机号:{},获取绑定验证码", clientIp, mobile);
+		
 		if(oConvertUtils.isEmpty(mobile)){
 			result.setMessage("手机号不允许为空!");
 			result.setSuccess(false);
@@ -318,6 +320,17 @@ public class LoginController {
 			return result;
 		}
 
+		//-------------------------------------------------------------------------------------
+		//增加 check防止恶意刷短信接口
+		if(!DySmsLimit.canSendSms(clientIp)){
+			log.warn("--------[警告] IP地址:{}, 短信接口请求太多-------", clientIp);
+			result.setMessage("短信接口请求太多,请稍后再试!");
+			result.setCode(CommonConstant.PHONE_SMS_FAIL_CODE);
+			result.setSuccess(false);
+			return result;
+		}
+		//-------------------------------------------------------------------------------------
+
 		//随机数
 		String captcha = RandomUtil.randomNumbers(6);
 		JSONObject obj = new JSONObject();
@@ -734,4 +747,82 @@ public class LoginController {
 		redisUtil.set(key, ++val, 600);
 	}
 
+	/**
+	 * 发送短信验证码接口(修改密码)
+	 *
+	 * @param jsonObject
+	 * @return
+	 */
+	@PostMapping(value = "/sendChangePwdSms")
+	public Result<String> sendSms(@RequestBody JSONObject jsonObject) {
+		Result<String> result = new Result<>();
+		String mobile = jsonObject.get("mobile").toString();
+		if (oConvertUtils.isEmpty(mobile)) {
+			result.setMessage("手机号不允许为空!");
+			result.setSuccess(false);
+			return result;
+		}
+		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+		String username = sysUser.getUsername();
+		LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>();
+		query.eq(SysUser::getUsername, username).eq(SysUser::getPhone, mobile);
+		SysUser user = sysUserService.getOne(query);
+		if (null == user) {
+			return Result.error("当前登录用户和绑定的手机号不匹配,无法修改密码!");
+		}
+		String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE + mobile;
+		Object object = redisUtil.get(redisKey);
+		if (object != null) {
+			result.setMessage("验证码10分钟内,仍然有效!");
+			result.setSuccess(false);
+			return result;
+		}
+		//随机数
+		String captcha = RandomUtil.randomNumbers(6);
+		JSONObject obj = new JSONObject();
+		obj.put("code", captcha);
+		try {
+			boolean b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.CHANGE_PASSWORD_TEMPLATE_CODE);
+			if (!b) {
+				result.setMessage("短信验证码发送失败,请稍后重试");
+				result.setSuccess(false);
+				return result;
+			}
+			//验证码5分钟内有效
+			redisUtil.set(redisKey, captcha, 300);
+			result.setSuccess(true);
+		} catch (ClientException e) {
+			e.printStackTrace();
+			result.error500(" 短信接口未配置,请联系管理员!");
+			return result;
+		}
+		return result;
+	}
+
+	
+	/**
+	 * 图形验证码
+	 * @param sysLoginModel
+	 * @return
+	 */
+	@RequestMapping(value = "/smsCheckCaptcha", method = RequestMethod.POST)
+	public Result<?> smsCheckCaptcha(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request){
+		String captcha = sysLoginModel.getCaptcha();
+		String checkKey = sysLoginModel.getCheckKey();
+		if(captcha==null){
+			return Result.error("验证码无效");
+		}
+		String lowerCaseCaptcha = captcha.toLowerCase();
+		String realKey = Md5Util.md5Encode(lowerCaseCaptcha+checkKey+jeecgBaseConfig.getSignatureSecret(), "utf-8");
+		Object checkCode = redisUtil.get(realKey);
+		if(checkCode==null || !checkCode.equals(lowerCaseCaptcha)) {
+			return Result.error("验证码错误");
+		}
+		String clientIp = IpUtils.getIpAddr(request);
+		//清空短信记录数量
+		DySmsLimit.clearSendSmsCount(clientIp);
+		redisUtil.removeAll(realKey);
+		return Result.ok();
+	}
+	
 }

+ 66 - 17
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java

@@ -1,6 +1,5 @@
 package org.jeecg.modules.system.controller;
 
-import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -18,10 +17,7 @@ import org.jeecg.common.constant.WebsocketConst;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.util.JwtUtil;
 import org.jeecg.common.system.vo.LoginUser;
-import org.jeecg.common.util.DateUtils;
-import org.jeecg.common.util.RedisUtil;
-import org.jeecg.common.util.TokenUtils;
-import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.common.util.*;
 import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
 import org.jeecg.modules.message.enums.RangeDateEnum;
 import org.jeecg.modules.message.websocket.WebSocket;
@@ -40,6 +36,7 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
 import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.http.HttpStatus;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
@@ -51,7 +48,10 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import java.util.*;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -86,7 +86,9 @@ public class SysAnnouncementController {
 	@Autowired
 	@Lazy
 	private RedisUtil redisUtil;
-
+	@Autowired
+	public RedisTemplate redisTemplate;
+	
 	/**
 	 * QQYUN-5072【性能优化】线上通知消息打开有点慢
 	 */
@@ -332,12 +334,19 @@ public class SysAnnouncementController {
 	 * @return
 	 */
 	@RequestMapping(value = "/listByUser", method = RequestMethod.GET)
-	public Result<Map<String, Object>> listByUser(@RequestParam(required = false, defaultValue = "5") Integer pageSize) {
+	public Result<Map<String, Object>> listByUser(@RequestParam(required = false, defaultValue = "5") Integer pageSize, HttpServletRequest request) {
 		long start = System.currentTimeMillis();
 		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
 		Map<String,Object> sysMsgMap = new HashMap(5);
 		LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
 		String userId = sysUser.getId();
+
+
+		//update-begin---author:scott ---date:2024-05-11  for:【性能优化】优化系统通知,只查近2个月的通知---
+		// 获取上个月的第一天(只查近两个月的通知)
+		Date lastMonthStartDay = DateRangeUtils.getLastMonthStartDay();
+		log.info("-----查询近两个月收到的未读通知-----,近2月的第一天:{}", lastMonthStartDay);
+		//update-end---author:scott ---date::2024-05-11  for:【性能优化】优化系统通知,只查近2个月的通知---
 		
 //		//补推送数据(用户和通知的关系表)
 //		completeNoteThreadPool.execute(()->{
@@ -347,19 +356,19 @@ public class SysAnnouncementController {
 		// 2.查询用户未读的系统消息
 		Page<SysAnnouncement> anntMsgList = new Page<SysAnnouncement>(0, pageSize);
         //通知公告消息
-		anntMsgList = sysAnnouncementService.querySysCementPageByUserId(anntMsgList,userId,"1");
+		anntMsgList = sysAnnouncementService.querySysCementPageByUserId(anntMsgList,userId,"1",null, lastMonthStartDay);
 		sysMsgMap.put("anntMsgList", anntMsgList.getRecords());
 		sysMsgMap.put("anntMsgTotal", anntMsgList.getTotal());
 
-		log.info("begin 获取用户系统公告 (通知)" + (System.currentTimeMillis() - start) + "毫秒");
+		log.info("begin 获取用户近2个月的系统公告 (通知)" + (System.currentTimeMillis() - start) + "毫秒");
 		
         //系统消息
 		Page<SysAnnouncement> sysMsgList = new Page<SysAnnouncement>(0, pageSize);
-		sysMsgList = sysAnnouncementService.querySysCementPageByUserId(sysMsgList,userId,"2");
+		sysMsgList = sysAnnouncementService.querySysCementPageByUserId(sysMsgList,userId,"2",null, lastMonthStartDay);
 		sysMsgMap.put("sysMsgList", sysMsgList.getRecords());
 		sysMsgMap.put("sysMsgTotal", sysMsgList.getTotal());
 
-		log.info("end 获取用户系统公告 (系统消息)" + (System.currentTimeMillis() - start) + "毫秒");
+		log.info("end 获取用户2个月的系统公告 (系统消息)" + (System.currentTimeMillis() - start) + "毫秒");
 		
 		result.setSuccess(true);
 		result.setResult(sysMsgMap);
@@ -367,6 +376,24 @@ public class SysAnnouncementController {
 	}
 
 
+	/**
+	 * 获取未读消息通知数量
+	 *
+	 * @return
+	 */
+	@RequestMapping(value = "/getUnreadMessageCount", method = RequestMethod.GET)
+	public Result<Integer> getUnreadMessageCount(@RequestParam(required = false, defaultValue = "5") Integer pageSize, HttpServletRequest request) {
+		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+		String userId = sysUser.getId();
+
+		// 获取上个月的第一天(只查近两个月的通知)
+		Date lastMonthStartDay = DateRangeUtils.getLastMonthStartDay();
+		log.info(" ------查询近两个月收到的未读通知消息数量------,近2月的第一天:{}", lastMonthStartDay);
+		Integer unreadMessageCount = sysAnnouncementService.getUnreadMessageCountByUserId(userId, lastMonthStartDay);
+		return Result.ok(unreadMessageCount);
+	}
+
+
     /**
      * 导出excel
      *
@@ -570,15 +597,37 @@ public class SysAnnouncementController {
      */
 	@GetMapping("/getLastAnnountTime")
 	public Result<Page<SysAnnouncementSend>> getLastAnnountTime(@RequestParam(name = "userId") String userId){
-        Result<Page<SysAnnouncementSend>> result = new Result<>();
-        Page<SysAnnouncementSend> page = new Page<>(1,1);
+		Result<Page<SysAnnouncementSend>> result = new Result<>();
+		//----------------------------------------------------------------------------------------
+		// step.1 此接口过慢,可以采用缓存一小时方案
+		String keyString = String.format(CommonConstant.CACHE_KEY_USER_LAST_ANNOUNT_TIME_1HOUR, userId);
+		if (redisTemplate.hasKey(keyString)) {
+			log.info("[SysAnnouncementSend Redis] 通过Redis缓存查询用户最后一次收到系统通知时间,userId={}", userId);
+			Page<SysAnnouncementSend> pageList = (Page<SysAnnouncementSend>) redisTemplate.opsForValue().get(keyString);
+			result.setSuccess(true);
+			result.setResult(pageList);
+			return result;
+		}
+		//----------------------------------------------------------------------------------------
+
+		Page<SysAnnouncementSend> page = new Page<>(1,1);
         LambdaQueryWrapper<SysAnnouncementSend> query = new LambdaQueryWrapper<>();
         query.eq(SysAnnouncementSend::getUserId,userId);
-        query.select(SysAnnouncementSend::getCreateTime);
+        //只查询上个月和本月,的通知的数据
+		query.ne(SysAnnouncementSend::getCreateTime, DateRangeUtils.getLastMonthStartDay());
+        query.select(SysAnnouncementSend::getCreateTime); // 提高查询效率
         query.orderByDesc(SysAnnouncementSend::getCreateTime);
         Page<SysAnnouncementSend> pageList = sysAnnouncementSendService.page(page, query);
-        result.setSuccess(true);
-        result.setResult(pageList);
+
+		//----------------------------------------------------------------------------------------
+		if (pageList != null && pageList.getSize() > 0) {
+			// step.3 保留1小时redis缓存
+			redisTemplate.opsForValue().set(keyString, pageList, 3600, TimeUnit.SECONDS);
+		}
+		//----------------------------------------------------------------------------------------
+
+		result.setSuccess(true);
+		result.setResult(pageList);
         return result;
     }
 

+ 7 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDictController.java

@@ -326,6 +326,13 @@ public class SysDictController {
 												  @RequestParam(name="condition") String condition,
 												  @RequestParam(value = "sign",required = false) String sign,HttpServletRequest request) {
 		Result<List<TreeSelectModel>> result = new Result<List<TreeSelectModel>>();
+
+		// 【QQYUN-9207】防止参数为空导致报错
+		if (oConvertUtils.isEmpty(tableName) || oConvertUtils.isEmpty(text) || oConvertUtils.isEmpty(code)) {
+			result.error500("字典Code格式不正确!");
+			return result;
+		}
+
 		// 1.获取查询条件参数
 		Map<String, String> query = null;
 		if(oConvertUtils.isNotEmpty(condition)) {

+ 12 - 2
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java

@@ -17,9 +17,11 @@ import cn.hutool.core.util.RandomUtil;
 import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.base.BaseMap;
 import org.jeecg.common.config.TenantContext;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.SymbolConstant;
+import org.jeecg.common.modules.redis.client.JeecgRedisClient;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
@@ -83,6 +85,8 @@ public class SysRoleController {
     private ISysUserRoleService sysUserRoleService;
 	@Autowired
 	private BaseCommonService baseCommonService;
+	@Autowired
+	private JeecgRedisClient jeecgRedisClient;
 	
 	/**
 	  * 分页列表查询 【系统角色,不做租户隔离】
@@ -124,7 +128,9 @@ public class SysRoleController {
 												HttpServletRequest req) {
 		Result<IPage<SysRole>> result = new Result<IPage<SysRole>>();
 		//此接口必须通过租户来隔离查询
-		role.setTenantId(oConvertUtils.getInt(!"0".equals(TenantContext.getTenant()) ? TenantContext.getTenant() : "", -1));
+		if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
+			role.setTenantId(oConvertUtils.getInt(!"0".equals(TenantContext.getTenant()) ? TenantContext.getTenant() : "", -1));
+		}
 		
 		QueryWrapper<SysRole> queryWrapper = QueryGenerator.initQueryWrapper(role, req.getParameterMap());
 		Page<SysRole> page = new Page<SysRole>(pageNo, pageSize);
@@ -145,7 +151,9 @@ public class SysRoleController {
 		Result<SysRole> result = new Result<SysRole>();
 		try {
 			//开启多租户隔离,角色id自动生成10位
-			if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
+			//update-begin---author:wangshuai---date:2024-05-23---for:【TV360X-42】角色新增时设置的编码,保存后不一致---
+			if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && oConvertUtils.isEmpty(role.getRoleCode())){
+			//update-end---author:wangshuai---date:2024-05-23---for:【TV360X-42】角色新增时设置的编码,保存后不一致---
 				role.setRoleCode(RandomUtil.randomString(10));
 			}
 			role.setCreateTime(new Date());
@@ -222,6 +230,7 @@ public class SysRoleController {
 		//update-end---author:wangshuai---date:2024-01-16---for:【QQYUN-7974】禁止删除 admin 角色---
     	
 		sysRoleService.deleteRole(id);
+
 		return Result.ok("删除角色成功");
 	}
 	
@@ -570,4 +579,5 @@ public class SysRoleController {
         result.setResult(sysRoleCountPage);
         return result;
     }
+
 }

+ 40 - 4
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java

@@ -1,6 +1,7 @@
 package org.jeecg.modules.system.controller;
 
 
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.RandomUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -351,10 +352,10 @@ public class SysTenantController {
      * @param ids
      * @return
      */
-    @DeleteMapping("/deletePackPermissions")
+    @DeleteMapping("/deleteTenantPack")
     @RequiresPermissions("system:tenant:delete:pack")
-    public Result<String> deletePackPermissions(@RequestParam(value = "ids") String ids) {
-        sysTenantPackService.deletePackPermissions(ids);
+    public Result<String> deleteTenantPack(@RequestParam(value = "ids") String ids) {
+        sysTenantPackService.deleteTenantPack(ids);
         return Result.ok("删除租户产品包成功");
     }
     
@@ -500,7 +501,7 @@ public class SysTenantController {
         Integer tenantId = sysTenantService.joinTenantByHouseNumber(sysTenant, sysUser.getId());
         Result<Integer> result = new Result<>();
         if(tenantId != 0){
-            result.setMessage("申请租户成功");
+            result.setMessage("申请加入组织成功");
             result.setSuccess(true);
             result.setResult(tenantId);
             return result;
@@ -935,4 +936,39 @@ public class SysTenantController {
         return Result.error("类型不匹配,禁止修改数据");
     }
     
+    /**
+     * 目前只给敲敲云租户下删除用户使用
+     * 
+     * 根据密码删除用户
+     */
+    @DeleteMapping("/deleteUserByPassword")
+    public Result<String> deleteUserByPassword(@RequestBody SysUser sysUser,HttpServletRequest request){
+        Integer tenantId = oConvertUtils.getInteger(TokenUtils.getTenantIdByRequest(request), null);
+        sysTenantService.deleteUserByPassword(sysUser, tenantId);
+        return Result.ok("删除用户成功");
+    }
+
+    /**
+     *  查询当前用户的所有有效租户【知识库专用接口】
+     * @return
+     */
+    @RequestMapping(value = "/getCurrentUserTenantForFile", method = RequestMethod.GET)
+    public Result<Map<String,Object>> getCurrentUserTenantForFile() {
+        Result<Map<String,Object>> result = new Result<Map<String,Object>>();
+        try {
+            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+            List<SysTenant> tenantList = sysTenantService.getTenantListByUserId(sysUser.getId());
+            Map<String,Object> map = new HashMap<>(5);
+            //在开启saas租户隔离的时候并且租户数据不为空,则返回租户信息
+            if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && CollectionUtil.isNotEmpty(tenantList)) {
+                map.put("list", tenantList);
+            }
+            result.setSuccess(true);
+            result.setResult(map);
+        }catch(Exception e) {
+            log.error(e.getMessage(), e);
+            result.error500("查询失败!");
+        }
+        return result;
+    }
 }

+ 14 - 8
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java

@@ -7,7 +7,6 @@ import com.alibaba.fastjson.JSONArray;
 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.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.extern.slf4j.Slf4j;
@@ -17,15 +16,17 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.apache.shiro.authz.annotation.RequiresRoles;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.aspect.annotation.PermissionData;
+import org.jeecg.common.base.BaseMap;
 import org.jeecg.common.config.TenantContext;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.SymbolConstant;
-import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
-import org.jeecg.modules.base.service.BaseCommonService;
+import org.jeecg.common.modules.redis.client.JeecgRedisClient;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.util.JwtUtil;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.*;
+import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
+import org.jeecg.modules.base.service.BaseCommonService;
 import org.jeecg.modules.system.entity.*;
 import org.jeecg.modules.system.model.DepartIdModel;
 import org.jeecg.modules.system.model.SysUserSysDepartModel;
@@ -101,6 +102,9 @@ public class SysUserController {
     @Autowired
     private ISysUserTenantService userTenantService;
 
+    @Autowired
+    private JeecgRedisClient jeecgRedisClient;
+    
     /**
      * 获取租户下用户数据(支持租户隔离)
      * @param user
@@ -1129,7 +1133,7 @@ public class SysUserController {
         }
         sysUser = this.sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername,username).eq(SysUser::getPhone,phone));
         if (sysUser == null) {
-            result.setMessage("未找到用户!");
+            result.setMessage("当前登录用户和绑定的手机号不匹配,无法修改密码!");
             result.setSuccess(false);
             return result;
         } else {
@@ -1143,6 +1147,8 @@ public class SysUserController {
             //update-end---author:wangshuai ---date:20220316  for:[VUEN-234]密码重置添加敏感日志------------
             result.setSuccess(true);
             result.setMessage("密码重置完成!");
+            //修改完密码后清空redis
+            redisUtil.removeAll(redisKey);
             return result;
         }
     }
@@ -1551,15 +1557,15 @@ public class SysUserController {
             @RequestParam(name = "departId", required = false) String departId,
             @RequestParam(name = "roleId", required = false) String roleId,
             @RequestParam(name="keyword",required=false) String keyword,
-            @RequestParam(name="excludeUserIdList",required = false) String excludeUserIdList) {
+            @RequestParam(name="excludeUserIdList",required = false) String excludeUserIdList,
+            HttpServletRequest req) {
         //------------------------------------------------------------------------------------------------
         Integer tenantId = null;
         //是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
         if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
             String tenantStr = TenantContext.getTenant();
-            if(oConvertUtils.isNotEmpty(tenantStr)){
-                tenantId = Integer.parseInt(tenantStr);
-            }
+            tenantId = oConvertUtils.getInteger(tenantStr, oConvertUtils.getInt(TokenUtils.getTenantIdByRequest(req), -1));
+            log.info("---------简流中选择用户接口,通过租户筛选,租户ID={}", tenantId);
         }
         //------------------------------------------------------------------------------------------------
         IPage<SysUser> pageList = sysUserDepartService.getUserInformation(tenantId, departId,roleId, keyword, pageSize, pageNo,excludeUserIdList);

+ 7 - 2
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java

@@ -61,8 +61,13 @@ public class ThirdAppController {
     @GetMapping("/getEnabledType")
     public Result getEnabledType() {
         Map<String, Boolean> enabledMap = new HashMap(5);
-        //update-begin---author:wangshuai ---date:20230224  for:[QQYUN-3440]通过租户模式隔离 ------------
-        int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
+        int tenantId;
+        //是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
+        if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
+            tenantId = oConvertUtils.getInt(TenantContext.getTenant(), -1);
+        } else {
+            tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
+        }
         //查询当前租户下的第三方配置
         List<SysThirdAppConfig> list = appConfigService.getThirdConfigListByThirdType(tenantId);
         //钉钉是否已配置

+ 2 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepart.java

@@ -74,6 +74,8 @@ public class SysDepart implements Serializable {
 	private String delFlag;
 	/**对接企业微信的ID*/
 	private String qywxIdentifier;
+	/**对接钉钉的部门ID*/
+	private String dingIdentifier;
 	/**创建人*/
 	private String createBy;
 	/**创建日期*/

+ 6 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysLog.java

@@ -108,6 +108,12 @@ public class SysLog implements Serializable {
 	 */
 	@Dict(dicCode = "operate_type")
 	private Integer operateType;
+	
+	/**
+	 * 客户终端类型 pc:电脑端 app:手机端 h5:移动网页端
+	 */
+	@Dict(dicCode = "client_type")
+	private String clientType;
 
 	/**
 	 * 租户ID

+ 10 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysAnnouncementMapper.java

@@ -26,7 +26,16 @@ public interface SysAnnouncementMapper extends BaseMapper<SysAnnouncement> {
      * @param msgCategory 消息类型
      * @return
      */
-	List<SysAnnouncement> querySysCementListByUserId(Page<SysAnnouncement> page, @Param("userId")String userId,@Param("msgCategory")String msgCategory);
+	List<SysAnnouncement> querySysCementListByUserId(Page<SysAnnouncement> page, @Param("userId")String userId,@Param("msgCategory")String msgCategory,
+                                                     @Param("tenantId")Integer tenantId, @Param("beginDate")Date beginDate);
+
+    /**
+     * 获取用户未读消息数量
+     *
+     * @param userId 用户id
+     * @return
+     */
+    Integer getUnreadMessageCountByUserId(@Param("userId") String userId, @Param("beginDate") Date beginDate);
 
     /**
      * 分页查询全部消息列表

+ 8 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDepartMapper.java

@@ -40,6 +40,14 @@ public interface SysDepartMapper extends BaseMapper<SysDepart> {
 	 * @return
 	 */
 	public List<SysDepart> queryDepartsByUsername(@Param("username") String username);
+	
+	/**
+	 * 根据用户名查询部门
+	 *
+	 * @param userId
+	 * @return
+	 */
+	public List<String> queryDepartsByUserId(@Param("userId") String userId);
 
     /**
      * 通过部门编码获取部门id

+ 8 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysPackPermissionMapper.java

@@ -20,4 +20,12 @@ public interface SysPackPermissionMapper extends BaseMapper<SysPackPermission> {
      * @return
      */
     List<String> getPermissionsByPackId(@Param("packId") String packId);
+
+    /**
+     * 删除产品包对应的菜单权限
+     *
+     * @param tenantIdList
+     */
+    void deletePackPermByTenantIds(@Param("tenantIdList") List<Integer> tenantIdList);
+    
 }

+ 10 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java

@@ -37,7 +37,16 @@ public interface SysRoleMapper extends BaseMapper<SysRole> {
      */
     @InterceptorIgnore(tenantLine = "true")
     SysRole getRoleNoTenant(@Param("roleCode") String roleCode);
-    
+
+    /**
+     * 根据用户id查询用户拥有的角色Code
+     *
+     * @param userId
+     * @param tenantId
+     * @return
+     */
+    List<SysRole> getRoleCodeListByUserId(@Param("userId") String userId, @Param("tenantId") Integer tenantId);
+
     /**
      * 删除角色与用户关系
      * @Author scott

+ 7 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysTenantMapper.java

@@ -127,4 +127,11 @@ public interface SysTenantMapper extends BaseMapper<SysTenant> {
      */
     @Select("select count(1) from sys_tenant where id = #{tenantId} and del_flag = 0")
     Long tenantIzExist(@Param("tenantId") Integer tenantId);
+
+    /**
+     * 根据用户id获取租户
+     * @param userId
+     * @return
+     */
+    List<SysTenant> getTenantListByUserId(@Param("userId") String userId);
 }

+ 6 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysTenantPackMapper.java

@@ -14,4 +14,10 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  */
 public interface SysTenantPackMapper extends BaseMapper<SysTenantPack> {
 
+    /**
+     * 删除租户产品包
+     *
+     * @param tenantIdList
+     */
+    void deletePackByTenantIds(@Param("tenantIdList") List<Integer> tenantIdList);
 }

+ 13 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysTenantPackUserMapper.java

@@ -31,5 +31,17 @@ public interface SysTenantPackUserMapper extends BaseMapper<SysTenantPackUser> {
      * @param tenantId
      * @return
      */
-    Long izHaveBuyAuth(@Param("userId") String userId, @Param("tenantId") String tenantId);
+    Long izHaveBuyAuth(@Param("userId") String userId, @Param("tenantId") Integer tenantId);
+
+    /**
+     * 根据租户id 删除租户产品包下的 用户
+     * @param tenantId
+     */
+    void deletePackUserByTenantId(@Param("tenantId") Integer tenantId, @Param("userIds") List<String> userIds);
+
+    /**
+     * 根据多个租户id 删除租户产品包下的 用户
+     * @param
+     */
+    void deletePackUserByTenantIds(@Param("tenantIds") List<Integer> tenantIds);
 }

+ 17 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 import org.jeecg.modules.system.entity.SysUser;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.jeecg.modules.system.model.SysUserSysDepartModel;
@@ -27,6 +28,13 @@ public interface SysUserMapper extends BaseMapper<SysUser> {
 	 * @return
 	 */
 	public SysUser getUserByName(@Param("username") String username);
+	
+	/**
+	  * 通过用户账号查询用户Id
+	 * @param username
+	 * @return
+	 */
+	public String getUserIdByName(@Param("username") String username);
 
 	/**
 	 *  根据部门Id查询用户信息
@@ -205,4 +213,13 @@ public interface SysUserMapper extends BaseMapper<SysUser> {
 	 * @return
 	 */
 	List<SysUser> getUserByDepartsTenantId(@Param("departIds") List<String> departIds,@Param("tenantId") Integer tenantId);
+
+	/**
+	 * 根据用户名和手机号获取用户
+	 * @param phone
+	 * @param username
+	 * @return
+	 */
+	@Select("select id,phone from sys_user where phone = #{phone} and username = #{username}")
+    SysUser getUserByNameAndPhone(@Param("phone") String phone, @Param("username") String username);
 }

+ 8 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserRoleMapper.java

@@ -23,6 +23,14 @@ public interface SysUserRoleMapper extends BaseMapper<SysUserRole> {
      */
 	@Select("select role_code from sys_role where id in (select role_id from sys_user_role where user_id = (select id from sys_user where username=#{username}))")
 	List<String> getRoleByUserName(@Param("username") String username);
+	
+    /**
+     * 通过用户账号查询角色集合
+     * @param userId 用户id
+     * @return List<String>
+     */
+	@Select("select role_code from sys_role where id in (select role_id from sys_user_role where user_id = #{userId})")
+	List<String> getRoleCodeByUserId(@Param("userId") String userId);
 
 	/**
      * 通过用户账号查询角色Id集合

+ 8 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserTenantMapper.java

@@ -166,4 +166,12 @@ public interface SysUserTenantMapper extends BaseMapper<SysUserTenant> {
      * @return
      */
     List<JwUserDepartVo> getUsersByTenantIdAndName(@Param("tenantId") Integer tenantId);
+
+    /**
+     * 根据多个用户id获取租户id
+     *
+     * @param userIds
+     * @return
+     */
+    List<Integer> getTenantIdsByUserIds(@Param("userIds") List<String> userIds);
 }

+ 11 - 2
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysAnnouncementMapper.xml

@@ -37,11 +37,19 @@
 	   where send_status = '1' 
 	   and del_flag = '0' 
 	   and msg_category = #{msgCategory} 
-	   and id IN ( select annt_id from sys_announcement_send where user_id = #{userId} and read_flag = 0)
+	   and create_time &gt;= #{beginDate}
+		<if test="tenantId!=null and tenantId != 0">
+			and tenant_id = #{tenantId}
+		</if>
+	   and id IN ( select annt_id from sys_announcement_send where user_id = #{userId} and read_flag = 0 and create_time &gt;= #{beginDate})
 	   order by create_time DESC
 	</select>
 
-
+	<!-- 获取用户未读消息数量 -->
+	<select id="getUnreadMessageCountByUserId" resultType="java.lang.Integer">
+		select count(1) from sys_announcement_send where user_id = #{userId} and read_flag = 0 and create_time &gt;= #{beginDate}
+	</select>
+	
 	<!-- 查询消息记录 -->
 	<select id="queryAllMessageList" resultMap="SysAnnouncement">
 	   select
@@ -72,6 +80,7 @@
 	
 		<if test="beginDate!=null">
 			and a.create_time &gt;= #{beginDate}
+			and b.create_time &gt;= #{beginDate}
 		</if>
 		<if test="endDate!=null">
 			and a.create_time &lt;= #{endDate}

+ 11 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDepartMapper.xml

@@ -20,6 +20,17 @@
             )
         )
     </select>
+    
+    <!-- 根据username查询所拥有的部门 -->
+    <select id="queryDepartsByUserId" parameterType="String" resultType="java.lang.String">
+        SELECT id
+        FROM sys_depart
+        WHERE id IN (
+            SELECT dep_id
+            FROM sys_user_depart
+            WHERE user_id = #{userId}
+        )
+    </select>
 
     <!-- 根据部门Id查询,当前和下级所有部门IDS -->
     <select id="getSubDepIdsByDepId" resultType="java.lang.String">

+ 11 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysPackPermissionMapper.xml

@@ -7,5 +7,15 @@
         where
         pack_id = #{packId}
     </select>
-    
+
+    <!--删除产品包对应的菜单权限-->
+    <delete id="deletePackPermByTenantIds">
+        delete from sys_tenant_pack_perms
+        where pack_id in(
+            select id from sys_tenant_pack where tenant_id in
+            <foreach collection="tenantIdList" index="index" item="tenantId" open="(" separator="," close=")">
+                #{tenantId}
+            </foreach>
+        )
+    </delete>
 </mapper>

+ 1 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysPermissionMapper.xml

@@ -136,6 +136,7 @@
 				SELECT distinct a.permission_id
 				FROM sys_tenant_pack_perms a
 				INNER JOIN sys_tenant_pack b ON a.pack_id = b.id AND b.STATUS = '1'
+				INNER JOIN sys_tenant st ON st.id = b.tenant_id and st.del_flag = 0
 				INNER JOIN sys_tenant_pack_user c ON c.pack_id = b.id AND c.STATUS = '1' AND c.user_id = #{userId,jdbcType=VARCHAR}
 			)
 			and p.del_flag = 0

+ 10 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml

@@ -20,5 +20,14 @@
         SELECT * from sys_role
         WHERE role_code = #{roleCode}
     </select>
-    
+
+    <!-- 根据用户id查询用户拥有的角色 -->
+    <select id="getRoleCodeListByUserId" resultType="org.jeecg.modules.system.entity.SysRole">
+        SELECT id, role_code from sys_role
+        WHERE id in (SELECT role_id from sys_user_role WHERE user_id = #{userId})
+        <if test="tenantId != null">
+            AND tenant_id = #{tenantId}
+        </if>
+    </select>
+
 </mapper>

+ 7 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysTenantMapper.xml

@@ -132,5 +132,12 @@
         and a.tenant_id = #{tenantId}
         and b.user_id = #{userId}
     </select>
+    
+    <!--根据用户id获取租户信息-->
+    <select id="getTenantListByUserId" resultType="org.jeecg.modules.system.entity.SysTenant">
+        SELECT st.id,st.name FROM sys_tenant st 
+        LEFT JOIN sys_user_tenant sut on st.id= sut.tenant_id and st.status = 1 and sut.status='1'
+        WHERE sut.user_id = #{userId}
+    </select>
 
 </mapper>

+ 0 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysTenantPackMapper.xml


この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません