From a3695151dcac51ea21256720bbf4006a79128a90 Mon Sep 17 00:00:00 2001 From: zhangdaiscott Date: Fri, 13 Aug 2021 15:27:30 +0800 Subject: [PATCH] =?UTF-8?q?JeecgBoot=202.4.6=E7=89=88=E6=9C=AC=E5=8F=91?= =?UTF-8?q?=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jeecg-boot/README.md | 8 +- .../jeecg-system-cloud-api/pom.xml | 2 +- .../jeecg/common/bpm/api/IBpmBaseExtAPI.java | 89 ++++++ .../factory/BpmBaseExtAPIFallbackFactory.java | 18 ++ .../api/fallback/BpmBaseExtAPIFallback.java | 42 +++ .../common/online/api/IOnlineBaseExtAPI.java | 72 +++++ .../OnlineBaseExtAPIFallbackFactory.java | 17 ++ .../fallback/OnlineBaseExtAPIFallback.java | 51 ++++ .../jeecg/common/system/api/ISysBaseAPI.java | 103 ++++++- .../api/fallback/SysBaseAPIFallback.java | 46 ++++ .../java/org/jeecg/config/FeignConfig.java | 43 +-- .../jeecg-system-local-api/pom.xml | 2 +- .../jeecg/common/bpm/api/IBpmBaseExtAPI.java | 55 ++++ .../common/online/api/IOnlineBaseExtAPI.java | 61 ++++ .../jeecg/common/system/api/ISysBaseAPI.java | 44 ++- .../jeecg-boot-base-api/pom.xml | 2 +- .../jeecg-boot-base-core/pom.xml | 9 +- .../java/org/jeecg/common/api/CommonAPI.java | 26 ++ .../org/jeecg/common/aspect/DictAspect.java | 224 ++++++++++++++- .../common/constant/DataBaseConstant.java | 14 +- .../common/constant/ServiceNameConstants.java | 1 + .../constant/enums/RoleIndexConfigEnum.java | 82 ++++++ .../common/es/JeecgElasticsearchTemplate.java | 25 +- .../common/system/query/QueryCondition.java | 16 +- .../common/system/query/QueryGenerator.java | 93 +++++-- .../jeecg/common/system/vo/DictModelMany.java | 18 ++ .../system/vo/DynamicDataSourceModel.java | 10 +- .../org/jeecg/common/util/CommonUtils.java | 58 +++- .../java/org/jeecg/common/util/DateUtils.java | 2 +- .../java/org/jeecg/common/util/MinioUtil.java | 4 + .../jeecg/common/util/PathMatcherUtil.java | 4 +- .../org/jeecg/common/util/ReflectHelper.java | 17 ++ .../common/util/dynamic/db/DbTypeUtils.java | 39 +++ .../common/util/dynamic/db/DynamicDBUtil.java | 3 +- .../common/util/dynamic/db/SqlUtils.java | 213 -------------- .../common/util/filter/FileTypeFilter.java | 166 +++++++++++ .../jeecg/common/util/oss/OssBootUtil.java | 7 + .../common/util/security/SecurityTools.java | 5 +- .../util/security/entity/SecurityResp.java | 2 +- .../java/org/jeecg/config/DruidConfig.java | 14 +- .../java/org/jeecg/config/StaticConfig.java | 6 + .../java/org/jeecg/config/Swagger2Config.java | 3 +- .../config/mybatis/JeecgTenantParser.java | 260 +++++++++--------- .../config/mybatis/MybatisPlusConfig.java | 142 ---------- .../config/mybatis/MybatisPlusSaasConfig.java | 88 ++++++ .../org/jeecg/config/shiro/ShiroConfig.java | 19 +- .../org/jeecg/config/shiro/ShiroRealm.java | 13 +- .../jeecg/config/shiro/filters/JwtFilter.java | 7 +- .../sign/interceptor/SignAuthInterceptor.java | 15 +- .../BodyReaderHttpServletRequestWrapper.java | 4 +- .../org/jeecg/config/sign/util/HttpUtils.java | 14 +- .../org/jeecg/config/sign/util/SignUtil.java | 17 +- .../modules/base/mapper/BaseCommonMapper.java | 5 +- .../jeecg-boot-base-tools/pom.xml | 8 +- .../jeecg/common/constant/CacheConstant.java | 7 +- jeecg-boot/jeecg-boot-base/pom.xml | 2 +- jeecg-boot/jeecg-boot-module-demo/pom.xml | 2 +- .../modules/demo/test/entity/JeecgDemo.java | 3 + .../demo/test/mapper/xml/JeecgDemoMapper.xml | 4 +- .../jeecg-boot-module-system/Dockerfile | 4 +- jeecg-boot/jeecg-boot-module-system/pom.xml | 37 ++- .../config/init/CodeGenerateDbConfig.java | 1 + .../api/controller/SystemAPIController.java | 225 ++++++++++----- .../service/impl/QuartzJobServiceImpl.java | 6 + .../system/controller/CommonController.java | 2 +- .../system/controller/LoginController.java | 36 ++- .../controller/SysAnnouncementController.java | 9 + .../controller/SysDepartController.java | 10 +- .../system/controller/SysDictController.java | 68 ++--- .../controller/SysDictItemController.java | 8 +- .../controller/SysPermissionController.java | 19 +- .../controller/SysTenantController.java | 28 +- .../system/controller/SysUserController.java | 94 ++++--- ...ller.java => SysUserOnlineController.java} | 38 +-- .../controller/ThirdLoginController.java | 171 +++++++++--- .../modules/system/mapper/SysDictMapper.java | 48 +++- .../modules/system/mapper/SysUserMapper.java | 1 + .../system/mapper/xml/SysDictMapper.xml | 56 +++- .../system/mapper/xml/SysLogMapper.xml | 14 +- .../mapper/xml/SysThirdAccountMapper.xml | 2 +- .../system/service/ISysDictService.java | 34 +++ .../system/service/ISysTenantService.java | 27 ++ .../service/ISysThirdAccountService.java | 8 + .../system/service/impl/SysBaseApiImpl.java | 85 ++++++ .../service/impl/SysDictServiceImpl.java | 36 +++ .../service/impl/SysLogServiceImpl.java | 5 +- .../service/impl/SysTenantServiceImpl.java | 45 ++- .../impl/SysThirdAccountServiceImpl.java | 15 + .../impl/ThirdAppDingtalkServiceImpl.java | 112 +++++++- .../ThirdAppWechatEnterpriseServiceImpl.java | 97 ++++++- .../jeecg/modules/system/util/XSSUtils.java | 44 +++ .../modules/system/vo/SysUserOnlineVO.java | 62 +++++ .../src/main/resources/application-dev.yml | 21 +- .../src/main/resources/application-prod.yml | 19 +- .../src/main/resources/application-test.yml | 15 +- .../src/main/resources/banner.txt | 2 +- .../entity/${entityName}.javai | 2 +- .../${entityPackage}/entity/[1-n]Entity.javai | 2 +- .../java/org/jeecg/SecurityToolsTest.java | 6 +- .../jeecg-boot-starter-cloud/pom.xml | 2 +- .../java/org/jeecg/config/FeignConfig.java | 4 +- .../jeecg-boot-starter-job/pom.xml | 2 +- .../jeecg-boot-starter-lock/pom.xml | 2 +- .../jeecg-boot-starter-rabbitmq/pom.xml | 2 +- jeecg-boot/jeecg-boot-starter/pom.xml | 2 +- .../jeecg-cloud-gateway/Dockerfile | 4 +- .../jeecg-cloud-gateway/README.md | 7 + .../jeecg-cloud-gateway/pom.xml | 15 +- .../filter/SentinelFilterContextConfig.java | 24 ++ .../handler/MySwaggerResourceProvider.java | 3 + .../handler/SentinelBlockRequestHandler.java | 38 +++ .../src/main/resources/application.yml | 7 + .../jeecg-cloud-monitor/pom.xml | 2 +- .../jeecg-cloud-nacos/Dockerfile | 4 +- .../jeecg-cloud-nacos/pom.xml | 6 +- .../alibaba/nacos/JeecgNacosApplication.java | 3 + .../src/main/resources/application.yml | 1 - .../jeecg-cloud-sentinel/pom.xml | 110 ++++++++ .../JeecgSentinelDashboardApplication.java | 49 ++++ .../src/main/resources/application.properties | 28 ++ .../jeecg-cloud-system-start/Dockerfile | 4 +- .../jeecg-cloud-system-start/pom.xml | 2 +- .../jeecg-cloud-xxljob/Dockerfile | 4 +- .../jeecg-cloud-xxljob/pom.xml | 2 +- jeecg-boot/jeecg-cloud-module/pom.xml | 7 +- jeecg-boot/pom.xml | 40 +-- 126 files changed, 3238 insertions(+), 976 deletions(-) create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/factory/BpmBaseExtAPIFallbackFactory.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/fallback/BpmBaseExtAPIFallback.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/factory/OnlineBaseExtAPIFallbackFactory.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/fallback/OnlineBaseExtAPIFallback.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/RoleIndexConfigEnum.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DictModelMany.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java delete mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/SqlUtils.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/FileTypeFilter.java delete mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusConfig.java create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java rename jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/{SysOnlineController.java => SysUserOnlineController.java} (83%) create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/XSSUtils.java create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/vo/SysUserOnlineVO.java create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/README.md create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/filter/SentinelFilterContextConfig.java create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/handler/SentinelBlockRequestHandler.java create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/pom.xml create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/src/main/java/com/alibaba/csp/sentinel/dashboard/JeecgSentinelDashboardApplication.java create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/src/main/resources/application.properties diff --git a/jeecg-boot/README.md b/jeecg-boot/README.md index 3af418a1..e203d810 100644 --- a/jeecg-boot/README.md +++ b/jeecg-boot/README.md @@ -1,13 +1,13 @@ Jeecg-Boot 低代码开发平台 =============== -当前最新版本: 2.4.5(发布日期:20210607) +当前最新版本: 2.4.6(发布日期:20210813) ## 后端技术架构 - 基础框架:Spring Boot 2.3.5.RELEASE -- 持久层框架:Mybatis-plus 3.4.1 +- 持久层框架:Mybatis-plus 3.4.3.1 - 安全框架:Apache Shiro 1.7.0,Jwt 3.11.0 @@ -29,7 +29,7 @@ Jeecg-Boot 低代码开发平台 - 依赖管理:Maven -- 数据库:MySQL5.7+ & Oracle 11g +- 数据库:MySQL5.7+ & Oracle 11g & SqlServer & postgresql - 缓存:Redis @@ -43,7 +43,7 @@ Jeecg-Boot 低代码开发平台 - 常见问题: [http://jeecg.com/doc/qa](http://jeecg.com/doc/qa) -- QQ交流群 : ③816531124、①284271917、②769925425 +- QQ交流群 : ④774126647、③816531124、①284271917、②769925425 ## 专项文档 diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/pom.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/pom.xml index 3ccebddf..d5d34a21 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/pom.xml +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/pom.xml @@ -5,7 +5,7 @@ jeecg-boot-base-api org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java new file mode 100644 index 00000000..e951bd61 --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java @@ -0,0 +1,89 @@ +package org.jeecg.common.bpm.api; + +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.constant.ServiceNameConstants; +import org.jeecg.common.online.api.factory.OnlineBaseExtAPIFallbackFactory; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * 流程接口 + * + * @author scott + */ +@Component +@FeignClient(contextId = "bpmBaseRemoteApi", value = ServiceNameConstants.SYSTEM_SERVICE, + fallbackFactory = OnlineBaseExtAPIFallbackFactory.class) +public interface IBpmBaseExtAPI { + /** + * 23. 流程提交接口(online,自定义开发) + * + * @param flowCode + * 流程业务关联 例如:joa_leave_01 + * @param id + * 表单业务数据data id + * @param formUrl + * 流程审批时附件页面默认展示的PC端表单组件(地址) + * @param formUrlMobile + * 流程审批时附件页面默认展示的移动端表单组件(地址) + * @param username + * 流程发起人账号 + * @param jsonData + * Json串,额外扩展的流程变量值 【非必填】 + * @return + * @throws Exception + */ + @PostMapping(value = "/act/process/extActProcess/startMutilProcess") + Result startMutilProcess(@RequestParam("flowCode") String flowCode, @RequestParam("id") String id, + @RequestParam("formUrl") String formUrl, @RequestParam("formUrlMobile") String formUrlMobile, + @RequestParam("username") String username, @RequestParam("jsonData") String jsonData) throws Exception; + + /** + * 24. 流程提交接口(自定义表单设计器) + * + * @param flowCode + * 流程业务关联 例如:joa_leave_01 + * @param id + * 表单业务数据data id + * @param formUrl + * 流程审批时附件页面默认展示的PC端表单组件(地址) + * @param formUrlMobile + * 流程审批时附件页面默认展示的移动端表单组件(地址) + * @param username + * 流程发起人账号 + * @param jsonData + * Json串,额外扩展的流程变量值 【非必填】 + * @return + * @throws Exception + */ + @PostMapping(value = "/act/process/extActProcess/startDesFormMutilProcess") + Result startDesFormMutilProcess(@RequestParam("flowCode") String flowCode, @RequestParam("id") String id, + @RequestParam("formUrl") String formUrl, @RequestParam("formUrlMobile") String formUrlMobile, + @RequestParam("username") String username, @RequestParam("jsonData") String jsonData) throws Exception; + + /** + * 25. 保存流程草稿箱接口(自定义开发表单、online表单) + * + * @param flowCode + * 流程业务关联 例如:joa_leave_01 + * @param id + * 表单业务数据data id + * @param formUrl + * 流程审批时附件页面默认展示的PC端表单组件(地址) 【非必填】 + * @param formUrlMobile + * 流程审批时附件页面默认展示的移动端表单组件(地址) 【非必填】 + * @param username + * 流程发起人账号 + * @param jsonData + * Json串,额外扩展的流程变量值 【非必填】 + * @return + * @throws Exception + */ + @PostMapping(value = "/act/process/extActProcess/saveMutilProcessDraft") + Result saveMutilProcessDraft(@RequestParam("flowCode") String flowCode, @RequestParam("id") String id, + @RequestParam("formUrl") String formUrl, @RequestParam("formUrlMobile") String formUrlMobile, + @RequestParam("username") String username, @RequestParam("jsonData") String jsonData) throws Exception; + +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/factory/BpmBaseExtAPIFallbackFactory.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/factory/BpmBaseExtAPIFallbackFactory.java new file mode 100644 index 00000000..6546be5a --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/factory/BpmBaseExtAPIFallbackFactory.java @@ -0,0 +1,18 @@ +package org.jeecg.common.bpm.api.factory; + +import org.jeecg.common.bpm.api.IBpmBaseExtAPI; +import org.jeecg.common.bpm.api.fallback.BpmBaseExtAPIFallback; +import org.springframework.stereotype.Component; + +import feign.hystrix.FallbackFactory; + +@Component +public class BpmBaseExtAPIFallbackFactory implements FallbackFactory { + + @Override + public IBpmBaseExtAPI create(Throwable throwable) { + BpmBaseExtAPIFallback fallback = new BpmBaseExtAPIFallback(); + fallback.setCause(throwable); + return fallback; + } +} \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/fallback/BpmBaseExtAPIFallback.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/fallback/BpmBaseExtAPIFallback.java new file mode 100644 index 00000000..b0ddadcd --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/fallback/BpmBaseExtAPIFallback.java @@ -0,0 +1,42 @@ +package org.jeecg.common.bpm.api.fallback; + +import java.util.List; +import java.util.Map; + +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.bpm.api.IBpmBaseExtAPI; +import org.jeecg.common.online.api.IOnlineBaseExtAPI; +import org.jeecg.common.system.vo.DictModel; + +import com.alibaba.fastjson.JSONObject; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +/** + * 进入fallback的方法 检查是否token未设置 + */ +@Slf4j +public class BpmBaseExtAPIFallback implements IBpmBaseExtAPI { + + @Setter + private Throwable cause; + + @Override + public Result startMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile, + String username, String jsonData) throws Exception { + return null; + } + + @Override + public Result startDesFormMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile, + String username, String jsonData) throws Exception { + return null; + } + + @Override + public Result saveMutilProcessDraft(String flowCode, String id, String formUrl, String formUrlMobile, + String username, String jsonData) throws Exception { + return null; + } +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java new file mode 100644 index 00000000..f3e0751b --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java @@ -0,0 +1,72 @@ +package org.jeecg.common.online.api; + +import com.alibaba.fastjson.JSONObject; +import org.jeecg.common.constant.ServiceNameConstants; +import org.jeecg.common.online.api.factory.OnlineBaseExtAPIFallbackFactory; +import org.jeecg.common.system.vo.DictModel; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 【Online】Feign API接口 + */ +@Component +@FeignClient(contextId = "onlineBaseRemoteApi", value = ServiceNameConstants.SYSTEM_ONLINE, fallbackFactory = OnlineBaseExtAPIFallbackFactory.class) +public interface IOnlineBaseExtAPI { + + /** + * 【Online】 表单设计器专用:同步新增 + */ + @PostMapping(value = "/online/api/cgform/crazyForm/{name}") + String cgformPostCrazyForm(@PathVariable("name") String tableName, @RequestBody JSONObject jsonObject) throws Exception; + + /** + * 【Online】 表单设计器专用:同步编辑 + */ + @PutMapping(value = "/online/api/cgform/crazyForm/{name}") + String cgformPutCrazyForm(@PathVariable("name") String tableName, @RequestBody JSONObject jsonObject) throws Exception; + + /** + * 通过online表名查询数据,同时查询出子表的数据 + * + * @param tableName online表名 + * @param dataIds online数据ID + * @return + */ + @GetMapping(value = "/online/api/cgform/queryAllDataByTableName") + JSONObject cgformQueryAllDataByTableName(@RequestParam("tableName") String tableName, @RequestParam("dataIds") String dataIds); + + /** + * online表单删除数据 + * + * @param cgformCode Online表单code + * @param dataIds 数据ID,可逗号分割 + * @return + */ + @DeleteMapping("/online/api/cgform/cgformDeleteDataByCode") + String cgformDeleteDataByCode(@RequestParam("cgformCode") String cgformCode, @RequestParam("dataIds") String dataIds); + + /** + * 【cgreport】通过 head code 获取 sql语句,并执行该语句返回查询数据 + * + * @param code 报表Code,如果没传ID就通过code查 + * @param forceKey + * @param dataList + * @return + */ + @GetMapping("/online/api/cgreportGetData") + Map cgreportGetData(@RequestParam("code") String code, @RequestParam("forceKey") String forceKey, @RequestParam("dataList") String dataList); + + /** + * 【cgreport】对 cgreportGetData 的返回值做优化,封装 DictModel 集合 + * + * @return + */ + @GetMapping("/online/api/cgreportGetDataPackage") + List cgreportGetDataPackage(@RequestParam("code") String code, @RequestParam("dictText") String dictText, @RequestParam("dictCode") String dictCode, @RequestParam("dataList") String dataList); + +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/factory/OnlineBaseExtAPIFallbackFactory.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/factory/OnlineBaseExtAPIFallbackFactory.java new file mode 100644 index 00000000..491297c5 --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/factory/OnlineBaseExtAPIFallbackFactory.java @@ -0,0 +1,17 @@ +package org.jeecg.common.online.api.factory; + +import feign.hystrix.FallbackFactory; +import org.jeecg.common.online.api.IOnlineBaseExtAPI; +import org.jeecg.common.online.api.fallback.OnlineBaseExtAPIFallback; +import org.springframework.stereotype.Component; + +@Component +public class OnlineBaseExtAPIFallbackFactory implements FallbackFactory { + + @Override + public IOnlineBaseExtAPI create(Throwable throwable) { + OnlineBaseExtAPIFallback fallback = new OnlineBaseExtAPIFallback(); + fallback.setCause(throwable); + return fallback; + } +} \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/fallback/OnlineBaseExtAPIFallback.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/fallback/OnlineBaseExtAPIFallback.java new file mode 100644 index 00000000..51050ece --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/fallback/OnlineBaseExtAPIFallback.java @@ -0,0 +1,51 @@ +package org.jeecg.common.online.api.fallback; + +import com.alibaba.fastjson.JSONObject; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.online.api.IOnlineBaseExtAPI; +import org.jeecg.common.system.vo.DictModel; + +import java.util.List; +import java.util.Map; + +/** + * 进入fallback的方法 检查是否token未设置 + */ +@Slf4j +public class OnlineBaseExtAPIFallback implements IOnlineBaseExtAPI { + + @Setter + private Throwable cause; + + @Override + public String cgformPostCrazyForm(String tableName, JSONObject jsonObject) { + return null; + } + + @Override + public String cgformPutCrazyForm(String tableName, JSONObject jsonObject) { + return null; + } + + @Override + public JSONObject cgformQueryAllDataByTableName(String tableName, String dataIds) { + return null; + } + + @Override + public String cgformDeleteDataByCode(String cgformCode, String dataIds) { + return null; + } + + @Override + public Map cgreportGetData(String code, String forceKey, String dataList) { + return null; + } + + @Override + public List cgreportGetDataPackage(String code, String dictText, String dictCode, String dataList) { + return null; + } + +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java index 565ebf1c..24f6d003 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java @@ -9,10 +9,7 @@ import org.jeecg.common.system.api.factory.SysBaseAPIFallbackFactory; import org.jeecg.common.system.vo.*; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; @@ -109,6 +106,14 @@ public interface ISysBaseAPI extends CommonAPI { @GetMapping("/sys/api/queryDictItemsByCode") List queryDictItemsByCode(@RequestParam("code") String code); + /** + * 获取有效的数据字典项 + * @param code + * @return + */ + @GetMapping("/sys/api/queryEnableDictItemsByCode") + public List queryEnableDictItemsByCode(@RequestParam("code") String code); + /** 11查询所有的父级字典,按照create_time排序 */ @GetMapping("/sys/api/queryAllDict") List queryAllDict(); @@ -385,30 +390,31 @@ public interface ISysBaseAPI extends CommonAPI { * @return */ @GetMapping("/sys/api/queryUsersByUsernames") - List queryUsersByUsernames(String usernames); + List queryUsersByUsernames(@RequestParam("usernames") String usernames); /** * 37根据多个用户ID(逗号分隔),查询返回多个用户信息 * @param ids * @return */ - @GetMapping("/sys/api/queryUsersByIds") - List queryUsersByIds(String ids); + @RequestMapping("/sys/api/queryUsersByIds") + List queryUsersByIds(@RequestParam("ids") String ids); /** * 38根据多个部门编码(逗号分隔),查询返回多个部门信息 * @param orgCodes * @return */ - @GetMapping("/sys/api/queryDepartsByOrgcodes") - List queryDepartsByOrgcodes(String orgCodes); + @RequestMapping("/sys/api/queryDepartsByOrgcodes") + List queryDepartsByOrgcodes(@RequestParam("orgCodes") String orgCodes); + /** * 39根据多个部门编码(逗号分隔),查询返回多个部门信息 * @param ids * @return */ @GetMapping("/sys/api/queryDepartsByOrgIds") - List queryDepartsByOrgIds(String ids); + List queryDepartsByOrgIds(@RequestParam("ids") String ids); /** * 40发送邮件消息 @@ -424,4 +430,81 @@ public interface ISysBaseAPI extends CommonAPI { */ @GetMapping("/sys/api/getDeptUserByOrgCode") List getDeptUserByOrgCode(@RequestParam("orgCode")String orgCode); + + /** + * 42 查询分类字典翻译 + */ + @GetMapping("/sys/api/loadCategoryDictItem") + List loadCategoryDictItem(@RequestParam("ids") String ids); + + /** + * 43 根据字典code加载字典text + * + * @param dictCode 顺序:tableName,text,code + * @param keys 要查询的key + * @return + */ + @GetMapping("/sys/api/loadDictItem") + List loadDictItem(@RequestParam("dictCode") String dictCode, @RequestParam("keys") String keys); + + /** + * 44 根据字典code查询字典项 + * + * @param dictCode 顺序:tableName,text,code + * @param dictCode 要查询的key + * @return + */ + @GetMapping("/sys/api/getDictItems") + List getDictItems(@RequestParam("dictCode") String dictCode); + + /** + * 45 根据多个字典code查询多个字典项 + * + * @param dictCodeList + * @return key = dictCode ; value=对应的字典项 + */ + @RequestMapping("/sys/api/getManyDictItems") + Map> getManyDictItems(@RequestParam("dictCodeList") List dictCodeList); + + /** + * 46 【JSearchSelectTag下拉搜索组件专用接口】 + * 大数据量的字典表 走异步加载 即前端输入内容过滤数据 + * + * @param dictCode 字典code格式:table,text,code + * @param keyword 过滤关键字 + * @return + */ + @GetMapping("/sys/api/loadDictItemByKeyword") + List loadDictItemByKeyword(@RequestParam("dictCode") String dictCode, @RequestParam("keyword") String keyword, @RequestParam(value = "pageSize", required = false) Integer pageSize); + + /** + * 47 根据多个部门id(逗号分隔),查询返回多个部门信息 + * @param ids + * @return + */ + @GetMapping("/sys/api/queryDepartsByIds") + List queryDepartsByIds(@RequestParam("ids") String ids); + + /** + * 48 普通字典的翻译,根据多个dictCode和多条数据,多个以逗号分割 + * @param dictCodes + * @param keys + * @return + */ + @Override + @GetMapping("/sys/api/translateManyDict") + Map> translateManyDict(@RequestParam("dictCodes") String dictCodes, @RequestParam("keys") String keys); + + /** + * 49 字典表的 翻译,可批量 + * @param table + * @param text + * @param code + * @param keys 多个用逗号分割 + * @return + */ + @Override + @GetMapping("/sys/api/translateDictFromTableByKeys") + List translateDictFromTableByKeys(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("keys") String keys); + } diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java index ede60daf..45cc7de8 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java @@ -72,6 +72,11 @@ public class SysBaseAPIFallback implements ISysBaseAPI { return null; } + @Override + public List queryEnableDictItemsByCode(String code) { + return null; + } + @Override public List queryAllDict() { return null; @@ -255,6 +260,22 @@ public class SysBaseAPIFallback implements ISysBaseAPI { public List queryDepartsByOrgcodes(String orgCodes) { return null; } + + @Override + public List queryDepartsByIds(String ids) { + return null; + } + + @Override + public Map> translateManyDict(String dictCodes, String keys) { + return null; + } + + @Override + public List translateDictFromTableByKeys(String table, String text, String code, String keys) { + return null; + } + @Override public void sendEmailMsg(String email,String title,String content) { @@ -269,4 +290,29 @@ public class SysBaseAPIFallback implements ISysBaseAPI { public List queryDepartsByOrgIds(String ids) { return null; } + + @Override + public List loadCategoryDictItem(String ids) { + return null; + } + + @Override + public List loadDictItem(String dictCode, String keys) { + return null; + } + + @Override + public List getDictItems(String dictCode) { + return null; + } + + @Override + public Map> getManyDictItems(List dictCodeList) { + return null; + } + + @Override + public List loadDictItemByKeyword(String dictCode, String keyword, Integer pageSize) { + return null; + } } diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/config/FeignConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/config/FeignConfig.java index a0572cd7..49e50031 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/config/FeignConfig.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/config/FeignConfig.java @@ -1,17 +1,13 @@ package org.jeecg.config; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.serializer.SerializerFeature; -import com.alibaba.fastjson.support.config.FastJsonConfig; -import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; -import com.alibaba.fastjson.support.springfox.SwaggerJsonSerializer; -import feign.Feign; -import feign.Logger; -import feign.RequestInterceptor; -import feign.codec.Decoder; -import feign.codec.Encoder; -import feign.form.spring.SpringFormEncoder; -import lombok.extern.slf4j.Slf4j; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.SortedMap; + +import javax.servlet.http.HttpServletRequest; + import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.util.DateUtils; import org.jeecg.common.util.PathMatcherUtil; @@ -33,12 +29,19 @@ import org.springframework.http.MediaType; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.SortedMap; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import com.alibaba.fastjson.support.springfox.SwaggerJsonSerializer; + +import feign.Feign; +import feign.Logger; +import feign.RequestInterceptor; +import feign.codec.Decoder; +import feign.codec.Encoder; +import feign.form.spring.SpringFormEncoder; +import lombok.extern.slf4j.Slf4j; @ConditionalOnClass(Feign.class) @AutoConfigureBefore(FeignAutoConfiguration.class) @@ -52,13 +55,13 @@ public class FeignConfig { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (null != attributes) { HttpServletRequest request = attributes.getRequest(); - log.info("Feign request: {}", request.getRequestURI()); + log.debug("Feign request: {}", request.getRequestURI()); // 将token信息放入header中 String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN); if(token==null || "".equals(token)){ token = request.getParameter("token"); } - log.info("Feign request token: {}", token); + log.debug("Feign request token: {}", token); requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token); //根据URL地址过滤请求 【字典表参数签名验证】 diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/pom.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/pom.xml index 65a4e37d..174fb92d 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/pom.xml +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/pom.xml @@ -5,7 +5,7 @@ jeecg-boot-base-api org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java new file mode 100644 index 00000000..c1db8aee --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java @@ -0,0 +1,55 @@ +package org.jeecg.common.bpm.api; + +import java.util.List; +import java.util.Map; + +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.system.vo.DictModel; + +import com.alibaba.fastjson.JSONObject; + +/** + * 流程接口 + * + * @author scott + */ +public interface IBpmBaseExtAPI { + /** + * 23. 流程提交接口(online,自定义开发) + * @param flowCode 流程业务关联 例如:joa_leave_01 + * @param id 表单业务数据data id + * @param formUrl 流程审批时附件页面默认展示的PC端表单组件(地址) + * @param formUrlMobile 流程审批时附件页面默认展示的移动端表单组件(地址) + * @param username 流程发起人账号 + * @param jsonData Json串,额外扩展的流程变量值 【非必填】 + * @return + * @throws Exception + */ + Result startMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile,String username, String jsonData) throws Exception; + + /** + * 24. 流程提交接口(自定义表单设计器) + * @param flowCode 流程业务关联 例如:joa_leave_01 + * @param id 表单业务数据data id + * @param formUrl 流程审批时附件页面默认展示的PC端表单组件(地址) + * @param formUrlMobile 流程审批时附件页面默认展示的移动端表单组件(地址) + * @param username 流程发起人账号 + * @param jsonData Json串,额外扩展的流程变量值 【非必填】 + * @return + * @throws Exception + */ + Result startDesFormMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile,String username,String jsonData) throws Exception; + /** + * 25. 保存流程草稿箱接口(自定义开发表单、online表单) + * @param flowCode 流程业务关联 例如:joa_leave_01 + * @param id 表单业务数据data id + * @param formUrl 流程审批时附件页面默认展示的PC端表单组件(地址) 【非必填】 + * @param formUrlMobile 流程审批时附件页面默认展示的移动端表单组件(地址) 【非必填】 + * @param username 流程发起人账号 + * @param jsonData Json串,额外扩展的流程变量值 【非必填】 + * @return + * @throws Exception + */ + Result saveMutilProcessDraft(String flowCode, String id, String formUrl, String formUrlMobile,String username,String jsonData) throws Exception; + +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java new file mode 100644 index 00000000..bda8bea8 --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java @@ -0,0 +1,61 @@ +package org.jeecg.common.online.api; + +import com.alibaba.fastjson.JSONObject; +import org.jeecg.common.system.vo.DictModel; + +import java.util.List; +import java.util.Map; + +/** + * 表单设计器【Online】翻译API接口 + * + * @author sunjianlei + */ +public interface IOnlineBaseExtAPI { + + /** + * 【Online】 表单设计器专用:同步新增 + */ + String cgformPostCrazyForm(String tableName, JSONObject jsonObject) throws Exception; + + /** + * 【Online】 表单设计器专用:同步编辑 + */ + String cgformPutCrazyForm(String tableName, JSONObject jsonObject) throws Exception; + + /** + * online表单删除数据 + * + * @param cgformCode Online表单code + * @param dataIds 数据ID,可逗号分割 + * @return + */ + String cgformDeleteDataByCode(String cgformCode, String dataIds); + + /** + * 通过online表名查询数据,同时查询出子表的数据 + * + * @param tableName online表名 + * @param dataIds online数据ID + * @return + */ + JSONObject cgformQueryAllDataByTableName(String tableName, String dataIds); + + /** + * 对 cgreportGetData 的返回值做优化,封装 DictModel 集合 + * + * @return + */ + List cgreportGetDataPackage(String code, String dictText, String dictCode, String dataList); + + /** + * 【cgreport】通过 head code 获取 sql语句,并执行该语句返回查询数据 + * + * @param code 报表Code,如果没传ID就通过code查 + * @param forceKey + * @param dataList + * @return + */ + Map cgreportGetData(String code, String forceKey, String dataList); + +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java index aacde42d..3d0c34a1 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java @@ -1,14 +1,11 @@ package org.jeecg.common.system.api; -import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.jeecg.common.api.CommonAPI; import org.jeecg.common.api.dto.OnlineAuthDTO; import org.jeecg.common.api.dto.message.*; import org.jeecg.common.system.vo.*; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; @@ -289,4 +286,45 @@ public interface ISysBaseAPI extends CommonAPI { * @param orgCode */ List getDeptUserByOrgCode(String orgCode); + + /** + * 查询分类字典翻译 + */ + List loadCategoryDictItem(String ids); + + /** + * 根据字典code加载字典text + * + * @param dictCode 顺序:tableName,text,code + * @param keys 要查询的key + * @return + */ + List loadDictItem(String dictCode, String keys); + + /** + * 根据字典code查询字典项 + * + * @param dictCode 顺序:tableName,text,code + * @param dictCode 要查询的key + * @return + */ + List getDictItems(String dictCode); + + /** + * 根据多个字典code查询多个字典项 + * @param dictCodeList + * @return key = dictCode ; value=对应的字典项 + */ + Map> getManyDictItems(List dictCodeList); + + /** + * 【JSearchSelectTag下拉搜索组件专用接口】 + * 大数据量的字典表 走异步加载 即前端输入内容过滤数据 + * + * @param dictCode 字典code格式:table,text,code + * @param keyword 过滤关键字 + * @return + */ + List loadDictItemByKeyword(String dictCode, String keyword, Integer pageSize); + } diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/pom.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/pom.xml index 4c9cb34d..a91aac5f 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/pom.xml +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/pom.xml @@ -5,7 +5,7 @@ jeecg-boot-base org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/pom.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/pom.xml index 13303ce0..5f860247 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/pom.xml +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/pom.xml @@ -4,7 +4,7 @@ org.jeecgframework.boot jeecg-boot-base - 2.4.5 + 2.4.6 4.0.0 @@ -14,7 +14,7 @@ aliyun aliyun Repository - http://maven.aliyun.com/nexus/content/groups/public + https://maven.aliyun.com/repository/public false @@ -22,7 +22,7 @@ jeecg jeecg Repository - http://maven.jeecg.org/nexus/content/repositories/jeecg + https://maven.jeecg.org/nexus/content/repositories/jeecg false @@ -114,9 +114,10 @@ org.jeecgframework.boot hibernate-re - 2.4.5-RC + 2.4.6-beta + mysql diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/CommonAPI.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/CommonAPI.java index 5a7665cd..b355910e 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/CommonAPI.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/CommonAPI.java @@ -3,6 +3,7 @@ package org.jeecg.common.api; import org.jeecg.common.system.vo.*; import java.util.List; +import java.util.Map; import java.util.Set; public interface CommonAPI { @@ -85,6 +86,13 @@ public interface CommonAPI { */ public List queryDictItemsByCode(String code); + /** + * 获取有效的数据字典项 + * @param code + * @return + */ + public List queryEnableDictItemsByCode(String code); + /** * 13获取表数据字典 * @param table @@ -94,4 +102,22 @@ public interface CommonAPI { */ List queryTableDictItemsByCode(String table, String text, String code); + /** + * 14 普通字典的翻译,根据多个dictCode和多条数据,多个以逗号分割 + * @param dictCodes 例如:user_status,sex + * @param keys 例如:1,2,0 + * @return + */ + Map> translateManyDict(String dictCodes, String keys); + + /** + * 15 字典表的 翻译,可批量 + * @param table + * @param text + * @param code + * @param keys 多个用逗号分割 + * @return + */ + List translateDictFromTableByKeys(String table, String text, String code, String keys); + } diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java index f07aefb3..be04c543 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java @@ -1,5 +1,6 @@ package org.jeecg.common.aspect; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.metadata.IPage; import com.fasterxml.jackson.annotation.JsonFormat; @@ -14,17 +15,17 @@ import org.jeecg.common.api.CommonAPI; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.Dict; import org.jeecg.common.constant.CommonConstant; -import org.jeecg.modules.base.service.BaseCommonService; +import org.jeecg.common.system.vo.DictModel; import org.jeecg.common.util.oConvertUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; + import java.lang.reflect.Field; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * @Description: 字典aop类 @@ -56,7 +57,7 @@ public class DictAspect { long start=System.currentTimeMillis(); this.parseDictText(result); long end=System.currentTimeMillis(); - log.debug("解析注入JSON数据 耗时"+(end-start)+"ms"); + log.debug("注入字典到JSON数据 耗时"+(end-start)+"ms"); return result; } @@ -86,6 +87,12 @@ public class DictAspect { if (result instanceof Result) { if (((Result) result).getResult() instanceof IPage) { List items = new ArrayList<>(); + + //step.1 筛选出加了 Dict 注解的字段列表 + List dictFieldList = new ArrayList<>(); + // 字典数据列表, key = 字典code,value=数据列表 + Map> dataListMap = new HashMap<>(); + for (Object record : ((IPage) ((Result) result).getResult()).getRecords()) { ObjectMapper mapper = new ObjectMapper(); String json="{}"; @@ -98,20 +105,28 @@ public class DictAspect { JSONObject item = JSONObject.parseObject(json); //update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------ //for (Field field : record.getClass().getDeclaredFields()) { + // 遍历所有字段,把字典Code取出来,放到 map 里 for (Field field : oConvertUtils.getAllFields(record)) { + String value = item.getString(field.getName()); + if (oConvertUtils.isEmpty(value)) { + continue; + } //update-end--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------ if (field.getAnnotation(Dict.class) != null) { + if (!dictFieldList.contains(field)) { + dictFieldList.add(field); + } String code = field.getAnnotation(Dict.class).dicCode(); String text = field.getAnnotation(Dict.class).dicText(); String table = field.getAnnotation(Dict.class).dictTable(); - String key = String.valueOf(item.get(field.getName())); - //翻译字典值对应的txt - String textValue = translateDictValue(code, text, table, key); - - log.debug(" 字典Val : "+ textValue); - log.debug(" __翻译字典字段__ "+field.getName() + CommonConstant.DICT_TEXT_SUFFIX+": "+ textValue); - item.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue); + List dataList; + String dictCode = code; + if (!StringUtils.isEmpty(table)) { + dictCode = String.format("%s,%s,%s", table, text, code); + } + dataList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>()); + this.listAddAllDeduplicate(dataList, Arrays.asList(value.split(","))); } //date类型默认转换string格式化日期 if (field.getType().getName().equals("java.util.Date")&&field.getAnnotation(JsonFormat.class)==null&&item.get(field.getName())!=null){ @@ -121,12 +136,194 @@ public class DictAspect { } items.add(item); } + + //step.2 调用翻译方法,一次性翻译 + Map> translText = this.translateAllDict(dataListMap); + + //step.3 将翻译结果填充到返回结果里 + for (JSONObject record : items) { + for (Field field : dictFieldList) { + String code = field.getAnnotation(Dict.class).dicCode(); + String text = field.getAnnotation(Dict.class).dicText(); + String table = field.getAnnotation(Dict.class).dictTable(); + + String fieldDictCode = code; + if (!StringUtils.isEmpty(table)) { + fieldDictCode = String.format("%s,%s,%s", table, text, code); + } + + String value = record.getString(field.getName()); + if (oConvertUtils.isNotEmpty(value)) { + List dictModels = translText.get(fieldDictCode); + if(dictModels==null || dictModels.size()==0){ + continue; + } + + String textValue = this.translDictText(dictModels, value); + log.debug(" 字典Val : " + textValue); + log.debug(" __翻译字典字段__ " + field.getName() + CommonConstant.DICT_TEXT_SUFFIX + ": " + textValue); + + // TODO-sun 测试输出,待删 + log.debug(" ---- dictCode: " + fieldDictCode); + log.debug(" ---- value: " + value); + log.debug(" ----- text: " + textValue); + log.debug(" ---- dictModels: " + JSON.toJSONString(dictModels)); + + record.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue); + } + } + } + ((IPage) ((Result) result).getResult()).setRecords(items); } } } + /** + * list 去重添加 + */ + private void listAddAllDeduplicate(List dataList, List addList) { + // 筛选出dataList中没有的数据 + List filterList = addList.stream().filter(i -> !dataList.contains(i)).collect(Collectors.toList()); + dataList.addAll(filterList); + } + + /** + * 一次性把所有的字典都翻译了 + * 1. 所有的普通数据字典的所有数据只执行一次SQL + * 2. 表字典相同的所有数据只执行一次SQL + * @param dataListMap + * @return + */ + private Map> translateAllDict(Map> dataListMap) { + // 翻译后的字典文本,key=dictCode + Map> translText = new HashMap<>(); + // 需要翻译的数据(有些可以从redis缓存中获取,就不走数据库查询) + List needTranslData = new ArrayList<>(); + //step.1 先通过redis中获取缓存字典数据 + for (String dictCode : dataListMap.keySet()) { + List dataList = dataListMap.get(dictCode); + if (dataList.size() == 0) { + continue; + } + // 表字典需要翻译的数据 + List needTranslDataTable = new ArrayList<>(); + for (String s : dataList) { + String data = s.trim(); + if (data.length() == 0) { + continue; //跳过循环 + } + if (dictCode.contains(",")) { + String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, data); + if (redisTemplate.hasKey(keyString)) { + try { + String text = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString)); + List list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>()); + list.add(new DictModel(data, text)); + } catch (Exception e) { + log.warn(e.getMessage()); + } + } else if (!needTranslDataTable.contains(data)) { + // 去重添加 + needTranslDataTable.add(data); + } + } else { + String keyString = String.format("sys:cache:dict::%s:%s", dictCode, data); + if (redisTemplate.hasKey(keyString)) { + try { + String text = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString)); + List list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>()); + list.add(new DictModel(data, text)); + } catch (Exception e) { + log.warn(e.getMessage()); + } + } else if (!needTranslData.contains(data)) { + // 去重添加 + needTranslData.add(data); + } + } + + } + //step.2 调用数据库翻译表字典 + if (needTranslDataTable.size() > 0) { + String[] arr = dictCode.split(","); + String table = arr[0], text = arr[1], code = arr[2]; + String values = String.join(",", needTranslDataTable); + log.info("translateDictFromTableByKeys.dictCode:" + dictCode); + log.info("translateDictFromTableByKeys.values:" + values); + List texts = commonAPI.translateDictFromTableByKeys(table, text, code, values); + log.info("translateDictFromTableByKeys.result:" + texts); + List list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>()); + list.addAll(texts); + + // 做 redis 缓存 + for (DictModel dict : texts) { + String redisKey = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, dict.getValue()); + try { + redisTemplate.opsForValue().set(redisKey, dict.getText()); + } catch (Exception e) { + log.warn(e.getMessage(), e); + } + } + } + } + + //step.3 调用数据库进行翻译普通字典 + if (needTranslData.size() > 0) { + List dictCodeList = Arrays.asList(dataListMap.keySet().toArray(new String[]{})); + // 将不包含逗号的字典code筛选出来,因为带逗号的是表字典,而不是普通的数据字典 + List filterDictCodes = dictCodeList.stream().filter(key -> !key.contains(",")).collect(Collectors.toList()); + String dictCodes = String.join(",", filterDictCodes); + String values = String.join(",", needTranslData); + log.info("translateManyDict.dictCodes:" + dictCodes); + log.info("translateManyDict.values:" + values); + Map> manyDict = commonAPI.translateManyDict(dictCodes, values); + log.info("translateManyDict.result:" + manyDict); + for (String dictCode : manyDict.keySet()) { + List list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>()); + List newList = manyDict.get(dictCode); + list.addAll(newList); + + // 做 redis 缓存 + for (DictModel dict : newList) { + String redisKey = String.format("sys:cache:dict::%s:%s", dictCode, dict.getValue()); + try { + redisTemplate.opsForValue().set(redisKey, dict.getText()); + } catch (Exception e) { + log.warn(e.getMessage(), e); + } + } + } + } + return translText; + } + + /** + * 字典值替换文本 + * + * @param dictModels + * @param values + * @return + */ + private String translDictText(List dictModels, String values) { + List result = new ArrayList<>(); + + // 允许多个逗号分隔,允许传数组对象 + String[] splitVal = values.split(","); + for (String val : splitVal) { + String dictText = val; + for (DictModel dict : dictModels) { + if (val.equals(dict.getValue())) { + dictText = dict.getText(); + break; + } + } + result.add(dictText); + } + return String.join(",", result); + } + /** * 翻译字典文本 * @param code @@ -135,6 +332,7 @@ public class DictAspect { * @param key * @return */ + @Deprecated private String translateDictValue(String code, String text, String table, String key) { if(oConvertUtils.isEmpty(key)) { return null; @@ -151,7 +349,7 @@ public class DictAspect { if (!StringUtils.isEmpty(table)){ log.info("--DictAspect------dicTable="+ table+" ,dicText= "+text+" ,dicCode="+code); String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s,%s,%s]",table,text,code,k.trim()); - if (redisTemplate.hasKey(keyString)){ + if (redisTemplate.hasKey(keyString)){ try { tmpValue = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString)); } catch (Exception e) { diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java index f8e90ba9..bb272ab6 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java @@ -11,12 +11,14 @@ public interface DataBaseConstant { public static final String DB_TYPE_SQLSERVER = "SQLSERVER"; public static final String DB_TYPE_MARIADB = "MARIADB"; - // 数据库类型,对应 database_type 字典 - public static final String DB_TYPE_MYSQL_NUM = "1"; - public static final String DB_TYPE_ORACLE_NUM = "2"; - public static final String DB_TYPE_SQLSERVER_NUM = "3"; - public static final String DB_TYPE_POSTGRESQL_NUM = "4"; - public static final String DB_TYPE_MARIADB_NUM = "5"; +// // 数据库类型,对应 database_type 字典 +// public static final String DB_TYPE_MYSQL_NUM = "1"; +// public static final String DB_TYPE_MYSQL7_NUM = "6"; +// public static final String DB_TYPE_ORACLE_NUM = "2"; +// public static final String DB_TYPE_SQLSERVER_NUM = "3"; +// public static final String DB_TYPE_POSTGRESQL_NUM = "4"; +// public static final String DB_TYPE_MARIADB_NUM = "5"; + //*********系统上下文变量**************************************** /** * 数据-所属机构编码 diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ServiceNameConstants.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ServiceNameConstants.java index f09ba116..b54dc342 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ServiceNameConstants.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ServiceNameConstants.java @@ -29,6 +29,7 @@ public interface ServiceNameConstants { * 系统管理 admin */ String SYSTEM_SERVICE = "jeecg-system"; + String SYSTEM_ONLINE = "jeecg-online"; /** * gateway通过header传递根路径 basePath diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/RoleIndexConfigEnum.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/RoleIndexConfigEnum.java new file mode 100644 index 00000000..9f9007b8 --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/RoleIndexConfigEnum.java @@ -0,0 +1,82 @@ +package org.jeecg.common.constant.enums; + +/** + * 首页自定义 + * 通过角色编码与首页组件路径配置 + */ +public enum RoleIndexConfigEnum { + /** + * 管理员 + */ + ADMIN("admin1", "dashboard/Analysis2"), + /** + * 测试 + */ + TEST("test", "dashboard/Analysis"), + /** + * hr + */ + HR("hr", "dashboard/Analysis1"); + + /** + * 角色编码 + */ + String roleCode; + /** + * 路由index + */ + String componentUrl; + + /** + * 构造器 + * + * @param roleCode 角色编码 + * @param componentUrl 首页组件路径(规则跟菜单配置一样) + */ + RoleIndexConfigEnum(String roleCode, String componentUrl) { + this.roleCode = roleCode; + this.componentUrl = componentUrl; + } + /** + * 根据code找枚举 + * @param roleCode 角色编码 + * @return + */ + public static RoleIndexConfigEnum getEnumByCode(String roleCode) { + for (RoleIndexConfigEnum e : RoleIndexConfigEnum.values()) { + if (e.roleCode.equals(roleCode)) { + return e; + } + } + return null; + } + /** + * 根据code找index + * @param roleCode 角色编码 + * @return + */ + public static String getIndexByCode(String roleCode) { + for (RoleIndexConfigEnum e : RoleIndexConfigEnum.values()) { + if (e.roleCode.equals(roleCode)) { + return e.componentUrl; + } + } + return null; + } + + public String getRoleCode() { + return roleCode; + } + + public void setRoleCode(String roleCode) { + this.roleCode = roleCode; + } + + public String getComponentUrl() { + return componentUrl; + } + + public void setComponentUrl(String componentUrl) { + this.componentUrl = componentUrl; + } +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/es/JeecgElasticsearchTemplate.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/es/JeecgElasticsearchTemplate.java index 41d21bd7..b57da23e 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/es/JeecgElasticsearchTemplate.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/es/JeecgElasticsearchTemplate.java @@ -26,6 +26,8 @@ public class JeecgElasticsearchTemplate { /** es服务地址 */ private String baseUrl; private final String FORMAT_JSON = "format=json"; + /** Elasticsearch 的版本号 */ + private String version = null; // ElasticSearch 最大可返回条目数 public static final int ES_MAX_SIZE = 10000; @@ -37,15 +39,31 @@ public class JeecgElasticsearchTemplate { // 验证配置的ES地址是否有效 if (checkEnabled) { try { - RestUtil.get(this.getBaseUrl().toString()); + this.getElasticsearchVersion(); log.info("ElasticSearch 服务连接成功"); + log.info("ElasticSearch version: " + this.version); } catch (Exception e) { + this.version = ""; log.warn("ElasticSearch 服务连接失败,原因:配置未通过。可能是BaseURL未配置或配置有误,也可能是Elasticsearch服务未启动。接下来将会拒绝执行任何方法!"); } } } } + /** + * 获取 Elasticsearch 的版本号信息,失败返回null + */ + private void getElasticsearchVersion() { + if (this.version == null) { + String url = this.getBaseUrl().toString(); + JSONObject result = RestUtil.get(url); + if (result != null) { + JSONObject v = result.getJSONObject("version"); + this.version = v.getString("number"); + } + } + } + public StringBuilder getBaseUrl(String indexName, String typeName) { typeName = typeName.trim().toLowerCase(); return this.getBaseUrl(indexName).append("/").append(typeName); @@ -185,6 +203,11 @@ public class JeecgElasticsearchTemplate { */ public JSONObject getIndexMapping(String indexName, String typeName) { String url = this.getBaseUrl(indexName, typeName).append("/_mapping?").append(FORMAT_JSON).toString(); + // 针对 es 7.x 版本做兼容 + this.getElasticsearchVersion(); + if (oConvertUtils.isNotEmpty(this.version) && this.version.startsWith("7")) { + url += "&include_type_name=true"; + } log.info("getIndexMapping-url:" + url); /* * 参考返回JSON结构: diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryCondition.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryCondition.java index a9bad2a2..d239781e 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryCondition.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryCondition.java @@ -7,7 +7,13 @@ public class QueryCondition implements Serializable { private static final long serialVersionUID = 4740166316629191651L; private String field; + /** 组件的类型(例如:input、select、radio) */ private String type; + /** + * 对应的数据库字段的类型 + * 支持:int、bigDecimal、short、long、float、double、boolean + */ + private String dbType; private String rule; private String val; @@ -27,6 +33,14 @@ public class QueryCondition implements Serializable { this.type = type; } + public String getDbType() { + return dbType; + } + + public void setDbType(String dbType) { + this.dbType = dbType; + } + public String getRule() { return rule; } @@ -49,7 +63,7 @@ public class QueryCondition implements Serializable { if(field == null || "".equals(field)){ return ""; } - sb.append(this.field).append(" ").append(this.rule).append(" ").append(this.type).append(" ").append(this.val); + sb.append(this.field).append(" ").append(this.rule).append(" ").append(this.type).append(" ").append(this.dbType).append(" ").append(this.val); return sb.toString(); } } diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java index 553d012a..8a22441b 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java @@ -1,9 +1,17 @@ package org.jeecg.common.system.query; -import com.alibaba.fastjson.JSON; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import lombok.extern.slf4j.Slf4j; +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; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + import org.apache.commons.beanutils.PropertyUtils; import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.DataBaseConstant; @@ -16,17 +24,12 @@ import org.jeecg.common.util.SqlInjectionUtil; import org.jeecg.common.util.oConvertUtils; import org.springframework.util.NumberUtils; -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; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; + +import lombok.extern.slf4j.Slf4j; @Slf4j public class QueryGenerator { @@ -238,12 +241,12 @@ public class QueryGenerator { //queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column)); String columnStr = oConvertUtils.camelToUnderline(column); String[] columnArray = columnStr.split(","); - queryWrapper.orderByAsc(columnArray); + queryWrapper.orderByAsc(Arrays.asList(columnArray)); } else { //queryWrapper.orderByDesc(oConvertUtils.camelToUnderline(column)); String columnStr = oConvertUtils.camelToUnderline(column); String[] columnArray = columnStr.split(","); - queryWrapper.orderByDesc(columnArray); + queryWrapper.orderByDesc(Arrays.asList(columnArray)); } //update-end--Author:scott Date:20210531 for:36 多条件排序无效问题修正------- } @@ -284,6 +287,39 @@ public class QueryGenerator { }else if("datetime".equals(rule.getType())){ queryValue = DateUtils.str2Date(rule.getVal(), DateUtils.datetimeFormat.get()); } + // update-begin--author:sunjianlei date:20210702 for:【/issues/I3VR8E】高级查询没有类型转换,查询参数都是字符串类型 ---- + String dbType = rule.getDbType(); + if (oConvertUtils.isNotEmpty(dbType)) { + try { + String valueStr = String.valueOf(queryValue); + switch (dbType.toLowerCase().trim()) { + case "int": + queryValue = Integer.parseInt(valueStr); + break; + case "bigdecimal": + queryValue = new BigDecimal(valueStr); + break; + case "short": + queryValue = Short.parseShort(valueStr); + break; + case "long": + queryValue = Long.parseLong(valueStr); + break; + case "float": + queryValue = Float.parseFloat(valueStr); + break; + case "double": + queryValue = Double.parseDouble(valueStr); + break; + case "boolean": + queryValue = Boolean.parseBoolean(valueStr); + break; + } + } catch (Exception e) { + log.error("高级查询值转换失败:", e); + } + } + // update-begin--author:sunjianlei date:20210702 for:【/issues/I3VR8E】高级查询没有类型转换,查询参数都是字符串类型 ---- addEasyQuery(andWrapper, fieldColumnMap.get(rule.getField()), QueryRuleEnum.getByValue(rule.getRule()), queryValue); //update-end-author:taoyan date:20201228 for: 【高级查询】 oracle 日期等于查询报错 @@ -313,13 +349,15 @@ public class QueryGenerator { */ private static QueryRuleEnum convert2Rule(Object value) { // 避免空数据 + // update-begin-author:taoyan date:20210629 for: 查询条件输入空格导致return null后续判断导致抛出null异常 if (value == null) { - return null; + return QueryRuleEnum.EQ; } String val = (value + "").toString().trim(); if (val.length() == 0) { - return null; + return QueryRuleEnum.EQ; } + // update-end-author:taoyan date:20210629 for: 查询条件输入空格导致return null后续判断导致抛出null异常 QueryRuleEnum rule =null; //update-begin--Author:scott Date:20190724 for:initQueryWrapper组装sql查询条件错误 #284------------------- @@ -820,20 +858,25 @@ public class QueryGenerator { } private static String getInConditionValue(Object value,boolean isString) { + //update-begin-author:taoyan date:20210628 for: 查询条件如果输入,导致sql报错 + String[] temp = value.toString().split(","); + if(temp.length==0){ + return "('')"; + } if(isString) { - String temp[] = value.toString().split(","); - String res=""; + List res = new ArrayList<>(); for (String string : temp) { if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){ - res+=",N'"+string+"'"; + res.add("N'"+string+"'"); }else{ - res+=",'"+string+"'"; + res.add("'"+string+"'"); } } - return "("+res.substring(1)+")"; + return "("+String.join("," ,res)+")"; }else { return "("+value.toString()+")"; } + //update-end-author:taoyan date:20210628 for: 查询条件如果输入,导致sql报错 } private static String getLikeConditionValue(Object value) { @@ -1003,8 +1046,6 @@ public class QueryGenerator { - /** 当前系统数据库类型 */ - private static String DB_TYPE; /** * 获取系统数据库类型 */ diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DictModelMany.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DictModelMany.java new file mode 100644 index 00000000..778fb4b5 --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DictModelMany.java @@ -0,0 +1,18 @@ +package org.jeecg.common.system.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 查询多个字典时用到 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class DictModelMany extends DictModel { + + /** + * 字典code,根据多个字段code查询时才用到,用于区分不同的字典选项 + */ + private String dictCode; + +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DynamicDataSourceModel.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DynamicDataSourceModel.java index 91a0e63b..5926a3b7 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DynamicDataSourceModel.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DynamicDataSourceModel.java @@ -36,10 +36,12 @@ public class DynamicDataSourceModel { * 数据源地址 */ private java.lang.String dbUrl; - /** - * 数据库名称 - */ - private java.lang.String dbName; + +// /** +// * 数据库名称 +// */ +// private java.lang.String dbName; + /** * 用户名 */ diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java index 27e5cc9c..a080e655 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java @@ -1,26 +1,26 @@ package org.jeecg.common.util; -import cn.hutool.core.util.StrUtil; -import cn.hutool.extra.pinyin.PinyinUtil; -import lombok.extern.slf4j.Slf4j; +import java.io.*; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.sql.DataSource; + import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.DataBaseConstant; -import org.jeecg.common.exception.JeecgBootException; +import org.jeecg.common.util.filter.FileTypeFilter; import org.jeecg.common.util.oss.OssBootUtil; import org.jeecgframework.poi.util.PoiPublicUtil; import org.springframework.util.FileCopyUtils; import org.springframework.web.multipart.MultipartFile; -import javax.sql.DataSource; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.SQLException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils; + +import lombok.extern.slf4j.Slf4j; @Slf4j public class CommonUtils { @@ -116,6 +116,9 @@ public class CommonUtils { */ public static String uploadLocal(MultipartFile mf,String bizPath,String uploadpath){ try { + //update-begin-author:liusq date:20210809 for: 过滤上传文件类型 + FileTypeFilter.fileTypeFilter(mf); + //update-end-author:liusq date:20210809 for: 过滤上传文件类型 String fileName = null; File file = new File(uploadpath + File.separator + bizPath + File.separator ); if (!file.exists()) { @@ -143,6 +146,8 @@ public class CommonUtils { return dbpath; } catch (IOException e) { log.error(e.getMessage(), e); + }catch (Exception e) { + log.error(e.getMessage(), e); } return ""; } @@ -163,6 +168,13 @@ public class CommonUtils { /** 当前系统数据库类型 */ private static String DB_TYPE = ""; + private static DbType dbTypeEnum = null; + + /** + * 全局获取平台数据库类型(作废了) + * @return + */ + @Deprecated public static String getDatabaseType() { if(oConvertUtils.isNotEmpty(DB_TYPE)){ return DB_TYPE; @@ -177,6 +189,24 @@ public class CommonUtils { } } + /** + * 全局获取平台数据库类型(对应mybaisPlus枚举) + * @return + */ + public static DbType getDatabaseTypeEnum() { + if (oConvertUtils.isNotEmpty(dbTypeEnum)) { + return dbTypeEnum; + } + try { + DataSource dataSource = SpringContextUtils.getApplicationContext().getBean(DataSource.class); + dbTypeEnum = JdbcUtils.getDbType(dataSource.getConnection().getMetaData().getURL()); + return dbTypeEnum; + } catch (SQLException e) { + log.warn(e.getMessage(), e); + return null; + } + } + /** * 获取数据库类型 * @param dataSource diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateUtils.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateUtils.java index 6a5f14c7..c9304695 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateUtils.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateUtils.java @@ -291,7 +291,7 @@ public class DateUtils extends PropertyEditorSupport { Date dt = new Date(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String nowTime = df.format(dt); - Timestamp buydate = Timestamp.valueOf(nowTime); + java.sql.Timestamp buydate = java.sql.Timestamp.valueOf(nowTime); return buydate; } diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java index 8f32476c..e1aeac4a 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java @@ -2,6 +2,7 @@ package org.jeecg.common.util; import io.minio.*; import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.util.filter.FileTypeFilter; import org.jeecg.common.util.filter.StrAttackFilter; import org.springframework.web.multipart.MultipartFile; @@ -68,6 +69,9 @@ public class MinioUtil { minioClient.makeBucket(MakeBucketArgs.builder().bucket(newBucket).build()); log.info("create a new bucket."); } + //update-begin-author:liusq date:20210809 for: 过滤上传文件类型 + FileTypeFilter.fileTypeFilter(file); + //update-end-author:liusq date:20210809 for: 过滤上传文件类型 InputStream stream = file.getInputStream(); // 获取文件名 String orgName = file.getOriginalFilename(); diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/PathMatcherUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/PathMatcherUtil.java index 0b813f4a..e4427ba9 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/PathMatcherUtil.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/PathMatcherUtil.java @@ -1,10 +1,10 @@ package org.jeecg.common.util; -import org.springframework.util.AntPathMatcher; - import java.util.Collection; import java.util.Map; +import org.springframework.util.AntPathMatcher; + /** * 使用Spring自身提供的地址匹配工具匹配URL */ diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/ReflectHelper.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/ReflectHelper.java index 3d066c27..a66ae891 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/ReflectHelper.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/ReflectHelper.java @@ -192,6 +192,23 @@ public class ReflectHelper { } } + /** + * 获取属性值 + */ + public static Object getFieldVal(String fieldName, Object o) { + try { + // 暴力反射获取属性 + Field filed = o.getClass().getDeclaredField(fieldName); + // 设置反射时取消Java的访问检查,暴力访问 + filed.setAccessible(true); + Object val = filed.get(o); + return val; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + /** * 获取属性名数组 */ diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java new file mode 100644 index 00000000..6bc63fbf --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java @@ -0,0 +1,39 @@ +package org.jeecg.common.util.dynamic.db; + +import com.baomidou.mybatisplus.annotation.DbType; + +/** + * 数据库类型判断 + * 【有些数据库引擎是一样的,以达到复用目的】 + */ +public class DbTypeUtils { + + public static boolean dbTypeIsMySQL(DbType dbType) { + return dbTypeIf(dbType, DbType.MYSQL, DbType.MARIADB, DbType.CLICK_HOUSE, DbType.SQLITE); + } + + public static boolean dbTypeIsOracle(DbType dbType) { + return dbTypeIf(dbType, DbType.ORACLE, DbType.ORACLE_12C, DbType.DM); + } + + public static boolean dbTypeIsSQLServer(DbType dbType) { + return dbTypeIf(dbType, DbType.SQL_SERVER, DbType.SQL_SERVER2005); + } + + public static boolean dbTypeIsPostgre(DbType dbType) { + return dbTypeIf(dbType, DbType.POSTGRE_SQL, DbType.KINGBASE_ES, DbType.GAUSS); + } + + /** + * 判断数据库类型 + */ + public static boolean dbTypeIf(DbType dbType, DbType... correctTypes) { + for (DbType type : correctTypes) { + if (type.equals(dbType)) { + return true; + } + } + return false; + } + +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DynamicDBUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DynamicDBUtil.java index 86f3f115..66c8c81e 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DynamicDBUtil.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DynamicDBUtil.java @@ -49,7 +49,7 @@ public class DynamicDBUtil { dataSource.setBreakAfterAcquireFailure(true); dataSource.setConnectionErrorRetryAttempts(0); dataSource.setUsername(dbUser); - dataSource.setMaxWait(60000); + dataSource.setMaxWait(30000); dataSource.setPassword(dbPassword); log.info("******************************************"); @@ -151,6 +151,7 @@ public class DynamicDBUtil { list = findList(dbKey, sql, param); if (oConvertUtils.listIsEmpty(list)) { log.error("Except one, but not find actually"); + return null; } if (list.size() > 1) { log.error("Except one, but more than one actually"); diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/SqlUtils.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/SqlUtils.java deleted file mode 100644 index 0c4c03ee..00000000 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/SqlUtils.java +++ /dev/null @@ -1,213 +0,0 @@ -package org.jeecg.common.util.dynamic.db; - -import org.apache.commons.lang3.StringUtils; -import org.jeecg.common.constant.DataBaseConstant; -import org.jeecg.common.system.vo.DynamicDataSourceModel; - -import java.text.MessageFormat; -import java.util.Map; - -/** - * 根据不同的数据库,动态生成SQL,例如分页 - */ -public class SqlUtils { - - public static final String DATABSE_TYPE_MYSQL = "mysql"; - public static final String DATABSE_TYPE_MARIADB = "mariadb"; - public static final String DATABSE_TYPE_POSTGRE = "postgresql"; - public static final String DATABSE_TYPE_ORACLE = "oracle"; - public static final String DATABSE_TYPE_SQLSERVER = "sqlserver"; - - - /** - * 分页SQL - */ - public static final String MYSQL_SQL = "select * from ( {0}) sel_tab00 limit {1},{2}"; - public static final String POSTGRE_SQL = "select * from ( {0}) sel_tab00 limit {2} offset {1}"; - public static final String ORACLE_SQL = "select * from (select row_.*,rownum rownum_ from ({0}) row_ where rownum <= {1}) where rownum_>{2}"; - public static final String SQLSERVER_SQL = "select * from ( select row_number() over(order by tempColumn) tempRowNumber, * from (select top {1} tempColumn = 0, {0}) t ) tt where tempRowNumber > {2}"; - - /** - * 获取所有表的SQL - */ - public static final String MYSQL_ALLTABLES_SQL = "select distinct table_name from information_schema.columns where table_schema = {0}"; - public static final String POSTGRE__ALLTABLES_SQL = "SELECT distinct c.relname AS table_name FROM pg_class c"; - public static final String ORACLE__ALLTABLES_SQL = "select distinct colstable.table_name as table_name from user_tab_cols colstable"; - public static final String SQLSERVER__ALLTABLES_SQL = "select distinct c.name as table_name from sys.objects c"; - - /** - * 获取指定表的所有列名 - */ - public static final String MYSQL_ALLCOLUMNS_SQL = "select column_name from information_schema.columns where table_name = {0} and table_schema = {1}"; - public static final String POSTGRE_ALLCOLUMNS_SQL = "select table_name from information_schema.columns where table_name = {0}"; - public static final String ORACLE_ALLCOLUMNS_SQL = "select column_name from all_tab_columns where table_name ={0}"; - public static final String SQLSERVER_ALLCOLUMNS_SQL = "select name from syscolumns where id={0}"; - - /* - * 判断数据库类型 - */ - - public static boolean dbTypeIsMySQL(String dbType) { - return dbTypeIf(dbType, DATABSE_TYPE_MYSQL, DataBaseConstant.DB_TYPE_MYSQL_NUM) || dbTypeIf(dbType, DATABSE_TYPE_MARIADB, DataBaseConstant.DB_TYPE_MARIADB_NUM); - } - - public static boolean dbTypeIsOracle(String dbType) { - return dbTypeIf(dbType, DATABSE_TYPE_ORACLE, DataBaseConstant.DB_TYPE_ORACLE_NUM); - } - - public static boolean dbTypeIsSQLServer(String dbType) { - return dbTypeIf(dbType, DATABSE_TYPE_SQLSERVER, DataBaseConstant.DB_TYPE_SQLSERVER_NUM); - } - - public static boolean dbTypeIsPostgre(String dbType) { - return dbTypeIf(dbType, DATABSE_TYPE_POSTGRE, DataBaseConstant.DB_TYPE_POSTGRESQL_NUM); - } - - /** - * 判断数据库类型 - */ - public static boolean dbTypeIf(String dbType, String... correctTypes) { - for (String type : correctTypes) { - if (type.equalsIgnoreCase(dbType)) { - return true; - } - } - return false; - } - - /** - * 获取全 SQL - * 拼接 where 条件 - * - * @param sql - * @param params - * @return - */ - public static String getFullSql(String sql, Map params) { - return getFullSql(sql, params, null, null); - } - - /** - * 获取全 SQL - * 拼接 where 条件 - * 拼接 order 排序 - * - * @param sql - * @param params - * @param orderColumn 排序字段 - * @param orderBy 排序方式,只能是 DESC 或 ASC - * @return - */ - public static String getFullSql(String sql, Map params, String orderColumn, String orderBy) { - StringBuilder sqlBuilder = new StringBuilder(); - sqlBuilder.append("SELECT t.* FROM ( ").append(sql).append(" ) t "); - if (params != null && params.size() >= 1) { - sqlBuilder.append("WHERE 1=1 "); - for (Object key : params.keySet()) { - String value = String.valueOf(params.get(key)); - if (StringUtils.isNotBlank(value)) { - sqlBuilder.append(" AND (").append(key).append(" = N'").append(value).append("')"); - } - } - if (StringUtils.isNotBlank(orderColumn) && StringUtils.isNotBlank(orderBy)) { - sqlBuilder.append("ORDER BY ").append(orderColumn).append(" ").append("DESC".equalsIgnoreCase(orderBy) ? "DESC" : "ASC"); - } - } - return sqlBuilder.toString(); - } - - /** - * 获取求数量 SQL - * - * @param sql - * @return - */ - public static String getCountSql(String sql) { - return String.format("SELECT COUNT(1) \"total\" FROM ( %s ) temp_count", sql); - } - - /** - * 生成分页查询 SQL - * - * @param dbType 数据库类型 - * @param sql - * @param page - * @param rows - * @return - */ - public static String createPageSqlByDBType(String dbType, String sql, int page, int rows) { - int beginNum = (page - 1) * rows; - Object[] sqlParam = new Object[3]; - sqlParam[0] = sql; - sqlParam[1] = String.valueOf(beginNum); - sqlParam[2] = String.valueOf(rows); - if (dbTypeIsMySQL(dbType)) { - sql = MessageFormat.format(MYSQL_SQL, sqlParam); - } else if (dbTypeIsPostgre(dbType)) { - sql = MessageFormat.format(POSTGRE_SQL, sqlParam); - } else { - int beginIndex = (page - 1) * rows; - int endIndex = beginIndex + rows; - sqlParam[2] = Integer.toString(beginIndex); - sqlParam[1] = Integer.toString(endIndex); - if (dbTypeIsOracle(dbType)) { - sql = MessageFormat.format(ORACLE_SQL, sqlParam); - } else if (dbTypeIsSQLServer(dbType)) { - sqlParam[0] = sql.substring(getAfterSelectInsertPoint(sql)); - sql = MessageFormat.format(SQLSERVER_SQL, sqlParam); - } - } - return sql; - } - - /** - * 生成分页查询 SQL - * - * @param sql - * @param page - * @param rows - * @return - */ - public static String createPageSqlByDBKey(String dbKey, String sql, int page, int rows) { - DynamicDataSourceModel dynamicSourceEntity = DataSourceCachePool.getCacheDynamicDataSourceModel(dbKey); - String dbType = dynamicSourceEntity.getDbType(); - return createPageSqlByDBType(dbType, sql, page, rows); - } - - private static int getAfterSelectInsertPoint(String sql) { - int selectIndex = sql.toLowerCase().indexOf("select"); - int selectDistinctIndex = sql.toLowerCase().indexOf("select distinct"); - return selectIndex + (selectDistinctIndex == selectIndex ? 15 : 6); - } - - public static String getAllTableSql(String dbType, Object... params) { - if (StringUtils.isNotEmpty(dbType)) { - if (dbTypeIsMySQL(dbType)) { - return MessageFormat.format(MYSQL_ALLTABLES_SQL, params); - } else if (dbTypeIsOracle(dbType)) { - return ORACLE__ALLTABLES_SQL; - } else if (dbTypeIsPostgre(dbType)) { - return POSTGRE__ALLTABLES_SQL; - } else if (dbTypeIsSQLServer(dbType)) { - return SQLSERVER__ALLTABLES_SQL; - } - } - return null; - } - - public static String getAllColumnSQL(String dbType, Object... params) { - if (StringUtils.isNotEmpty(dbType)) { - if (dbTypeIsMySQL(dbType)) { - return MessageFormat.format(MYSQL_ALLCOLUMNS_SQL, params); - } else if (dbTypeIsOracle(dbType)) { - return MessageFormat.format(ORACLE_ALLCOLUMNS_SQL, params); - } else if (dbTypeIsPostgre(dbType)) { - return MessageFormat.format(POSTGRE_ALLCOLUMNS_SQL, params); - } else if (dbTypeIsSQLServer(dbType)) { - return MessageFormat.format(SQLSERVER_ALLCOLUMNS_SQL, params); - } - } - return null; - } - -} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/FileTypeFilter.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/FileTypeFilter.java new file mode 100644 index 00000000..fd36d7e8 --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/FileTypeFilter.java @@ -0,0 +1,166 @@ +package org.jeecg.common.util.filter; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @Description: TODO + * @author: lsq + * @date: 2021年08月09日 15:29 + */ +public class FileTypeFilter { + + //文件后缀 + private static String[] forbidType = {"jsp","php"}; + + // 初始化文件头类型,不够的自行补充 + final static HashMap fileTypeMap = new HashMap<>(); + + static { + fileTypeMap.put("3c25402070616765206c", "jsp"); + fileTypeMap.put("3c3f7068700a0a2f2a2a0a202a205048", "php"); + /* fileTypeMap.put("ffd8ffe000104a464946", "jpg"); + fileTypeMap.put("89504e470d0a1a0a0000", "png"); + fileTypeMap.put("47494638396126026f01", "gif"); + fileTypeMap.put("49492a00227105008037", "tif"); + fileTypeMap.put("424d228c010000000000", "bmp"); + fileTypeMap.put("424d8240090000000000", "bmp"); + fileTypeMap.put("424d8e1b030000000000", "bmp"); + fileTypeMap.put("41433130313500000000", "dwg"); + fileTypeMap.put("3c21444f435459504520", "html"); + fileTypeMap.put("3c21646f637479706520", "htm"); + fileTypeMap.put("48544d4c207b0d0a0942", "css"); + fileTypeMap.put("696b2e71623d696b2e71", "js"); + fileTypeMap.put("7b5c727466315c616e73", "rtf"); + fileTypeMap.put("38425053000100000000", "psd"); + fileTypeMap.put("46726f6d3a203d3f6762", "eml"); + fileTypeMap.put("d0cf11e0a1b11ae10000", "doc"); + fileTypeMap.put("5374616E64617264204A", "mdb"); + fileTypeMap.put("252150532D41646F6265", "ps"); + fileTypeMap.put("255044462d312e350d0a", "pdf"); + fileTypeMap.put("2e524d46000000120001", "rmvb"); + fileTypeMap.put("464c5601050000000900", "flv"); + fileTypeMap.put("00000020667479706d70", "mp4"); + fileTypeMap.put("49443303000000002176", "mp3"); + fileTypeMap.put("000001ba210001000180", "mpg"); + fileTypeMap.put("3026b2758e66cf11a6d9", "wmv"); + fileTypeMap.put("52494646e27807005741", "wav"); + fileTypeMap.put("52494646d07d60074156", "avi"); + fileTypeMap.put("4d546864000000060001", "mid"); + fileTypeMap.put("504b0304140000000800", "zip"); + fileTypeMap.put("526172211a0700cf9073", "rar"); + fileTypeMap.put("235468697320636f6e66", "ini"); + fileTypeMap.put("504b03040a0000000000", "jar"); + fileTypeMap.put("4d5a9000030000000400", "exe"); + fileTypeMap.put("3c25402070616765206c", "jsp"); + fileTypeMap.put("4d616e69666573742d56", "mf"); + fileTypeMap.put("3c3f786d6c2076657273", "xml"); + fileTypeMap.put("494e5345525420494e54", "sql"); + fileTypeMap.put("7061636b616765207765", "java"); + fileTypeMap.put("406563686f206f66660d", "bat"); + fileTypeMap.put("1f8b0800000000000000", "gz"); + fileTypeMap.put("6c6f67346a2e726f6f74", "properties"); + fileTypeMap.put("cafebabe0000002e0041", "class"); + fileTypeMap.put("49545346030000006000", "chm"); + fileTypeMap.put("04000000010000001300", "mxp"); + fileTypeMap.put("504b0304140006000800", "docx"); + fileTypeMap.put("6431303a637265617465", "torrent"); + fileTypeMap.put("6D6F6F76", "mov"); + fileTypeMap.put("FF575043", "wpd"); + fileTypeMap.put("CFAD12FEC5FD746F", "dbx"); + fileTypeMap.put("2142444E", "pst"); + fileTypeMap.put("AC9EBD8F", "qdf"); + fileTypeMap.put("E3828596", "pwl"); + fileTypeMap.put("2E7261FD", "ram");*/ + } + + /** + * @param fileName + * @return String + * @description 通过文件后缀名获取文件类型 + */ + private static String getFileTypeBySuffix(String fileName) { + return fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()); + } + + /** + * 文件类型过滤 + * + * @param file + */ + public static void fileTypeFilter(MultipartFile file) throws Exception { + String suffix = getFileType(file); + for (String type : forbidType) { + if (type.contains(suffix)) { + throw new Exception("上传失败,文件类型异常:" + suffix); + } + } + } + + /** + * 通过读取文件头部获得文件类型 + * + * @param file + * @return 文件类型 + * @throws Exception + */ + + private static String getFileType(MultipartFile file) throws Exception { + String fileExtendName = null; + InputStream is; + try { + //is = new FileInputStream(file); + is = file.getInputStream(); + byte[] b = new byte[10]; + is.read(b, 0, b.length); + String fileTypeHex = String.valueOf(bytesToHexString(b)); + Iterator keyIter = fileTypeMap.keySet().iterator(); + while (keyIter.hasNext()) { + String key = keyIter.next(); + // 验证前5个字符比较 + if (key.toLowerCase().startsWith(fileTypeHex.toLowerCase().substring(0, 5)) + || fileTypeHex.toLowerCase().substring(0, 5).startsWith(key.toLowerCase())) { + fileExtendName = fileTypeMap.get(key); + break; + } + } + // 如果不是上述类型,则判断扩展名 + if (StringUtils.isBlank(fileExtendName)) { + String fileName = file.getOriginalFilename(); + return getFileTypeBySuffix(fileName); + } + is.close(); + return fileExtendName; + } catch (Exception exception) { + throw new Exception(exception.getMessage(), exception); + } + } + + /** + * 获得文件头部字符串 + * + * @param src + * @return + */ + private static String bytesToHexString(byte[] src) { + StringBuilder stringBuilder = new StringBuilder(); + if (src == null || src.length <= 0) { + return null; + } + for (int i = 0; i < src.length; i++) { + int v = src[i] & 0xFF; + String hv = Integer.toHexString(v); + if (hv.length() < 2) { + stringBuilder.append(0); + } + stringBuilder.append(hv); + } + return stringBuilder.toString(); + } +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java index d073120e..5598dfed 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java @@ -9,6 +9,7 @@ import com.aliyun.oss.model.PutObjectResult; import lombok.extern.slf4j.Slf4j; import org.apache.tomcat.util.http.fileupload.FileItemStream; import org.jeecg.common.util.CommonUtils; +import org.jeecg.common.util.filter.FileTypeFilter; import org.jeecg.common.util.filter.StrAttackFilter; import org.jeecg.common.util.oConvertUtils; import org.springframework.web.multipart.MultipartFile; @@ -110,6 +111,9 @@ public class OssBootUtil { if("" == orgName){ orgName=file.getName(); } + //update-begin-author:liusq date:20210809 for: 过滤上传文件类型 + FileTypeFilter.fileTypeFilter(file); + //update-end-author:liusq date:20210809 for: 过滤上传文件类型 orgName = CommonUtils.getFileName(orgName); String fileName = orgName.indexOf(".")==-1 ?orgName + "_" + System.currentTimeMillis() @@ -136,6 +140,9 @@ public class OssBootUtil { } catch (IOException e) { e.printStackTrace(); return null; + }catch (Exception e) { + e.printStackTrace(); + return null; } return FILE_URL; } diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/SecurityTools.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/SecurityTools.java index 30fba766..dec223fb 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/SecurityTools.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/SecurityTools.java @@ -8,9 +8,8 @@ import cn.hutool.crypto.asymmetric.RSA; import cn.hutool.crypto.asymmetric.Sign; import cn.hutool.crypto.asymmetric.SignAlgorithm; import cn.hutool.crypto.symmetric.AES; -import cn.hutool.json.JSONObject; import org.jeecg.common.util.security.entity.*; - +import com.alibaba.fastjson.JSONObject; import javax.crypto.SecretKey; import java.security.KeyPair; @@ -34,7 +33,7 @@ public class SecurityTools { String dencrptValue =aes.decryptStr(data); //log.info("解密后报文"+dencrptValue); - resp.setData(new JSONObject(dencrptValue)); + resp.setData(JSONObject.parseObject(dencrptValue)); boolean verify = sign.verify(dencrptValue.getBytes(), Base64Decoder.decode(signData)); resp.setSuccess(verify); diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/entity/SecurityResp.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/entity/SecurityResp.java index eb4cff3a..d5415d08 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/entity/SecurityResp.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/entity/SecurityResp.java @@ -1,6 +1,6 @@ package org.jeecg.common.util.security.entity; -import cn.hutool.json.JSONObject; +import com.alibaba.fastjson.JSONObject; import lombok.Data; @Data diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/DruidConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/DruidConfig.java index c8a2ed64..d04c22f5 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/DruidConfig.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/DruidConfig.java @@ -1,8 +1,9 @@ package org.jeecg.config; -import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; -import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; -import com.alibaba.druid.util.Utils; +import java.io.IOException; + +import javax.servlet.*; + import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; @@ -10,8 +11,9 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import javax.servlet.*; -import java.io.IOException; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; +import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; +import com.alibaba.druid.util.Utils; @Configuration @AutoConfigureAfter(DruidDataSourceAutoConfigure.class) @@ -34,7 +36,7 @@ public class DruidConfig { * 去除Druid监控页面的广告 * * @param properties DruidStatProperties属性集合 - * @return {@link org.springframework.boot.web.servlet.FilterRegistrationBean} + * @return {@link FilterRegistrationBean} */ @Bean @ConditionalOnWebApplication diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java index cbee37ed..ba1a4750 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java @@ -20,6 +20,12 @@ public class StaticConfig { @Value(value = "${spring.mail.username}") private String emailFrom; + /** + * 签名密钥串 + */ + @Value(value = "${jeecg.signatureSecret}") + private String signatureSecret; + /*@Bean public void initStatic() { diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/Swagger2Config.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/Swagger2Config.java index 4b338758..bedc0963 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/Swagger2Config.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/Swagger2Config.java @@ -110,7 +110,8 @@ public class Swagger2Config implements WebMvcConfigurer { // 描述 .description("后台API接口") // 作者 - .contact("JEECG团队") + .contact(new Contact("北京国炬信息技术有限公司","www.jeccg.com","jeecgos@163.com")) + // .contact("JEECG团队") .license("The Apache License, Version 2.0") .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html") .build(); diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/JeecgTenantParser.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/JeecgTenantParser.java index af0f9c37..5233fdb8 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/JeecgTenantParser.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/JeecgTenantParser.java @@ -1,130 +1,130 @@ -package org.jeecg.config.mybatis; - -import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser; -import net.sf.jsqlparser.expression.BinaryExpression; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.expression.Parenthesis; -import net.sf.jsqlparser.expression.operators.conditional.AndExpression; -import net.sf.jsqlparser.expression.operators.conditional.OrExpression; -import net.sf.jsqlparser.expression.operators.relational.*; -import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.schema.Table; -import net.sf.jsqlparser.statement.select.*; - -import java.util.List; - -/** - * 复写租户条件 - */ -public class JeecgTenantParser extends TenantSqlParser { - - /** - * @param expression - * @param table - * @return - */ - protected Expression processTableAlias(Expression expression, Table table) { - String tableAliasName; - if (table.getAlias() == null) { - tableAliasName = table.getName(); - } else { - tableAliasName = table.getAlias().getName(); - } - - // in - if (expression instanceof InExpression) { - InExpression in = (InExpression) expression; - if (in.getLeftExpression() instanceof Column) { - setTableAliasNameForColumn((Column) in.getLeftExpression(), tableAliasName); - } - - // 比较操作 - } else if (expression instanceof BinaryExpression) { - BinaryExpression compare = (BinaryExpression) expression; - if (compare.getLeftExpression() instanceof Column) { - setTableAliasNameForColumn((Column) compare.getLeftExpression(), tableAliasName); - } else if (compare.getRightExpression() instanceof Column) { - setTableAliasNameForColumn((Column) compare.getRightExpression(), tableAliasName); - } - - // between - } else if (expression instanceof Between) { - Between between = (Between) expression; - if (between.getLeftExpression() instanceof Column) { - setTableAliasNameForColumn((Column) between.getLeftExpression(), tableAliasName); - } - } - return expression; - } - - private void setTableAliasNameForColumn(Column column, String tableAliasName) { - column.setColumnName(tableAliasName + "." + column.getColumnName()); - } - - /** - * 默认是按 tenant_id=1 按等于条件追加 - * - * @param currentExpression 现有的条件:比如你原来的sql查询条件 - * @param table - * @return - */ - @Override - protected Expression builderExpression(Expression currentExpression, Table table) { - final Expression tenantExpression = this.getTenantHandler().getTenantId(true); - Expression appendExpression; - if (!(tenantExpression instanceof SupportsOldOracleJoinSyntax)) { - appendExpression = new EqualsTo(); - ((EqualsTo) appendExpression).setLeftExpression(this.getAliasColumn(table)); - ((EqualsTo) appendExpression).setRightExpression(tenantExpression); - } else { - appendExpression = processTableAlias(tenantExpression, table); - } - if (currentExpression == null) { - return appendExpression; - } - if (currentExpression instanceof BinaryExpression) { - BinaryExpression binaryExpression = (BinaryExpression) currentExpression; - if (binaryExpression.getLeftExpression() instanceof FromItem) { - processFromItem((FromItem) binaryExpression.getLeftExpression()); - } - if (binaryExpression.getRightExpression() instanceof FromItem) { - processFromItem((FromItem) binaryExpression.getRightExpression()); - } - } else if (currentExpression instanceof InExpression) { - InExpression inExp = (InExpression) currentExpression; - ItemsList rightItems = inExp.getRightItemsList(); - if (rightItems instanceof SubSelect) { - processSelectBody(((SubSelect) rightItems).getSelectBody()); - } - } - if (currentExpression instanceof OrExpression) { - return new AndExpression(new Parenthesis(currentExpression), appendExpression); - } else { - return new AndExpression(currentExpression, appendExpression); - } - } - - @Override - protected void processPlainSelect(PlainSelect plainSelect, boolean addColumn) { - FromItem fromItem = plainSelect.getFromItem(); - if (fromItem instanceof Table) { - Table fromTable = (Table) fromItem; - if (!this.getTenantHandler().doTableFilter(fromTable.getName())) { - plainSelect.setWhere(builderExpression(plainSelect.getWhere(), fromTable)); - if (addColumn) { - plainSelect.getSelectItems().add(new SelectExpressionItem(new Column(this.getTenantHandler().getTenantIdColumn()))); - } - } - } else { - processFromItem(fromItem); - } - List joins = plainSelect.getJoins(); - if (joins != null && joins.size() > 0) { - joins.forEach(j -> { - processJoin(j); - processFromItem(j.getRightItem()); - }); - } - } - -} +//package org.jeecg.config.mybatis; +// +//import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser; +//import net.sf.jsqlparser.expression.BinaryExpression; +//import net.sf.jsqlparser.expression.Expression; +//import net.sf.jsqlparser.expression.Parenthesis; +//import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +//import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +//import net.sf.jsqlparser.expression.operators.relational.*; +//import net.sf.jsqlparser.schema.Column; +//import net.sf.jsqlparser.schema.Table; +//import net.sf.jsqlparser.statement.select.*; +// +//import java.util.List; +// +///** +// * 复写租户条件 +// */ +//public class JeecgTenantParser extends TenantSqlParser { +// +// /** +// * @param expression +// * @param table +// * @return +// */ +// protected Expression processTableAlias(Expression expression, Table table) { +// String tableAliasName; +// if (table.getAlias() == null) { +// tableAliasName = table.getName(); +// } else { +// tableAliasName = table.getAlias().getName(); +// } +// +// // in +// if (expression instanceof InExpression) { +// InExpression in = (InExpression) expression; +// if (in.getLeftExpression() instanceof Column) { +// setTableAliasNameForColumn((Column) in.getLeftExpression(), tableAliasName); +// } +// +// // 比较操作 +// } else if (expression instanceof BinaryExpression) { +// BinaryExpression compare = (BinaryExpression) expression; +// if (compare.getLeftExpression() instanceof Column) { +// setTableAliasNameForColumn((Column) compare.getLeftExpression(), tableAliasName); +// } else if (compare.getRightExpression() instanceof Column) { +// setTableAliasNameForColumn((Column) compare.getRightExpression(), tableAliasName); +// } +// +// // between +// } else if (expression instanceof Between) { +// Between between = (Between) expression; +// if (between.getLeftExpression() instanceof Column) { +// setTableAliasNameForColumn((Column) between.getLeftExpression(), tableAliasName); +// } +// } +// return expression; +// } +// +// private void setTableAliasNameForColumn(Column column, String tableAliasName) { +// column.setColumnName(tableAliasName + "." + column.getColumnName()); +// } +// +// /** +// * 默认是按 tenant_id=1 按等于条件追加 +// * +// * @param currentExpression 现有的条件:比如你原来的sql查询条件 +// * @param table +// * @return +// */ +// @Override +// protected Expression builderExpression(Expression currentExpression, Table table) { +// final Expression tenantExpression = this.getTenantHandler().getTenantId(true); +// Expression appendExpression; +// if (!(tenantExpression instanceof SupportsOldOracleJoinSyntax)) { +// appendExpression = new EqualsTo(); +// ((EqualsTo) appendExpression).setLeftExpression(this.getAliasColumn(table)); +// ((EqualsTo) appendExpression).setRightExpression(tenantExpression); +// } else { +// appendExpression = processTableAlias(tenantExpression, table); +// } +// if (currentExpression == null) { +// return appendExpression; +// } +// if (currentExpression instanceof BinaryExpression) { +// BinaryExpression binaryExpression = (BinaryExpression) currentExpression; +// if (binaryExpression.getLeftExpression() instanceof FromItem) { +// processFromItem((FromItem) binaryExpression.getLeftExpression()); +// } +// if (binaryExpression.getRightExpression() instanceof FromItem) { +// processFromItem((FromItem) binaryExpression.getRightExpression()); +// } +// } else if (currentExpression instanceof InExpression) { +// InExpression inExp = (InExpression) currentExpression; +// ItemsList rightItems = inExp.getRightItemsList(); +// if (rightItems instanceof SubSelect) { +// processSelectBody(((SubSelect) rightItems).getSelectBody()); +// } +// } +// if (currentExpression instanceof OrExpression) { +// return new AndExpression(new Parenthesis(currentExpression), appendExpression); +// } else { +// return new AndExpression(currentExpression, appendExpression); +// } +// } +// +// @Override +// protected void processPlainSelect(PlainSelect plainSelect, boolean addColumn) { +// FromItem fromItem = plainSelect.getFromItem(); +// if (fromItem instanceof Table) { +// Table fromTable = (Table) fromItem; +// if (!this.getTenantHandler().doTableFilter(fromTable.getName())) { +// plainSelect.setWhere(builderExpression(plainSelect.getWhere(), fromTable)); +// if (addColumn) { +// plainSelect.getSelectItems().add(new SelectExpressionItem(new Column(this.getTenantHandler().getTenantIdColumn()))); +// } +// } +// } else { +// processFromItem(fromItem); +// } +// List joins = plainSelect.getJoins(); +// if (joins != null && joins.size() > 0) { +// joins.forEach(j -> { +// processJoin(j); +// processFromItem(j.getRightItem()); +// }); +// } +// } +// +//} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusConfig.java deleted file mode 100644 index 56abfba6..00000000 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusConfig.java +++ /dev/null @@ -1,142 +0,0 @@ -package org.jeecg.config.mybatis; - -import com.baomidou.mybatisplus.core.parser.ISqlParser; -import com.baomidou.mybatisplus.core.parser.ISqlParserFilter; -import com.baomidou.mybatisplus.core.toolkit.PluginUtils; -import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; -import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler; -import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.expression.LongValue; -import net.sf.jsqlparser.expression.operators.relational.ExpressionList; -import net.sf.jsqlparser.expression.operators.relational.InExpression; -import net.sf.jsqlparser.schema.Column; -import org.apache.ibatis.reflection.MetaObject; -import org.jeecg.common.util.oConvertUtils; -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.util.ArrayList; -import java.util.List; - -/** - * 单数据源配置(jeecg.datasource.open = false时生效) - * @Author zhoujf - * - */ -@Configuration -@MapperScan(value={"org.jeecg.modules.**.mapper*"}) -public class MybatisPlusConfig { - - /** - * tenant_id 字段名 - */ - public static final String tenant_field = "tenant_id"; - - /** - * 有哪些表需要做多租户 这些表需要添加一个字段 ,字段名和tenant_field对应的值一样 - */ - private static final List tenantTable = new ArrayList(); - /** - * ddl 关键字 判断不走多租户的sql过滤 - */ - private static final List DDL_KEYWORD = new ArrayList(); - static { - tenantTable.add("jee_bug_danbiao"); - DDL_KEYWORD.add("alter"); - } - - /** - * 多租户属于 SQL 解析部分,依赖 MP 分页插件 - */ - @Bean - public PaginationInterceptor paginationInterceptor() { - PaginationInterceptor paginationInterceptor = new PaginationInterceptor().setLimit(-1); - //多租户配置 配置后每次执行sql会走一遍他的转化器 如果不需要多租户功能 可以将其注释 - tenantConfig(paginationInterceptor); - return paginationInterceptor; - } - - /** - * 多租户的配置 - * @param paginationInterceptor - */ - private void tenantConfig(PaginationInterceptor paginationInterceptor){ - /* - * 【测试多租户】 SQL 解析处理拦截器
- * 这里固定写成住户 1 实际情况你可以从cookie读取,因此数据看不到 【 麻花藤 】 这条记录( 注意观察 SQL )
- */ - List sqlParserList = new ArrayList<>(); - TenantSqlParser tenantSqlParser = new JeecgTenantParser(); - tenantSqlParser.setTenantHandler(new TenantHandler() { - - @Override - public Expression getTenantId(boolean select) { - String tenant_id = oConvertUtils.getString(TenantContext.getTenant(),"0"); - return new LongValue(tenant_id); - } - @Override - public String getTenantIdColumn() { - return tenant_field; - } - - @Override - public boolean doTableFilter(String tableName) { - //true则不加租户条件查询 false则加 - // return excludeTable.contains(tableName); - if(tenantTable.contains(tableName)){ - return false; - } - return true; - } - - private Expression in(String ids){ - final InExpression inExpression = new InExpression(); - inExpression.setLeftExpression(new Column(getTenantIdColumn())); - final ExpressionList itemsList = new ExpressionList(); - final List inValues = new ArrayList<>(2); - for(String id:ids.split(",")){ - inValues.add(new LongValue(id)); - } - itemsList.setExpressions(inValues); - inExpression.setRightItemsList(itemsList); - return inExpression; - } - - }); - - sqlParserList.add(tenantSqlParser); - paginationInterceptor.setSqlParserList(sqlParserList); - paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() { - @Override - public boolean doFilter(MetaObject metaObject) { - String sql = (String) metaObject.getValue(PluginUtils.DELEGATE_BOUNDSQL_SQL); - for(String tableName: tenantTable){ - String sql_lowercase = sql.toLowerCase(); - if(sql_lowercase.indexOf(tableName.toLowerCase())>=0){ - for(String key: DDL_KEYWORD){ - if(sql_lowercase.indexOf(key)>=0){ - return true; - } - } - return false; - } - } - /*if ("mapper路径.方法名".equals(ms.getId())) { - //使用这种判断也可以避免走此过滤器 - return true; - }*/ - return true; - } - }); - } -// /** -// * mybatis-plus SQL执行效率插件【生产环境可以关闭】 -// */ -// @Bean -// public PerformanceInterceptor performanceInterceptor() { -// return new PerformanceInterceptor(); -// } - -} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java new file mode 100644 index 00000000..6c1ff4e1 --- /dev/null +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java @@ -0,0 +1,88 @@ +package org.jeecg.config.mybatis; + +import java.util.ArrayList; +import java.util.List; + +import org.jeecg.common.util.oConvertUtils; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; + +/** + * 单数据源配置(jeecg.datasource.open = false时生效) + * @Author zhoujf + * + */ +@Configuration +@MapperScan(value={"org.jeecg.modules.**.mapper*"}) +public class MybatisPlusSaasConfig { + /** + * tenant_id 字段名 + */ + private static final String TENANT_FIELD_NAME = "tenant_id"; + /** + * 哪些表需要做多租户 表需要添加一个字段 tenant_id + */ + private static final List tenantTable = new ArrayList(); + + static { + tenantTable.add("demo"); + } + + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 先 add TenantLineInnerInterceptor 再 add PaginationInnerInterceptor + interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() { + @Override + public Expression getTenantId() { + String tenant_id = oConvertUtils.getString(TenantContext.getTenant(),"0"); + return new LongValue(tenant_id); + } + + @Override + public String getTenantIdColumn(){ + return TENANT_FIELD_NAME; + } + + // 返回 true 表示不走租户逻辑 + @Override + public boolean ignoreTable(String tableName) { + for(String temp: tenantTable){ + if(temp.equalsIgnoreCase(tableName)){ + return false; + } + } + return true; + } + })); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); + return interceptor; + } + +// /** +// * 下个版本会删除,现在为了避免缓存出现问题不得不配置 +// * @return +// */ +// @Bean +// public ConfigurationCustomizer configurationCustomizer() { +// return configuration -> configuration.setUseDeprecatedExecutor(false); +// } +// /** +// * mybatis-plus SQL执行效率插件【生产环境可以关闭】 +// */ +// @Bean +// public PerformanceInterceptor performanceInterceptor() { +// return new PerformanceInterceptor(); +// } + +} diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java index 1ea904ce..b26245fb 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java @@ -83,7 +83,6 @@ public class ShiroConfig { filterChainDefinitionMap.put("/sys/phoneLogin", "anon");//手机登录 filterChainDefinitionMap.put("/sys/user/checkOnlyUser", "anon");//校验用户是否存在 filterChainDefinitionMap.put("/sys/user/register", "anon");//用户注册 - filterChainDefinitionMap.put("/sys/user/querySysUser", "anon");//根据手机号获取用户信息 filterChainDefinitionMap.put("/sys/user/phoneVerification", "anon");//用户忘记密码验证手机号 filterChainDefinitionMap.put("/sys/user/passwordChange", "anon");//用户更改密码 filterChainDefinitionMap.put("/auth/2step-code", "anon");//登录验证码 @@ -101,9 +100,11 @@ public class ShiroConfig { filterChainDefinitionMap.put("/**/*.png", "anon"); filterChainDefinitionMap.put("/**/*.ico", "anon"); + // update-begin--Author:sunjianlei Date:20190813 for:排除字体格式的后缀 filterChainDefinitionMap.put("/**/*.ttf", "anon"); filterChainDefinitionMap.put("/**/*.woff", "anon"); filterChainDefinitionMap.put("/**/*.woff2", "anon"); + // update-begin--Author:sunjianlei Date:20190813 for:排除字体格式的后缀 filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/swagger-ui.html", "anon"); @@ -111,36 +112,26 @@ public class ShiroConfig { filterChainDefinitionMap.put("/webjars/**", "anon"); filterChainDefinitionMap.put("/v2/**", "anon"); - - // update-begin--Author:sunjianlei Date:20210510 for:排除消息通告查看详情页面(用于第三方APP) filterChainDefinitionMap.put("/sys/annountCement/show/**", "anon"); - // update-end--Author:sunjianlei Date:20210510 for:排除消息通告查看详情页面(用于第三方APP) //积木报表排除 filterChainDefinitionMap.put("/jmreport/**", "anon"); filterChainDefinitionMap.put("/**/*.js.map", "anon"); filterChainDefinitionMap.put("/**/*.css.map", "anon"); - //大屏设计器排除 - filterChainDefinitionMap.put("/bigscreen/**", "anon"); - - //测试示例 - filterChainDefinitionMap.put("/test/bigScreen/**", "anon"); //大屏模板例子 - //filterChainDefinitionMap.put("/test/jeecgDemo/rabbitMqClientTest/**", "anon"); //MQ测试 - //filterChainDefinitionMap.put("/test/jeecgDemo/html", "anon"); //模板页面 - //filterChainDefinitionMap.put("/test/jeecgDemo/redis/**", "anon"); //redis测试 + //大屏模板例子 + filterChainDefinitionMap.put("/test/bigScreen/**", "anon"); //websocket排除 filterChainDefinitionMap.put("/websocket/**", "anon");//系统通知和公告 filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块 filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例 - //性能监控 TODO 存在安全漏洞泄露TOEKN(durid连接池也有) filterChainDefinitionMap.put("/actuator/**", "anon"); // 添加自己的过滤器并且取名为jwt Map filterMap = new HashMap(1); - //如果cloudServer为空 则说明是单体 需要加载跨域配置 + //如果cloudServer为空 则说明是单体 需要加载跨域配置【微服务跨域切换】 Object cloudServer = env.getProperty(CommonConstant.CLOUD_SERVER_KEY); filterMap.put("jwt", new JwtFilter(cloudServer==null)); shiroFilterFactoryBean.setFilters(filterMap); diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java index e872f842..a1413281 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java @@ -18,6 +18,7 @@ import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.util.RedisUtil; import org.jeecg.common.util.SpringContextUtils; import org.jeecg.common.util.oConvertUtils; +import org.jeecg.config.mybatis.TenantContext; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -126,7 +127,17 @@ public class ShiroRealm extends AuthorizingRealm { if (!jwtTokenRefresh(token, username, loginUser.getPassword())) { throw new AuthenticationException("Token失效,请重新登录!"); } - + //update-begin-author:taoyan date:20210609 for:校验用户的tenant_id和前端传过来的是否一致 + String userTenantIds = loginUser.getRelTenantIds(); + if(oConvertUtils.isNotEmpty(userTenantIds)){ + String contextTenantId = TenantContext.getTenant(); + if(oConvertUtils.isNotEmpty(contextTenantId) && !"0".equals(contextTenantId)){ + if(String.join(",",userTenantIds).indexOf(contextTenantId)<0){ + throw new AuthenticationException("用户租户信息变更,请重新登陆!"); + } + } + } + //update-end-author:taoyan date:20210609 for:校验用户的tenant_id和前端传过来的是否一致 return loginUser; } diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java index e47bb7ce..f0affae7 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; import org.jeecg.common.constant.CommonConstant; +import org.jeecg.common.util.oConvertUtils; import org.jeecg.config.mybatis.TenantContext; import org.jeecg.config.shiro.JwtToken; import org.springframework.http.HttpStatus; @@ -22,6 +23,10 @@ import javax.servlet.http.HttpServletResponse; @Slf4j public class JwtFilter extends BasicHttpAuthenticationFilter { + /** + * 默认开启跨域设置(使用单体) + * 微服务情况下,此属性设置为false + */ private boolean allowOrigin = true; public JwtFilter(){} @@ -55,7 +60,7 @@ public class JwtFilter extends BasicHttpAuthenticationFilter { HttpServletRequest httpServletRequest = (HttpServletRequest) request; String token = httpServletRequest.getHeader(CommonConstant.X_ACCESS_TOKEN); // update-begin--Author:lvdandan Date:20210105 for:JT-355 OA聊天添加token验证,获取token参数 - if(token == null){ + if (oConvertUtils.isEmpty(token)) { token = httpServletRequest.getParameter("token"); } // update-end--Author:lvdandan Date:20210105 for:JT-355 OA聊天添加token验证,获取token参数 diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java index 8ca0e9be..98c1814e 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java @@ -1,8 +1,12 @@ package org.jeecg.config.sign.interceptor; -import com.alibaba.fastjson.JSON; -import lombok.extern.slf4j.Slf4j; +import java.io.PrintWriter; +import java.util.SortedMap; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.jeecg.common.api.vo.Result; import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.util.DateUtils; @@ -11,10 +15,9 @@ import org.jeecg.config.sign.util.HttpUtils; import org.jeecg.config.sign.util.SignUtil; import org.springframework.web.servlet.HandlerInterceptor; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.PrintWriter; -import java.util.SortedMap; +import com.alibaba.fastjson.JSON; + +import lombok.extern.slf4j.Slf4j; /** * 签名拦截器 diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/BodyReaderHttpServletRequestWrapper.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/BodyReaderHttpServletRequestWrapper.java index 1e596479..db42935f 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/BodyReaderHttpServletRequestWrapper.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/BodyReaderHttpServletRequestWrapper.java @@ -11,8 +11,8 @@ import java.nio.charset.Charset; /** * 保存过滤器里面的流 * - * @author show - * @date 10:03 2019/5/30 + * @author jeecg + * @date 20210621 */ public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/HttpUtils.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/HttpUtils.java index 5cbdd497..d90d3a07 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/HttpUtils.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/HttpUtils.java @@ -1,11 +1,5 @@ package org.jeecg.config.sign.util; -import com.alibaba.fastjson.JSONObject; -import lombok.extern.slf4j.Slf4j; -import org.jeecg.common.util.oConvertUtils; -import org.springframework.http.HttpMethod; - -import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -16,6 +10,14 @@ import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; +import javax.servlet.http.HttpServletRequest; + +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.util.oConvertUtils; +import org.springframework.http.HttpMethod; + +import com.alibaba.fastjson.JSONObject; + /** * http 工具类 获取请求中的参数 * diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java index 658d1c16..5b4b1705 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java @@ -2,6 +2,10 @@ package org.jeecg.config.sign.util; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.exception.JeecgBootException; +import org.jeecg.common.util.SpringContextUtils; +import org.jeecg.common.util.oConvertUtils; +import org.jeecg.config.StaticConfig; import org.springframework.util.DigestUtils; import org.springframework.util.StringUtils; @@ -10,13 +14,11 @@ import java.util.SortedMap; /** * 签名工具类 * - * @author show - * @date 10:01 2019/5/30 + * @author jeecg + * @date 20210621 */ @Slf4j public class SignUtil { - //签名密钥串(前后端要一致,正式发布请自行修改) - private static final String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a"; public static final String xPathVariable = "x-path-variable"; /** @@ -44,6 +46,11 @@ public class SignUtil { params.remove("_t"); String paramsJsonStr = JSONObject.toJSONString(params); log.info("Param paramsJsonStr : {}", paramsJsonStr); - return DigestUtils.md5DigestAsHex((paramsJsonStr+signatureSecret).getBytes()).toUpperCase(); + StaticConfig staticConfig = SpringContextUtils.getBean(StaticConfig.class); + String signatureSecret = staticConfig.getSignatureSecret(); + if(oConvertUtils.isEmpty(signatureSecret) || signatureSecret.contains("${")){ + throw new JeecgBootException("签名密钥 ${jeecg.signatureSecret} 缺少配置 !!"); + } + return DigestUtils.md5DigestAsHex((paramsJsonStr + signatureSecret).getBytes()).toUpperCase(); } } \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/BaseCommonMapper.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/BaseCommonMapper.java index d67f445e..d8eb102e 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/BaseCommonMapper.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/BaseCommonMapper.java @@ -1,6 +1,6 @@ package org.jeecg.modules.base.mapper; -import com.baomidou.mybatisplus.annotation.SqlParser; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import org.apache.ibatis.annotations.Param; import org.jeecg.common.api.dto.LogDTO; @@ -10,7 +10,8 @@ public interface BaseCommonMapper { * 保存日志 * @param dto */ - @SqlParser(filter=true) + //@SqlParser(filter=true) + @InterceptorIgnore void saveLog(@Param("dto")LogDTO dto); } diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/pom.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/pom.xml index fbaff9f4..53fe73e3 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/pom.xml +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/pom.xml @@ -4,7 +4,7 @@ org.jeecgframework.boot jeecg-boot-base - 2.4.5 + 2.4.6 4.0.0 公共模块 @@ -29,7 +29,11 @@ cn.hutool - hutool-all + hutool-core + + + cn.hutool + hutool-crypto diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/src/main/java/org/jeecg/common/constant/CacheConstant.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/src/main/java/org/jeecg/common/constant/CacheConstant.java index 04c4a40f..1926062a 100644 --- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/src/main/java/org/jeecg/common/constant/CacheConstant.java +++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/src/main/java/org/jeecg/common/constant/CacheConstant.java @@ -8,9 +8,14 @@ package org.jeecg.common.constant; public interface CacheConstant { /** - * 字典信息缓存 + * 字典信息缓存(含禁用的字典项) */ public static final String SYS_DICT_CACHE = "sys:cache:dict"; + + /** + * 字典信息缓存 status为有效的 + */ + public static final String SYS_ENABLE_DICT_CACHE = "sys:cache:dictEnable"; /** * 表字典信息缓存 */ diff --git a/jeecg-boot/jeecg-boot-base/pom.xml b/jeecg-boot/jeecg-boot-base/pom.xml index 34b5f4b6..e2b31540 100644 --- a/jeecg-boot/jeecg-boot-base/pom.xml +++ b/jeecg-boot/jeecg-boot-base/pom.xml @@ -5,7 +5,7 @@ jeecg-boot-parent org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 diff --git a/jeecg-boot/jeecg-boot-module-demo/pom.xml b/jeecg-boot/jeecg-boot-module-demo/pom.xml index d3831527..a42c31f3 100644 --- a/jeecg-boot/jeecg-boot-module-demo/pom.xml +++ b/jeecg-boot/jeecg-boot-module-demo/pom.xml @@ -5,7 +5,7 @@ jeecg-boot-parent org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 diff --git a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/entity/JeecgDemo.java b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/entity/JeecgDemo.java index 35cb6b97..e1959173 100644 --- a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/entity/JeecgDemo.java +++ b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/entity/JeecgDemo.java @@ -75,4 +75,7 @@ public class JeecgDemo extends JeecgEntity implements Serializable { /** 个人简介 */ @ApiModelProperty(value = "个人简介") private java.lang.String content; + + @ApiModelProperty(value = "租户ID") + private java.lang.Integer tenantId; } diff --git a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/mapper/xml/JeecgDemoMapper.xml b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/mapper/xml/JeecgDemoMapper.xml index 9c7759d2..fa9c6968 100644 --- a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/mapper/xml/JeecgDemoMapper.xml +++ b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/mapper/xml/JeecgDemoMapper.xml @@ -23,12 +23,12 @@ \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module-system/Dockerfile b/jeecg-boot/jeecg-boot-module-system/Dockerfile index 7ef2a80a..a77d79fe 100644 --- a/jeecg-boot/jeecg-boot-module-system/Dockerfile +++ b/jeecg-boot/jeecg-boot-module-system/Dockerfile @@ -10,6 +10,6 @@ WORKDIR /jeecg-boot EXPOSE 8080 -ADD ./target/jeecg-boot-module-system-2.4.5.jar ./ +ADD ./target/jeecg-boot-module-system-2.4.6.jar ./ -CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-2.4.5.jar \ No newline at end of file +CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-2.4.6.jar \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module-system/pom.xml b/jeecg-boot/jeecg-boot-module-system/pom.xml index 719b3a24..0fa37c00 100644 --- a/jeecg-boot/jeecg-boot-module-system/pom.xml +++ b/jeecg-boot/jeecg-boot-module-system/pom.xml @@ -4,7 +4,7 @@ org.jeecgframework.boot jeecg-boot-parent - 2.4.5 + 2.4.6 4.0.0 @@ -14,7 +14,7 @@ aliyun aliyun Repository - http://maven.aliyun.com/nexus/content/groups/public + https://maven.aliyun.com/repository/public false @@ -22,7 +22,7 @@ jeecg jeecg Repository - http://maven.jeecg.org/nexus/content/repositories/jeecg + https://maven.jeecg.org/nexus/content/repositories/jeecg false @@ -34,28 +34,35 @@ org.jeecgframework.boot jeecg-system-local-api - - org.jeecgframework - jeewx-api - 1.4.2 - - + org.jeecgframework.boot jeecg-boot-module-demo - ${jeecgboot.version} + 2.4.6 + - org.jeecgframework.jimureport - spring-boot-starter-jimureport - 1.3.4-beta + org.jeecgframework + jeewx-api + 1.4.5 - org.jeecgframework - autopoi-web + commons-beanutils + commons-beanutils + + + commons-lang + commons-lang + + + org.jeecgframework.jimureport + jimureport-spring-boot-starter + 1.3.78 + + diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/init/CodeGenerateDbConfig.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/init/CodeGenerateDbConfig.java index 99bd57e4..be63002a 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/init/CodeGenerateDbConfig.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/init/CodeGenerateDbConfig.java @@ -12,6 +12,7 @@ import org.springframework.context.annotation.Configuration; * @Description: 代码生成器,自定义DB配置 * 【加了此类,则online模式DB连接,使用平台的配置,jeecg_database.properties配置无效; * 但是使用GUI模式代码生成,还是走jeecg_database.properties配置】 + * 提醒: 达梦数据库需要修改下面的参数${spring.datasource.dynamic.datasource.master.url:}配置 * @author: scott * @date: 2021年02月18日 16:30 */ diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/controller/SystemAPIController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/controller/SystemAPIController.java index 16d2b2ce..e5cc51fb 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/controller/SystemAPIController.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/controller/SystemAPIController.java @@ -1,8 +1,8 @@ package org.jeecg.modules.api.controller; import com.alibaba.fastjson.JSONObject; -import org.jeecg.common.api.dto.message.*; import org.jeecg.common.api.dto.OnlineAuthDTO; +import org.jeecg.common.api.dto.message.*; import org.jeecg.common.system.api.ISysBaseAPI; import org.jeecg.common.system.vo.*; import org.jeecg.modules.system.service.ISysUserService; @@ -143,6 +143,17 @@ public class SystemAPIController { return sysBaseAPI.queryDictItemsByCode(code); } + /** + * 获取有效的数据字典 + * @param code + * @return + */ + @GetMapping("/queryEnableDictItemsByCode") + List queryEnableDictItemsByCode(@RequestParam("code") String code){ + return sysBaseAPI.queryEnableDictItemsByCode(code); + } + + /** 查询所有的父级字典,按照create_time排序 */ @GetMapping("/queryAllDict") List queryAllDict(){ @@ -158,17 +169,6 @@ public class SystemAPIController { return sysBaseAPI.queryAllDSysCategory(); } - /** - * 获取表数据字典 - * @param table - * @param text - * @param code - * @return - */ - @GetMapping("/queryTableDictItemsByCode") - List queryTableDictItemsByCode(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code){ - return sysBaseAPI.queryTableDictItemsByCode(table, text, code); - } /** * 查询所有部门 作为字典信息 id -->value,departName -->text @@ -179,34 +179,6 @@ public class SystemAPIController { return sysBaseAPI.queryAllDepartBackDictModel(); } - - /** - * 查询表字典 支持过滤数据 - * @param table - * @param text - * @param code - * @param filterSql - * @return - */ - @GetMapping("/queryFilterTableDictInfo") - List queryFilterTableDictInfo(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("filterSql") String filterSql){ - return sysBaseAPI.queryFilterTableDictInfo(table, text, code, filterSql); - } - - /** - * 查询指定table的 text code 获取字典,包含text和value - * @param table - * @param text - * @param code - * @param keyArray - * @return - */ - @Deprecated - @GetMapping("/queryTableDictByKeys") - public List queryTableDictByKeys(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("keyArray") String[] keyArray){ - return sysBaseAPI.queryTableDictByKeys(table, text, code, keyArray); - } - /** * 获取所有角色 带参 * roleIds 默认选中角色 @@ -447,19 +419,6 @@ public class SystemAPIController { return sysBaseAPI.getCacheUser(username); } - /** - * 字典表的 翻译 - * @param table - * @param text - * @param code - * @param key - * @return - */ - @GetMapping("/translateDictFromTable") - public String translateDictFromTable(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("key") String key){ - return sysBaseAPI.translateDictFromTable(table, text, code, key); - } - /** * 普通字典的翻译 * @param code @@ -477,18 +436,18 @@ public class SystemAPIController { * @param usernames * @return */ - @GetMapping("/queryUsersByUsernames") - List queryUsersByUsernames(String usernames){ + @RequestMapping("/queryUsersByUsernames") + List queryUsersByUsernames(@RequestParam("usernames") String usernames){ return this.sysBaseAPI.queryUsersByUsernames(usernames); } /** * 37根据多个用户id(逗号分隔),查询返回多个用户信息 - * @param usernames + * @param ids * @return */ - @GetMapping("/queryUsersByIds") - List queryUsersByIds(String ids){ + @RequestMapping("/queryUsersByIds") + List queryUsersByIds(@RequestParam("ids") String ids){ return this.sysBaseAPI.queryUsersByIds(ids); } @@ -498,18 +457,18 @@ public class SystemAPIController { * @return */ @GetMapping("/queryDepartsByOrgcodes") - List queryDepartsByOrgcodes(String orgCodes){ + List queryDepartsByOrgcodes(@RequestParam("orgCodes") String orgCodes){ return this.sysBaseAPI.queryDepartsByOrgcodes(orgCodes); } /** * 39根据多个部门ID(逗号分隔),查询返回多个部门信息 - * @param orgCodes + * @param ids * @return */ @GetMapping("/queryDepartsByIds") - List queryDepartsByIds(String orgCodes){ - return this.sysBaseAPI.queryDepartsByIds(orgCodes); + List queryDepartsByIds(@RequestParam("ids") String ids){ + return this.sysBaseAPI.queryDepartsByIds(ids); } /** @@ -530,4 +489,146 @@ public class SystemAPIController { List getDeptUserByOrgCode(@RequestParam("orgCode")String orgCode){ return this.sysBaseAPI.getDeptUserByOrgCode(orgCode); } + + /** + * 查询分类字典翻译 + * + * @param ids 分类字典表id + * @return + */ + @GetMapping("/loadCategoryDictItem") + public List loadCategoryDictItem(@RequestParam("ids") String ids) { + return sysBaseAPI.loadCategoryDictItem(ids); + } + + /** + * 根据字典code加载字典text + * + * @param dictCode 顺序:tableName,text,code + * @param keys 要查询的key + * @return + */ + @GetMapping("/loadDictItem") + public List loadDictItem(@RequestParam("dictCode") String dictCode, @RequestParam("keys") String keys) { + return sysBaseAPI.loadDictItem(dictCode, keys); + } + + /** + * 根据字典code查询字典项 + * + * @param dictCode 顺序:tableName,text,code + * @param dictCode 要查询的key + * @return + */ + @GetMapping("/getDictItems") + public List getDictItems(@RequestParam("dictCode") String dictCode) { + return sysBaseAPI.getDictItems(dictCode); + } + + /** + * 根据多个字典code查询多个字典项 + * + * @param dictCodeList + * @return key = dictCode ; value=对应的字典项 + */ + @RequestMapping("/getManyDictItems") + public Map> getManyDictItems(@RequestParam("dictCodeList") List dictCodeList) { + return sysBaseAPI.getManyDictItems(dictCodeList); + } + + /** + * 【下拉搜索】 + * 大数据量的字典表 走异步加载,即前端输入内容过滤数据 + * + * @param dictCode 字典code格式:table,text,code + * @param keyword 过滤关键字 + * @return + */ + @GetMapping("/loadDictItemByKeyword") + public List loadDictItemByKeyword(@RequestParam("dictCode") String dictCode, @RequestParam("keyword") String keyword, @RequestParam(value = "pageSize", required = false) Integer pageSize) { + return sysBaseAPI.loadDictItemByKeyword(dictCode, keyword, pageSize); + } + + /** + * 48 普通字典的翻译,根据多个dictCode和多条数据,多个以逗号分割 + * @param dictCodes + * @param keys + * @return + */ + @GetMapping("/translateManyDict") + public Map> translateManyDict(@RequestParam("dictCodes") String dictCodes, @RequestParam("keys") String keys){ + return this.sysBaseAPI.translateManyDict(dictCodes, keys); + } + + + /** + * 获取表数据字典 【接口签名验证】 + * @param table + * @param text + * @param code + * @return + */ + @GetMapping("/queryTableDictItemsByCode") + List queryTableDictItemsByCode(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code){ + return sysBaseAPI.queryTableDictItemsByCode(table, text, code); + } + + /** + * 查询表字典 支持过滤数据 【接口签名验证】 + * @param table + * @param text + * @param code + * @param filterSql + * @return + */ + @GetMapping("/queryFilterTableDictInfo") + List queryFilterTableDictInfo(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("filterSql") String filterSql){ + return sysBaseAPI.queryFilterTableDictInfo(table, text, code, filterSql); + } + + /** + * 【接口签名验证】 + * 查询指定table的 text code 获取字典,包含text和value + * @param table + * @param text + * @param code + * @param keyArray + * @return + */ + @Deprecated + @GetMapping("/queryTableDictByKeys") + public List queryTableDictByKeys(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("keyArray") String[] keyArray){ + return sysBaseAPI.queryTableDictByKeys(table, text, code, keyArray); + } + + + /** + * 字典表的 翻译【接口签名验证】 + * @param table + * @param text + * @param code + * @param key + * @return + */ + @GetMapping("/translateDictFromTable") + public String translateDictFromTable(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("key") String key){ + return sysBaseAPI.translateDictFromTable(table, text, code, key); + } + + + /** + * 【接口签名验证】 + * 49 字典表的 翻译,可批量 + * + * @param table + * @param text + * @param code + * @param keys 多个用逗号分割 + * @return + */ + @GetMapping("/translateDictFromTableByKeys") + public List translateDictFromTableByKeys(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("keys") String keys) { + return this.sysBaseAPI.translateDictFromTableByKeys(table, text, code, keys); + } + } diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/service/impl/QuartzJobServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/service/impl/QuartzJobServiceImpl.java index 3d68fc66..67e8b528 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/service/impl/QuartzJobServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/service/impl/QuartzJobServiceImpl.java @@ -11,6 +11,7 @@ import org.jeecg.modules.quartz.service.IQuartzJobService; import org.quartz.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.List; @@ -43,6 +44,7 @@ public class QuartzJobServiceImpl extends ServiceImpl userInfo(SysUser sysUser, Result result) { String syspassword = sysUser.getPassword(); String username = sysUser.getUsername(); - // 生成token - String token = JwtUtil.sign(username, syspassword); - // 设置token缓存有效时间 - redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); - redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000); - // 获取用户部门信息 JSONObject obj = new JSONObject(); List departs = sysDepartService.queryUserDeparts(sysUser.getId()); @@ -382,6 +375,25 @@ public class LoginController { // update-end--Author:wangshuai Date:20200805 for:如果用戶为选择部门,数据库为存在上一次登录部门,则取一条存进去 obj.put("multi_depart", 2); } + // update-begin--Author:sunjianlei Date:20210802 for:获取用户租户信息 + String tenantIds = sysUser.getRelTenantIds(); + if (oConvertUtils.isNotEmpty(tenantIds)) { + List tenantIdList = Arrays.asList(tenantIds.split(",")); + // 该方法仅查询有效的租户,如果返回0个就说明所有的租户均无效。 + List tenantList = sysTenantService.queryEffectiveTenant(tenantIdList); + if (tenantList.size() == 0) { + result.error500("与该用户关联的租户均已被冻结,无法登录!"); + return result; + } else { + obj.put("tenantList", tenantList); + } + } + // update-end--Author:sunjianlei Date:20210802 for:获取用户租户信息 + // 生成token + String token = JwtUtil.sign(username, syspassword); + // 设置token缓存有效时间 + redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); + redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000); obj.put("token", token); obj.put("userInfo", sysUser); obj.put("sysAllDictItems", sysDictService.queryAllDictItems()); diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java index 55ef63fc..65e30bc4 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java @@ -26,6 +26,7 @@ import org.jeecg.modules.system.service.ISysAnnouncementSendService; import org.jeecg.modules.system.service.ISysAnnouncementService; import org.jeecg.modules.system.service.impl.ThirdAppDingtalkServiceImpl; import org.jeecg.modules.system.service.impl.ThirdAppWechatEnterpriseServiceImpl; +import org.jeecg.modules.system.util.XSSUtils; import org.jeecgframework.poi.excel.ExcelImportUtil; import org.jeecgframework.poi.excel.def.NormalExcelConstants; import org.jeecgframework.poi.excel.entity.ExportParams; @@ -119,6 +120,10 @@ public class SysAnnouncementController { public Result add(@RequestBody SysAnnouncement sysAnnouncement) { Result result = new Result(); try { + // update-begin-author:liusq date:20210804 for:标题处理xss攻击的问题 + String title = XSSUtils.striptXSS(sysAnnouncement.getTitile()); + sysAnnouncement.setTitile(title); + // update-end-author:liusq date:20210804 for:标题处理xss攻击的问题 sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_0.toString()); sysAnnouncement.setSendStatus(CommonSendStatus.UNPUBLISHED_STATUS_0);//未发布 sysAnnouncementService.saveAnnouncement(sysAnnouncement); @@ -142,6 +147,10 @@ public class SysAnnouncementController { if(sysAnnouncementEntity==null) { result.error500("未找到对应实体"); }else { + // update-begin-author:liusq date:20210804 for:标题处理xss攻击的问题 + String title = XSSUtils.striptXSS(sysAnnouncement.getTitile()); + sysAnnouncement.setTitile(title); + // update-end-author:liusq date:20210804 for:标题处理xss攻击的问题 boolean ok = sysAnnouncementService.upDateAnnouncement(sysAnnouncement); //TODO 返回false说明什么? if(ok) { diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java index 3a7768f9..84562383 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.annotation.RequiresRoles; import org.jeecg.common.api.vo.Result; @@ -71,8 +72,13 @@ public class SysDepartController { LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal(); try { if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals( CommonConstant.USER_IDENTITY_2 )){ - List list = sysDepartService.queryMyDeptTreeList(user.getDepartIds()); - result.setResult(list); + //update-begin--Author:liusq Date:20210624 for:部门查询ids为空后的前端显示问题 issues/I3UD06 + String departIds = user.getDepartIds(); + if(StringUtils.isNotBlank(departIds)){ + List list = sysDepartService.queryMyDeptTreeList(departIds); + result.setResult(list); + } + //update-end--Author:liusq Date:20210624 for:部门查询ids为空后的前端显示问题 issues/I3UD06 result.setMessage(CommonConstant.USER_IDENTITY_2.toString()); result.setSuccess(true); }else{ diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java index cdbcac6b..6d6b6c03 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java @@ -111,33 +111,6 @@ public class SysDictController { return result; } - /** - * 获取字典数据 - * @param dictCode 字典code - * @param dictCode 表名,文本字段,code字段 | 举例:sys_user,realname,id - * @return - */ - @RequestMapping(value = "/getDictItems/{dictCode}", method = RequestMethod.GET) - public Result> getDictItems(@PathVariable String dictCode, @RequestParam(value = "sign",required = false) String sign,HttpServletRequest request) { - log.info(" dictCode : "+ dictCode); - Result> result = new Result>(); - try { - List ls = sysDictService.getDictItems(dictCode); - if (ls == null) { - result.error500("字典Code格式不正确!"); - return result; - } - result.setSuccess(true); - result.setResult(ls); - log.debug(result.toString()); - } catch (Exception e) { - log.error(e.getMessage(), e); - result.error500("操作失败"); - return result; - } - return result; - } - /** * 获取全部字典数据 * @@ -172,7 +145,36 @@ public class SysDictController { return result; } + /** + * 获取字典数据 【接口签名验证】 + * @param dictCode 字典code + * @param dictCode 表名,文本字段,code字段 | 举例:sys_user,realname,id + * @return + */ + @RequestMapping(value = "/getDictItems/{dictCode}", method = RequestMethod.GET) + public Result> getDictItems(@PathVariable String dictCode, @RequestParam(value = "sign",required = false) String sign,HttpServletRequest request) { + log.info(" dictCode : "+ dictCode); + Result> result = new Result>(); + try { + List ls = sysDictService.getDictItems(dictCode); + if (ls == null) { + result.error500("字典Code格式不正确!"); + return result; + } + result.setSuccess(true); + result.setResult(ls); + log.debug(result.toString()); + } catch (Exception e) { + log.error(e.getMessage(), e); + result.error500("操作失败"); + return result; + } + return result; + } + + /** + * 【接口签名验证】 * 【JSearchSelectTag下拉搜索组件专用接口】 * 大数据量的字典表 走异步加载 即前端输入内容过滤数据 * @param dictCode 字典code格式:table,text,code @@ -203,6 +205,7 @@ public class SysDictController { } /** + * 【接口签名验证】 * 【给表单设计器的表字典使用】下拉搜索模式,有值时动态拼接数据 * @param dictCode * @param keyword 当前控件的值,可以逗号分割 @@ -243,7 +246,7 @@ public class SysDictController { } /** - * + * 【接口签名验证】 * 根据字典code加载字典text 返回 * @param dictCode 顺序:tableName,text,code * @param keys 要查询的key @@ -280,6 +283,7 @@ public class SysDictController { } /** + * 【接口签名验证】 * 根据表名——显示字段-存储字段 pid 加载树形数据 */ @SuppressWarnings("unchecked") @@ -378,7 +382,7 @@ public class SysDictController { */ //@RequiresRoles({"admin"}) @RequestMapping(value = "/delete", method = RequestMethod.DELETE) - @CacheEvict(value=CacheConstant.SYS_DICT_CACHE, allEntries=true) + @CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true) public Result delete(@RequestParam(name="id",required=true) String id) { Result result = new Result(); boolean ok = sysDictService.removeById(id); @@ -397,7 +401,7 @@ public class SysDictController { */ //@RequiresRoles({"admin"}) @RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE) - @CacheEvict(value= CacheConstant.SYS_DICT_CACHE, allEntries=true) + @CacheEvict(value= {CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true) public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { Result result = new Result(); if(oConvertUtils.isEmpty(ids)) { @@ -418,6 +422,7 @@ public class SysDictController { Result result = new Result(); //清空字典缓存 Set keys = redisTemplate.keys(CacheConstant.SYS_DICT_CACHE + "*"); + Set keys7 = redisTemplate.keys(CacheConstant.SYS_ENABLE_DICT_CACHE + "*"); Set keys2 = redisTemplate.keys(CacheConstant.SYS_DICT_TABLE_CACHE + "*"); Set keys21 = redisTemplate.keys(CacheConstant.SYS_DICT_TABLE_BY_KEYS_CACHE + "*"); Set keys3 = redisTemplate.keys(CacheConstant.SYS_DEPARTS_CACHE + "*"); @@ -431,6 +436,7 @@ public class SysDictController { redisTemplate.delete(keys4); redisTemplate.delete(keys5); redisTemplate.delete(keys6); + redisTemplate.delete(keys7); return result; } @@ -562,7 +568,7 @@ public class SysDictController { } /** - * 取回 + * 逻辑删除的字段,进行取回 * @param id * @return */ diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictItemController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictItemController.java index 84d1b91e..7e927ea3 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictItemController.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictItemController.java @@ -73,7 +73,7 @@ public class SysDictItemController { */ //@RequiresRoles({"admin"}) @RequestMapping(value = "/add", method = RequestMethod.POST) - @CacheEvict(value= CacheConstant.SYS_DICT_CACHE, allEntries=true) + @CacheEvict(value= {CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true) public Result add(@RequestBody SysDictItem sysDictItem) { Result result = new Result(); try { @@ -94,7 +94,7 @@ public class SysDictItemController { */ //@RequiresRoles({"admin"}) @RequestMapping(value = "/edit", method = RequestMethod.PUT) - @CacheEvict(value=CacheConstant.SYS_DICT_CACHE, allEntries=true) + @CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true) public Result edit(@RequestBody SysDictItem sysDictItem) { Result result = new Result(); SysDictItem sysdict = sysDictItemService.getById(sysDictItem.getId()); @@ -118,7 +118,7 @@ public class SysDictItemController { */ //@RequiresRoles({"admin"}) @RequestMapping(value = "/delete", method = RequestMethod.DELETE) - @CacheEvict(value=CacheConstant.SYS_DICT_CACHE, allEntries=true) + @CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true) public Result delete(@RequestParam(name="id",required=true) String id) { Result result = new Result(); SysDictItem joinSystem = sysDictItemService.getById(id); @@ -140,7 +140,7 @@ public class SysDictItemController { */ //@RequiresRoles({"admin"}) @RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE) - @CacheEvict(value=CacheConstant.SYS_DICT_CACHE, allEntries=true) + @CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true) public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { Result result = new Result(); if(ids==null || "".equals(ids.trim())) { diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java index 6b2a0f26..a9736848 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java @@ -5,11 +5,11 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; -import org.apache.shiro.authz.annotation.RequiresRoles; import org.jeecg.common.api.vo.Result; import org.jeecg.common.constant.CommonConstant; -import org.jeecg.common.system.util.JwtUtil; +import org.jeecg.common.constant.enums.RoleIndexConfigEnum; import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.util.MD5Util; import org.jeecg.common.util.oConvertUtils; @@ -52,6 +52,9 @@ public class SysPermissionController { @Autowired private ISysDepartPermissionService sysDepartPermissionService; + @Autowired + private ISysUserService sysUserService; + /** * 加载数据节点 * @@ -212,6 +215,18 @@ public class SysPermissionController { //update-begin-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存 if(!PermissionDataUtil.hasIndexPage(metaList)){ SysPermission indexMenu = sysPermissionService.list(new LambdaQueryWrapper().eq(SysPermission::getName,"首页")).get(0); + //update-begin--Author:liusq Date:20210624 for:自定义首页地址LOWCOD-1578 + List roles = sysUserService.getRole(loginUser.getUsername()); + if(roles.size()>0){ + for (String code:roles) { + String componentUrl = RoleIndexConfigEnum.getIndexByCode(code); + if(StringUtils.isNotBlank(componentUrl)){ + indexMenu.setComponent(componentUrl); + break; + } + } + } + //update-end--Author:liusq Date:20210624 for:自定义首页地址LOWCOD-1578 metaList.add(0,indexMenu); } //update-end-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存 diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java index 7fbbc737..90533c4f 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java @@ -14,9 +14,9 @@ import org.jeecg.modules.system.entity.SysTenant; import org.jeecg.modules.system.service.ISysTenantService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; + import javax.servlet.http.HttpServletRequest; -import java.util.Arrays; -import java.util.Date; +import java.util.ArrayList; import java.util.List; /** @@ -99,7 +99,7 @@ public class SysTenantController { */ @RequestMapping(value = "/delete", method = RequestMethod.DELETE) public Result delete(@RequestParam(name="id",required=true) String id) { - sysTenantService.removeById(id); + sysTenantService.removeTenantById(id); return Result.ok("删除成功"); } @@ -114,9 +114,25 @@ public class SysTenantController { if(oConvertUtils.isEmpty(ids)) { result.error500("未选中租户!"); }else { - List ls = Arrays.asList(ids.split(",")); - sysTenantService.removeByIds(ls); - result.success("删除成功!"); + String[] ls = ids.split(","); + // 过滤掉已被引用的租户 + List idList = new ArrayList<>(); + for (String id : ls) { + int userCount = sysTenantService.countUserLinkTenant(id); + if (userCount == 0) { + idList.add(id); + } + } + if (idList.size() > 0) { + sysTenantService.removeByIds(idList); + if (ls.length == idList.size()) { + result.success("删除成功!"); + } else { + result.success("部分删除成功!(被引用的租户无法删除)"); + } + }else { + result.error500("选择的租户都已被引用,无法删除!"); + } } return result; } diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java index ce20f8e1..c94495b9 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java @@ -942,42 +942,42 @@ public class SysUserController { return result; } - /** - * 根据用户名或手机号查询用户信息 - * @param - * @return - */ - @GetMapping("/querySysUser") - public Result> querySysUser(SysUser sysUser) { - String phone = sysUser.getPhone(); - String username = sysUser.getUsername(); - Result> result = new Result>(); - Map map = new HashMap(); - if (oConvertUtils.isNotEmpty(phone)) { - SysUser user = sysUserService.getUserByPhone(phone); - if(user!=null) { - map.put("username",user.getUsername()); - map.put("phone",user.getPhone()); - result.setSuccess(true); - result.setResult(map); - return result; - } - } - if (oConvertUtils.isNotEmpty(username)) { - SysUser user = sysUserService.getUserByName(username); - if(user!=null) { - map.put("username",user.getUsername()); - map.put("phone",user.getPhone()); - result.setSuccess(true); - result.setResult(map); - return result; - } - } - result.setSuccess(false); - result.setMessage("验证失败"); - return result; - } - +// /** +// * 根据用户名或手机号查询用户信息 +// * @param +// * @return +// */ +// @GetMapping("/querySysUser") +// public Result> querySysUser(SysUser sysUser) { +// String phone = sysUser.getPhone(); +// String username = sysUser.getUsername(); +// Result> result = new Result>(); +// Map map = new HashMap(); +// if (oConvertUtils.isNotEmpty(phone)) { +// SysUser user = sysUserService.getUserByPhone(phone); +// if(user!=null) { +// map.put("username",user.getUsername()); +// map.put("phone",user.getPhone()); +// result.setSuccess(true); +// result.setResult(map); +// return result; +// } +// } +// if (oConvertUtils.isNotEmpty(username)) { +// SysUser user = sysUserService.getUserByName(username); +// if(user!=null) { +// map.put("username",user.getUsername()); +// map.put("phone",user.getPhone()); +// result.setSuccess(true); +// result.setResult(map); +// return result; +// } +// } +// result.setSuccess(false); +// result.setMessage("验证失败"); +// return result; +// } + /** * 用户手机号验证 */ @@ -1028,7 +1028,7 @@ public class SysUserController { result.setSuccess(false); return result; } - if(!smscode.equals(object)) { + if(!smscode.equals(object.toString())) { result.setMessage("短信验证码不匹配!"); result.setSuccess(false); return result; @@ -1347,7 +1347,7 @@ public class SysUserController { result.setSuccess(false); return result; } - if(!smscode.equals(object)) { + if(!smscode.equals(object.toString())) { result.setMessage("短信验证码不匹配!"); result.setSuccess(false); return result; @@ -1361,5 +1361,21 @@ public class SysUserController { return Result.ok("手机号设置成功!"); } - + + /** + * 根据对象里面的属性值作in查询 属性可能会变 用户组件用到 + * @param sysUser + * @return + */ + @GetMapping("/getMultiUser") + public List getMultiUser(SysUser sysUser){ + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(sysUser, null); + List ls = this.sysUserService.list(queryWrapper); + for(SysUser user: ls){ + user.setPassword(null); + user.setSalt(null); + } + return ls; + } + } diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysOnlineController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java similarity index 83% rename from jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysOnlineController.java rename to jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java index 8c7c1f2a..4262cbfc 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysOnlineController.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java @@ -1,7 +1,11 @@ package org.jeecg.modules.system.controller; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import lombok.extern.slf4j.Slf4j; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Resource; import org.apache.commons.lang.StringUtils; import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.vo.Result; @@ -14,17 +18,15 @@ import org.jeecg.common.util.RedisUtil; import org.jeecg.common.util.oConvertUtils; import org.jeecg.modules.base.service.BaseCommonService; import org.jeecg.modules.system.service.ISysUserService; -import org.jeecg.modules.system.vo.SysOnlineVO; +import org.jeecg.modules.system.vo.SysUserOnlineVO; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.*; -import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import lombok.extern.slf4j.Slf4j; /** * @Description: 在线用户 @@ -35,7 +37,7 @@ import java.util.List; @RestController @RequestMapping("/sys/online") @Slf4j -public class SysOnlineController { +public class SysUserOnlineController { @Autowired private RedisUtil redisUtil; @@ -53,13 +55,13 @@ public class SysOnlineController { private BaseCommonService baseCommonService; @RequestMapping(value = "/list", method = RequestMethod.GET) - public Result> list(@RequestParam(name="username", required=false) String username, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, - @RequestParam(name="pageSize", defaultValue="10") Integer pageSize) { + public Result> list(@RequestParam(name="username", required=false) String username, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, + @RequestParam(name="pageSize", defaultValue="10") Integer pageSize) { Collection keys = redisTemplate.keys(CommonConstant.PREFIX_USER_TOKEN + "*"); - SysOnlineVO online; - List onlineList = new ArrayList(); + SysUserOnlineVO online; + List onlineList = new ArrayList(); for (String key : keys) { - online = new SysOnlineVO(); + online = new SysUserOnlineVO(); String token = (String) redisUtil.get(key); if (!StringUtils.isEmpty(token)){ online.setToken(token); @@ -75,9 +77,9 @@ public class SysOnlineController { } } - Page page = new Page(pageNo, pageSize); + Page page = new Page(pageNo, pageSize); int count = onlineList.size(); - List pages = new ArrayList<>(); + List pages = new ArrayList<>(); //计算当前页第一条数据的下标 int currId = pageNo>1 ? (pageNo-1)*pageSize:0; for (int i=0; i> result = new Result>(); + Result> result = new Result>(); result.setSuccess(true); result.setResult(page); return result; @@ -102,7 +104,7 @@ public class SysOnlineController { * 强退用户 */ @RequestMapping(value = "/forceLogout",method = RequestMethod.POST) - public Result forceLogout(@RequestBody SysOnlineVO online) { + public Result forceLogout(@RequestBody SysUserOnlineVO online) { //用户退出逻辑 if(oConvertUtils.isEmpty(online.getToken())) { return Result.error("退出登录失败!"); diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java index 69cc20d8..65aca763 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java @@ -1,6 +1,5 @@ package org.jeecg.modules.system.controller; -import cn.hutool.crypto.SecureUtil; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.xkcoding.justauth.AuthRequestFactory; @@ -11,18 +10,22 @@ import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.request.AuthRequest; import me.zhyd.oauth.utils.AuthStateUtils; import org.jeecg.common.api.vo.Result; -import org.jeecg.common.constant.CacheConstant; import org.jeecg.common.constant.CommonConstant; -import org.jeecg.common.util.*; -import org.jeecg.modules.base.service.BaseCommonService; import org.jeecg.common.system.util.JwtUtil; -import org.jeecg.common.system.vo.LoginUser; +import org.jeecg.common.util.PasswordUtil; +import org.jeecg.common.util.RedisUtil; +import org.jeecg.common.util.RestUtil; +import org.jeecg.common.util.oConvertUtils; +import org.jeecg.config.thirdapp.ThirdAppConfig; +import org.jeecg.config.thirdapp.ThirdAppTypeItemVo; +import org.jeecg.modules.base.service.BaseCommonService; import org.jeecg.modules.system.entity.SysThirdAccount; import org.jeecg.modules.system.entity.SysUser; import org.jeecg.modules.system.model.ThirdLoginModel; import org.jeecg.modules.system.service.ISysThirdAccountService; import org.jeecg.modules.system.service.ISysUserService; -import org.springframework.beans.BeanUtils; +import org.jeecg.modules.system.service.impl.ThirdAppDingtalkServiceImpl; +import org.jeecg.modules.system.service.impl.ThirdAppWechatEnterpriseServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; @@ -30,7 +33,8 @@ import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.Date; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.List; /** @@ -45,7 +49,7 @@ public class ThirdLoginController { private ISysUserService sysUserService; @Autowired private ISysThirdAccountService sysThirdAccountService; - + @Autowired private BaseCommonService baseCommonService; @Autowired @@ -53,6 +57,13 @@ public class ThirdLoginController { @Autowired private AuthRequestFactory factory; + @Autowired + ThirdAppConfig thirdAppConfig; + @Autowired + private ThirdAppWechatEnterpriseServiceImpl thirdAppWechatEnterpriseService; + @Autowired + private ThirdAppDingtalkServiceImpl thirdAppDingtalkService; + @RequestMapping("/render/{source}") public void render(@PathVariable("source") String source, HttpServletResponse response) throws IOException { log.info("第三方登录进入render:" + source); @@ -61,7 +72,7 @@ public class ThirdLoginController { log.info("第三方登录认证地址:" + authorizeUrl); response.sendRedirect(authorizeUrl); } - + @RequestMapping("/{source}/callback") public String loginThird(@PathVariable("source") String source, AuthCallback callback,ModelMap modelMap) { log.info("第三方登录进入callback:" + source + " params:" + JSONObject.toJSONString(callback)); @@ -70,7 +81,7 @@ public class ThirdLoginController { log.info(JSONObject.toJSONString(response)); Result result = new Result(); if(response.getCode()==2000) { - + JSONObject data = JSONObject.parseObject(JSONObject.toJSONString(response.getData())); String username = data.getString("username"); String avatar = data.getString("avatar"); @@ -86,7 +97,7 @@ public class ThirdLoginController { SysThirdAccount user = null; if(thridList==null || thridList.size()==0) { //否则直接创建新账号 - user = saveThirdUser(tlm); + user = sysThirdAccountService.saveThirdUser(tlm); }else { //已存在 只设置用户名 不设置头像 user = thridList.get(0); @@ -130,7 +141,7 @@ public class ThirdLoginController { } //创建新账号 //update-begin-author:wangshuai date:20201118 for:修改成从第三方登录查出来的user_id,在查询用户表尽行token - SysThirdAccount user = saveThirdUser(model); + SysThirdAccount user = sysThirdAccountService.saveThirdUser(model); if(oConvertUtils.isNotEmpty(user.getSysUserId())){ String sysUserId = user.getSysUserId(); SysUser sysUser = sysUserService.getById(sysUserId); @@ -173,7 +184,7 @@ public class ThirdLoginController { result.setSuccess(false); return result; } - + sysUserService.updateById(user); result.setSuccess(true); // 生成token @@ -182,22 +193,6 @@ public class ThirdLoginController { return result; } - /** - * 创建新用户 - * @param tlm 第三方登录信息 - */ - private SysThirdAccount saveThirdUser(ThirdLoginModel tlm){ - SysThirdAccount user = new SysThirdAccount(); - user.setDelFlag(CommonConstant.DEL_FLAG_0); - user.setStatus(1); - user.setThirdType(tlm.getSource()); - user.setAvatar(tlm.getAvatar()); - user.setRealname(tlm.getUsername()); - user.setThirdUserUuid(tlm.getUuid()); - sysThirdAccountService.save(user); - return user; - } - private String saveToken(SysUser user) { // 生成token String token = JwtUtil.sign(user.getUsername(), user.getPassword()); @@ -206,14 +201,14 @@ public class ThirdLoginController { redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000); return token; } - + @SuppressWarnings("unchecked") @RequestMapping(value = "/getLoginUser/{token}/{thirdType}", method = RequestMethod.GET) @ResponseBody public Result getThirdLoginUser(@PathVariable("token") String token,@PathVariable("thirdType") String thirdType) throws Exception { Result result = new Result(); String username = JwtUtil.getUsername(token); - + //1. 校验用户是否有效 SysUser sysUser = sysUserService.getUserByName(username); result = sysUserService.checkUserIsEffective(sysUser); @@ -277,4 +272,118 @@ public class ThirdLoginController { result.setResult(token); return result; } + + /** + * 企业微信/钉钉 OAuth2登录 + * + * @param source + * @param state + * @return + */ + @ResponseBody + @GetMapping("/oauth2/{source}/login") + public String oauth2LoginCallback(@PathVariable("source") String source, @RequestParam("state") String state, HttpServletResponse response) throws Exception { + String url; + if (ThirdAppConfig.WECHAT_ENTERPRISE.equalsIgnoreCase(source)) { + ThirdAppTypeItemVo config = thirdAppConfig.getWechatEnterprise(); + StringBuilder builder = new StringBuilder(); + // 构造企业微信OAuth2登录授权地址 + builder.append("https://open.weixin.qq.com/connect/oauth2/authorize"); + // 企业的CorpID + builder.append("?appid=").append(config.getClientId()); + // 授权后重定向的回调链接地址,请使用urlencode对链接进行处理 + String redirectUri = RestUtil.getBaseUrl() + "/sys/thirdLogin/oauth2/wechat_enterprise/callback"; + builder.append("&redirect_uri=").append(URLEncoder.encode(redirectUri, "UTF-8")); + // 返回类型,此时固定为:code + builder.append("&response_type=code"); + // 应用授权作用域。 + // snsapi_base:静默授权,可获取成员的的基础信息(UserId与DeviceId); + builder.append("&scope=snsapi_base"); + // 重定向后会带上state参数,长度不可超过128个字节 + builder.append("&state=").append(state); + // 终端使用此参数判断是否需要带上身份信息 + builder.append("#wechat_redirect"); + url = builder.toString(); + } else if (ThirdAppConfig.DINGTALK.equalsIgnoreCase(source)) { + ThirdAppTypeItemVo config = thirdAppConfig.getDingtalk(); + StringBuilder builder = new StringBuilder(); + // 构造钉钉OAuth2登录授权地址 + builder.append("https://login.dingtalk.com/oauth2/auth"); + // 授权通过/拒绝后回调地址。 + // 注意 需要与注册应用时登记的域名保持一致。 + String redirectUri = RestUtil.getBaseUrl() + "/sys/thirdLogin/oauth2/dingtalk/callback"; + builder.append("?redirect_uri=").append(URLEncoder.encode(redirectUri, "UTF-8")); + // 固定值为code。 + // 授权通过后返回authCode。 + builder.append("&response_type=code"); + // 步骤一中创建的应用详情中获取。 + // 企业内部应用:client_id为应用的AppKey。 + builder.append("&client_id=").append(config.getClientId()); + // 授权范围,授权页面显示的授权信息以应用注册时配置的为准。 + // openid:授权后可获得用户userid + builder.append("&scope=openid"); + // 跟随authCode原样返回。 + builder.append("&state=").append(state); + url = builder.toString(); + } else { + return "不支持的source"; + } + log.info("oauth2 login url:" + url); + response.sendRedirect(url); + return "login…"; + } + + /** + * 企业微信/钉钉 OAuth2登录回调 + * + * @param code + * @param state + * @param response + * @return + */ + @ResponseBody + @GetMapping("/oauth2/{source}/callback") + public String oauth2LoginCallback( + @PathVariable("source") String source, + // 企业微信返回的code + @RequestParam(value = "code", required = false) String code, + // 钉钉返回的code + @RequestParam(value = "authCode", required = false) String authCode, + @RequestParam("state") String state, + HttpServletResponse response + ) { + SysUser loginUser; + if (ThirdAppConfig.WECHAT_ENTERPRISE.equalsIgnoreCase(source)) { + log.info("【企业微信】OAuth2登录进入callback:code=" + code + ", state=" + state); + loginUser = thirdAppWechatEnterpriseService.oauth2Login(code); + if (loginUser == null) { + return "登录失败"; + } + } else if (ThirdAppConfig.DINGTALK.equalsIgnoreCase(source)) { + log.info("【钉钉】OAuth2登录进入callback:authCode=" + authCode + ", state=" + state); + loginUser = thirdAppDingtalkService.oauth2Login(authCode); + if (loginUser == null) { + return "登录失败"; + } + } else { + return "不支持的source"; + } + try { + String token = saveToken(loginUser); + state += "/oauth2-app/login?oauth2LoginToken=" + URLEncoder.encode(token, "UTF-8"); + state += "&thirdType=" + "wechat_enterprise"; + log.info("OAuth2登录重定向地址: " + state); + try { + response.sendRedirect(state); + return "ok"; + } catch (IOException e) { + e.printStackTrace(); + return "重定向失败"; + } + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return "解码失败"; + } + } + } \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java index ab35a5d2..1753b413 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java @@ -1,20 +1,20 @@ package org.jeecg.modules.system.mapper; -import java.util.List; -import java.util.Map; - +import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import org.jeecg.common.system.vo.DictModel; +import org.jeecg.common.system.vo.DictModelMany; import org.jeecg.common.system.vo.DictQuery; import org.jeecg.modules.system.entity.SysDict; import org.jeecg.modules.system.model.DuplicateCheckVo; import org.jeecg.modules.system.model.TreeSelectModel; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.List; +import java.util.Map; /** *

@@ -30,11 +30,29 @@ public interface SysDictMapper extends BaseMapper { * 重复检查SQL * @return */ + @Deprecated public Long duplicateCheckCountSql(DuplicateCheckVo duplicateCheckVo); + @Deprecated public Long duplicateCheckCountSqlNoDataId(DuplicateCheckVo duplicateCheckVo); public List queryDictItemsByCode(@Param("code") String code); + /** + * 查询有效的数据字典项 + * @param code + * @return + */ + List queryEnableDictItemsByCode(@Param("code") String code); + + + /** + * 通过多个字典code获取字典数据 + * + * @param dictCodeList + * @return + */ + public List queryDictItemsByCodeList(@Param("dictCodeList") List dictCodeList); + @Deprecated public List queryTableDictItemsByCode(@Param("table") String table,@Param("text") String text,@Param("code") String code); @@ -47,9 +65,29 @@ public interface SysDictMapper extends BaseMapper { public String queryDictTextByKey(@Param("code") String code,@Param("key") String key); + /** + * 可通过多个字典code查询翻译文本 + * @param dictCodeList 多个字典code + * @param keys 数据列表 + * @return + */ + List queryManyDictByKeys(@Param("dictCodeList") List dictCodeList, @Param("keys") List keys); + @Deprecated public String queryTableDictTextByKey(@Param("table") String table,@Param("text") String text,@Param("code") String code,@Param("key") String key); + /** + * 通过查询指定table的 text code key 获取字典值,可批量查询 + * + * @param table + * @param text + * @param code + * @param keys + * @return + */ + @Deprecated + List queryTableDictTextByKeys(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keys") List keys); + @Deprecated public List queryTableDictByKeys(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keyArray") String[] keyArray); @@ -142,6 +180,7 @@ public interface SysDictMapper extends BaseMapper { * @param filterSql * @return */ + @Deprecated IPage queryTableDictWithFilter(Page page, @Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql); /** @@ -152,5 +191,6 @@ public interface SysDictMapper extends BaseMapper { * @param filterSql * @return */ + @Deprecated List queryAllTableDictItems(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql); } diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java index bdaca9b3..5ae50449 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java @@ -131,6 +131,7 @@ public interface SysUserMapper extends BaseMapper { int deleteLogicDeleted(@Param("userIds") String userIds); /** 更新空字符串为null【此写法有sql注入风险,禁止随便用】 */ + @Deprecated int updateNullByEmptyString(@Param("fieldName") String fieldName); /** diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml index 5ec72068..a942b6ba 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml @@ -8,7 +8,32 @@ where dict_id = (select id from sys_dict where dict_code = #{code}) order by s.sort_order asc - + + + + + + + + + + + + - + select count(*) as visit ,count(distinct(ip)) as ip ,DATE_FORMAT(create_time, '%Y-%m-%d') as tian @@ -34,30 +34,30 @@ group by tian,type order by tian asc - + select count(*) as visit ,count(distinct(ip)) as ip - ,to_char(create_time, 'yyyy-mm-dd') as tian + ,to_char(create_time, 'yyyy-mm-dd') as tian ,to_char(create_time, 'mm-dd') as type from sys_log where log_type = 1 and create_time >= #{dayStart} and create_time < #{dayEnd} group by to_char(create_time, 'yyyy-mm-dd'),to_char(create_time, 'mm-dd') order by to_char(create_time, 'yyyy-mm-dd') asc - + select count(*) as visit ,count(distinct(ip)) as ip - ,to_char(create_time, 'yyyy-mm-dd') as tian + ,to_char(create_time, 'yyyy-mm-dd') as tian ,to_char(create_time, 'mm-dd') as type from sys_log where log_type = 1 and create_time >= #{dayStart} and create_time < #{dayEnd} group by tian,type order by tian asc - + select count(*) as visit ,count(distinct(ip)) as ip - ,CONVERT(varchar(100), create_time, 23) as tian + ,CONVERT(varchar(100), create_time, 23) as tian ,RIGHT(CONVERT(varchar(100), create_time, 23),5) as type from sys_log where log_type = 1 and create_time >= #{dayStart} and create_time < #{dayEnd} diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysThirdAccountMapper.xml b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysThirdAccountMapper.xml index 9539eb6d..51dace64 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysThirdAccountMapper.xml +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysThirdAccountMapper.xml @@ -6,7 +6,7 @@ diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDictService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDictService.java index 2ed12b3e..0d3860d6 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDictService.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDictService.java @@ -22,6 +22,21 @@ public interface ISysDictService extends IService { public List queryDictItemsByCode(String code); + /** + * 查询有效的数据字典项 + * @param code + * @return + */ + List queryEnableDictItemsByCode(String code); + + /** + * 通过多个字典code获取字典数据 + * + * @param dictCodeList + * @return key = 字典code,value=对应的字典选项 + */ + Map> queryDictItemsByCodeList(List dictCodeList); + public Map> queryAllDictItems(); @Deprecated @@ -32,9 +47,28 @@ public interface ISysDictService extends IService { public String queryDictTextByKey(String code, String key); + /** + * 可通过多个字典code查询翻译文本 + * @param dictCodeList 多个字典code + * @param keys 数据列表 + * @return + */ + Map> queryManyDictByKeys(List dictCodeList, List keys); + @Deprecated String queryTableDictTextByKey(String table, String text, String code, String key); + /** + * 通过查询指定table的 text code key 获取字典值,可批量查询 + * + * @param table + * @param text + * @param code + * @param keys + * @return + */ + List queryTableDictTextByKeys(String table, String text, String code, List keys); + @Deprecated List queryTableDictByKeys(String table, String text, String code, String keys); @Deprecated diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java index 916c656e..80350a14 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java @@ -3,6 +3,33 @@ package org.jeecg.modules.system.service; import com.baomidou.mybatisplus.extension.service.IService; import org.jeecg.modules.system.entity.SysTenant; +import java.util.Collection; +import java.util.List; + public interface ISysTenantService extends IService { + /** + * 查询有效的租户 + * + * @param idList + * @return + */ + List queryEffectiveTenant(Collection idList); + + /** + * 返回某个租户被多少个用户引用了 + * + * @param id + * @return + */ + int countUserLinkTenant(String id); + + /** + * 根据ID删除租户,会判断是否已被引用 + * + * @param id + * @return + */ + boolean removeTenantById(String id); + } diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysThirdAccountService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysThirdAccountService.java index 5aac4825..e8040c73 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysThirdAccountService.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysThirdAccountService.java @@ -3,6 +3,7 @@ package org.jeecg.modules.system.service; import com.baomidou.mybatisplus.extension.service.IService; import org.jeecg.modules.system.entity.SysThirdAccount; import org.jeecg.modules.system.entity.SysUser; +import org.jeecg.modules.system.model.ThirdLoginModel; import java.util.List; @@ -32,4 +33,11 @@ public interface ISysThirdAccountService extends IService { */ List listThirdUserIdByUsername(String[] sysUsernameArr, String thirdType); + /** + * 创建新用户 + * + * @param tlm 第三方登录信息 + */ + SysThirdAccount saveThirdUser(ThirdLoginModel tlm); + } diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java index 2c4dfc7c..fe9335cb 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java @@ -97,6 +97,9 @@ public class SysBaseApiImpl implements ISysBaseAPI { @Autowired private ThirdAppDingtalkServiceImpl dingtalkService; + @Autowired + ISysCategoryService sysCategoryService; + @Override @Cacheable(cacheNames=CacheConstant.SYS_USERS_CACHE, key="#username") public LoginUser getUserByName(String username) { @@ -276,6 +279,12 @@ public class SysBaseApiImpl implements ISysBaseAPI { return sysDictService.queryDictItemsByCode(code); } + @Override + @Cacheable(value = CacheConstant.SYS_ENABLE_DICT_CACHE,key = "#code", unless = "#result == null ") + public List queryEnableDictItemsByCode(String code) { + return sysDictService.queryEnableDictItemsByCode(code); + } + @Override public List queryTableDictItemsByCode(String table, String text, String code) { //update-begin-author:taoyan date:20200820 for:【Online+系统】字典表加权限控制机制逻辑,想法不错 LOWCOD-799 @@ -1067,4 +1076,80 @@ public class SysBaseApiImpl implements ISysBaseAPI { return null; } + /** + * 查询分类字典翻译 + * + * @param ids 分类字典表id + * @return + */ + @Override + public List loadCategoryDictItem(String ids) { + return sysCategoryService.loadDictItem(ids, false); + } + + /** + * 根据字典code加载字典text + * + * @param dictCode 顺序:tableName,text,code + * @param keys 要查询的key + * @return + */ + @Override + public List loadDictItem(String dictCode, String keys) { + String[] params = dictCode.split(","); + return sysDictService.queryTableDictByKeys(params[0], params[1], params[2], keys, false); + } + + /** + * 根据字典code查询字典项 + * + * @param dictCode 顺序:tableName,text,code + * @param dictCode 要查询的key + * @return + */ + @Override + public List getDictItems(String dictCode) { + List ls = sysDictService.getDictItems(dictCode); + if (ls == null) { + ls = new ArrayList<>(); + } + return ls; + } + + /** + * 根据多个字典code查询多个字典项 + * + * @param dictCodeList + * @return key = dictCode ; value=对应的字典项 + */ + @Override + public Map> getManyDictItems(List dictCodeList) { + return sysDictService.queryDictItemsByCodeList(dictCodeList); + } + + /** + * 【下拉搜索】 + * 大数据量的字典表 走异步加载,即前端输入内容过滤数据 + * + * @param dictCode 字典code格式:table,text,code + * @param keyword 过滤关键字 + * @return + */ + @Override + public List loadDictItemByKeyword(String dictCode, String keyword, Integer pageSize) { + return sysDictService.loadDict(dictCode, keyword, pageSize); + } + + @Override + public Map> translateManyDict(String dictCodes, String keys) { + List dictCodeList = Arrays.asList(dictCodes.split(",")); + List values = Arrays.asList(keys.split(",")); + return sysDictService.queryManyDictByKeys(dictCodeList, values); + } + + @Override + public List translateDictFromTableByKeys(String table, String text, String code, String keys) { + return sysDictService.queryTableDictTextByKeys(table, text, code, Arrays.asList(keys.split(","))); + } + } \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java index fdea13f4..3621d964 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java @@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j; import org.jeecg.common.constant.CacheConstant; import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.system.vo.DictModel; +import org.jeecg.common.system.vo.DictModelMany; import org.jeecg.common.system.vo.DictQuery; import org.jeecg.common.util.SqlInjectionUtil; import org.jeecg.common.util.oConvertUtils; @@ -57,6 +58,25 @@ public class SysDictServiceImpl extends ServiceImpl impl return sysDictMapper.queryDictItemsByCode(code); } + @Override + @Cacheable(value = CacheConstant.SYS_ENABLE_DICT_CACHE,key = "#code", unless = "#result == null ") + public List queryEnableDictItemsByCode(String code) { + log.debug("无缓存dictCache的时候调用这里!"); + return sysDictMapper.queryEnableDictItemsByCode(code); + } + + @Override + public Map> queryDictItemsByCodeList(List dictCodeList) { + List list = sysDictMapper.queryDictItemsByCodeList(dictCodeList); + Map> dictMap = new HashMap<>(); + for (DictModelMany dict : list) { + List dictItemList = dictMap.computeIfAbsent(dict.getDictCode(), i -> new ArrayList<>()); + dict.setDictCode(null); + dictItemList.add(new DictModel(dict.getValue(), dict.getText())); + } + return dictMap; + } + @Override public Map> queryAllDictItems() { Map> res = new HashMap>(); @@ -93,6 +113,17 @@ public class SysDictServiceImpl extends ServiceImpl impl return sysDictMapper.queryDictTextByKey(code, key); } + @Override + public Map> queryManyDictByKeys(List dictCodeList, List keys) { + List list = sysDictMapper.queryManyDictByKeys(dictCodeList, keys); + Map> dictMap = new HashMap<>(); + for (DictModelMany dict : list) { + List dictItemList = dictMap.computeIfAbsent(dict.getDictCode(), i -> new ArrayList<>()); + dictItemList.add(new DictModel(dict.getValue(), dict.getText())); + } + return dictMap; + } + /** * 通过查询指定table的 text code 获取字典 * dictTableCache采用redis缓存有效期10分钟 @@ -130,6 +161,11 @@ public class SysDictServiceImpl extends ServiceImpl impl return sysDictMapper.queryTableDictTextByKey(table,text,code,key); } + @Override + public List queryTableDictTextByKeys(String table, String text, String code, List keys) { + return sysDictMapper.queryTableDictTextByKeys(table, text, code, keys); + } + @Override public List queryTableDictByKeys(String table, String text, String code, String keys) { return this.queryTableDictByKeys(table, text, code, keys, true); diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysLogServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysLogServiceImpl.java index ddc5bc0b..0f804e2c 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysLogServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysLogServiceImpl.java @@ -7,6 +7,7 @@ import java.util.Map; import javax.annotation.Resource; +import com.baomidou.mybatisplus.annotation.DbType; import org.jeecg.common.system.api.ISysBaseAPI; import org.jeecg.common.util.CommonUtils; import org.jeecg.modules.system.entity.SysLog; @@ -60,7 +61,7 @@ public class SysLogServiceImpl extends ServiceImpl impleme @Override public List> findVisitCount(Date dayStart, Date dayEnd) { - String dbType = CommonUtils.getDatabaseType(); - return sysLogMapper.findVisitCount(dayStart, dayEnd,dbType); + DbType dbType = CommonUtils.getDatabaseTypeEnum(); + return sysLogMapper.findVisitCount(dayStart, dayEnd,dbType.getDb()); } } diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java index a260d927..f545802b 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java @@ -1,15 +1,56 @@ package org.jeecg.modules.system.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.constant.CommonConstant; +import org.jeecg.common.exception.JeecgBootException; import org.jeecg.modules.system.entity.SysTenant; +import org.jeecg.modules.system.entity.SysUser; import org.jeecg.modules.system.mapper.SysTenantMapper; import org.jeecg.modules.system.service.ISysTenantService; +import org.jeecg.modules.system.service.ISysUserService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -@Service +import java.util.Collection; +import java.util.List; + +@Service("sysTenantServiceImpl") @Slf4j public class SysTenantServiceImpl extends ServiceImpl implements ISysTenantService { - + + @Autowired + ISysUserService userService; + + @Override + public List queryEffectiveTenant(Collection idList) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(SysTenant::getId, idList); + queryWrapper.eq(SysTenant::getStatus, CommonConstant.STATUS_1); + //此处查询忽略时间条件 + return super.list(queryWrapper); + } + + @Override + public int countUserLinkTenant(String id) { + LambdaQueryWrapper userQueryWrapper = new LambdaQueryWrapper<>(); + userQueryWrapper.eq(SysUser::getRelTenantIds, id); + userQueryWrapper.or().like(SysUser::getRelTenantIds, "%," + id); + userQueryWrapper.or().like(SysUser::getRelTenantIds, id + ",%"); + userQueryWrapper.or().like(SysUser::getRelTenantIds, "%," + id + ",%"); + // 查找出已被关联的用户数量 + return userService.count(userQueryWrapper); + } + + @Override + public boolean removeTenantById(String id) { + // 查找出已被关联的用户数量 + int userCount = this.countUserLinkTenant(id); + if (userCount > 0) { + throw new JeecgBootException("该租户已被引用,无法删除!"); + } + return super.removeById(id); + } } diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java index 3030c7a2..fde06dca 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java @@ -15,6 +15,7 @@ import org.jeecg.modules.system.mapper.SysRoleMapper; import org.jeecg.modules.system.mapper.SysThirdAccountMapper; import org.jeecg.modules.system.mapper.SysUserMapper; import org.jeecg.modules.system.mapper.SysUserRoleMapper; +import org.jeecg.modules.system.model.ThirdLoginModel; import org.jeecg.modules.system.service.ISysThirdAccountService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -133,4 +134,18 @@ public class SysThirdAccountServiceImpl extends ServiceImpl ddUserList = this.getDtAllUserByDepartment(allDepartment, accessToken); for (User dtUserInfo : ddUserList) { - SysThirdAccount sysThirdAccount = sysThirdAccountService.getOneByThirdUserId(dtUserInfo.getUserid(), ThirdAppConfig.DINGTALK.toLowerCase()); + SysThirdAccount sysThirdAccount = sysThirdAccountService.getOneByThirdUserId(dtUserInfo.getUserid(), THIRD_TYPE); List collect = sysUsersList.stream().filter(user -> (dtUserInfo.getMobile().equals(user.getPhone()) || dtUserInfo.getUserid().equals(user.getUsername())) ).collect(Collectors.toList()); if (collect != null && collect.size() > 0) { @@ -414,7 +422,7 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { sysThirdAccount.setSysUserId(sysUserId); sysThirdAccount.setStatus(1); sysThirdAccount.setDelFlag(0); - sysThirdAccount.setThirdType(ThirdAppConfig.DINGTALK.toLowerCase()); + sysThirdAccount.setThirdType(THIRD_TYPE); } sysThirdAccount.setThirdUserId(dtUserId); sysThirdAccountService.saveOrUpdate(sysThirdAccount); @@ -517,6 +525,9 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), password, salt); sysUser.setSalt(salt); sysUser.setPassword(passwordEncode); + // update-begin--Author:liusq Date:20210713 for:钉钉同步到本地的人员没有状态,导致同步之后无法登录 #I3ZC2L + sysUser.setStatus(1); + // update-end--Author:liusq Date:20210713 for:钉钉同步到本地的人员没有状态,导致同步之后无法登录 #I3ZC2L return this.dtUserToSysUser(dtUser, sysUser); } @@ -629,7 +640,7 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { return count; } LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysThirdAccount::getThirdType, ThirdAppConfig.DINGTALK.toLowerCase()); + queryWrapper.eq(SysThirdAccount::getThirdType, THIRD_TYPE); queryWrapper.in(SysThirdAccount::getSysUserId, userIdList); // 根据userId,获取第三方用户的id List thirdAccountList = sysThirdAccountService.list(queryWrapper); @@ -686,7 +697,7 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { } else { String[] toUsers = message.getToUser().split(","); // 通过第三方账号表查询出第三方userId - List thirdAccountList = sysThirdAccountService.listThirdUserIdByUsername(toUsers, ThirdAppConfig.DINGTALK.toLowerCase()); + List thirdAccountList = sysThirdAccountService.listThirdUserIdByUsername(toUsers, THIRD_TYPE); List dtUserIds = thirdAccountList.stream().map(SysThirdAccount::getThirdUserId).collect(Collectors.toList()); textMessage.setUserid_list(dtUserIds); } @@ -757,7 +768,7 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { if(userIds!=null){ String[] usernameList = sysUserService.userIdToUsername(Arrays.asList(userIds)).toArray(new String[]{}); // 通过第三方账号表查询出第三方userId - List thirdAccountList = sysThirdAccountService.listThirdUserIdByUsername(usernameList, ThirdAppConfig.DINGTALK.toLowerCase()); + List thirdAccountList = sysThirdAccountService.listThirdUserIdByUsername(usernameList, THIRD_TYPE); List dtUserIds = thirdAccountList.stream().map(SysThirdAccount::getThirdUserId).collect(Collectors.toList()); actionCardMessage.setUserid_list(dtUserIds); return JdtMessageAPI.sendActionCardMessage(actionCardMessage, accessToken); @@ -766,4 +777,91 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { return null; } + /** + * OAuth2登录,成功返回登录的SysUser,失败返回null + */ + public SysUser oauth2Login(String authCode) { + ThirdAppTypeItemVo dtConfig = thirdAppConfig.getDingtalk(); + // 1. 根据免登授权码获取用户 AccessToken + String userAccessToken = JdtOauth2API.getUserAccessToken(dtConfig.getClientId(), dtConfig.getClientSecret(), authCode); + if (userAccessToken == null) { + log.error("oauth2Login userAccessToken is null"); + return null; + } + // 2. 根据用户 AccessToken 获取当前用户的基本信息(不包括userId) + ContactUser contactUser = JdtOauth2API.getContactUsers("me", userAccessToken); + if (contactUser == null) { + log.error("oauth2Login contactUser is null"); + return null; + } + String unionId = contactUser.getUnionId(); + // 3. 根据获取到的 unionId 换取用户 userId + String accessToken = this.getAccessToken(); + if (accessToken == null) { + log.error("oauth2Login accessToken is null"); + return null; + } + Response getUserIdRes = JdtUserAPI.getUseridByUnionid(unionId, accessToken); + if (!getUserIdRes.isSuccess()) { + log.error("oauth2Login getUseridByUnionid failed: " + JSON.toJSONString(getUserIdRes)); + return null; + } + String appUserId = getUserIdRes.getResult(); + log.info("appUserId: " + appUserId); + if (appUserId != null) { + // 判断第三方用户表有没有这个人 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysThirdAccount::getThirdUserUuid, appUserId); + queryWrapper.or().eq(SysThirdAccount::getThirdUserId, appUserId); + queryWrapper.eq(SysThirdAccount::getThirdType, THIRD_TYPE); + SysThirdAccount thirdAccount = sysThirdAccountService.getOne(queryWrapper); + if (thirdAccount != null) { + return this.getSysUserByThird(thirdAccount, null, appUserId, accessToken); + } else { + // 直接创建新账号 + User appUser = JdtUserAPI.getUserById(appUserId, accessToken).getResult(); + ThirdLoginModel tlm = new ThirdLoginModel(THIRD_TYPE, appUser.getUserid(), appUser.getName(), appUser.getAvatar()); + thirdAccount = sysThirdAccountService.saveThirdUser(tlm); + return this.getSysUserByThird(thirdAccount, appUser, null, null); + } + } + return null; + } + + /** + * 根据第三方账号获取本地账号,如果不存在就创建 + * + * @param thirdAccount + * @param appUser + * @param appUserId + * @param accessToken + * @return + */ + private SysUser getSysUserByThird(SysThirdAccount thirdAccount, User appUser, String appUserId, String accessToken) { + String sysUserId = thirdAccount.getSysUserId(); + if (oConvertUtils.isNotEmpty(sysUserId)) { + return sysUserService.getById(sysUserId); + } else { + // 如果没有 sysUserId ,说明没有绑定账号,获取到手机号之后进行绑定 + if (appUser == null) { + appUser = JdtUserAPI.getUserById(appUserId, accessToken).getResult(); + } + // 判断系统里是否有这个手机号的用户 + SysUser sysUser = sysUserService.getUserByPhone(appUser.getMobile()); + if (sysUser != null) { + thirdAccount.setAvatar(appUser.getAvatar()); + thirdAccount.setRealname(appUser.getName()); + thirdAccount.setThirdUserId(appUser.getUserid()); + thirdAccount.setThirdUserUuid(appUser.getUserid()); + thirdAccount.setSysUserId(sysUser.getId()); + sysThirdAccountService.updateById(thirdAccount); + return sysUser; + } else { + // 没有就走创建逻辑 + return sysThirdAccountService.createUser(appUser.getMobile(), appUser.getUserid()); + } + + } + } + } \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java index 086cf63b..4796d323 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java @@ -27,6 +27,7 @@ import org.jeecg.config.thirdapp.ThirdAppConfig; import org.jeecg.modules.system.entity.*; import org.jeecg.modules.system.mapper.SysAnnouncementSendMapper; import org.jeecg.modules.system.model.SysDepartTreeModel; +import org.jeecg.modules.system.model.ThirdLoginModel; import org.jeecg.modules.system.service.*; import org.jeecg.modules.system.vo.thirdapp.JwDepartmentTreeVo; import org.jeecg.modules.system.vo.thirdapp.SyncInfoVo; @@ -62,6 +63,9 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { @Autowired private SysAnnouncementSendMapper sysAnnouncementSendMapper; + // 第三方APP类型,当前固定为 wechat_enterprise + public final String THIRD_TYPE = ThirdAppConfig.WECHAT_ENTERPRISE.toLowerCase(); + @Override public String getAccessToken() { String CORP_ID = thirdAppConfig.getWechatEnterprise().getClientId(); @@ -302,7 +306,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { * 2. 本地表里没有,就先用手机号判断,不通过再用username判断。 */ User qwUser; - SysThirdAccount sysThirdAccount = sysThirdAccountService.getOneBySysUserId(sysUser.getId(), ThirdAppConfig.WECHAT_ENTERPRISE.toLowerCase()); + SysThirdAccount sysThirdAccount = sysThirdAccountService.getOneBySysUserId(sysUser.getId(), THIRD_TYPE); for (User qwUserTemp : qwUsers) { if (sysThirdAccount == null || oConvertUtils.isEmpty(sysThirdAccount.getThirdUserId()) || !sysThirdAccount.getThirdUserId().equals(qwUserTemp.getUserid())) { // sys_third_account 表匹配失败,尝试用手机号匹配 @@ -360,7 +364,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { * 1. 查询 sys_third_account(第三方账号表)是否有数据,如果有代表已同步 * 2. 本地表里没有,就先用手机号判断,不通过再用username判断。 */ - SysThirdAccount sysThirdAccount = sysThirdAccountService.getOneByThirdUserId(qwUser.getUserid(), ThirdAppConfig.WECHAT_ENTERPRISE.toLowerCase()); + SysThirdAccount sysThirdAccount = sysThirdAccountService.getOneByThirdUserId(qwUser.getUserid(), THIRD_TYPE); List collect = sysUsersList.stream().filter(user -> (qwUser.getMobile().equals(user.getPhone()) || qwUser.getUserid().equals(user.getUsername())) ).collect(Collectors.toList()); @@ -407,7 +411,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { sysThirdAccount.setSysUserId(sysUserId); sysThirdAccount.setStatus(1); sysThirdAccount.setDelFlag(0); - sysThirdAccount.setThirdType(ThirdAppConfig.WECHAT_ENTERPRISE.toLowerCase()); + sysThirdAccount.setThirdType(THIRD_TYPE); } sysThirdAccount.setThirdUserId(qwUserId); sysThirdAccountService.saveOrUpdate(sysThirdAccount); @@ -581,6 +585,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { private SysUser qwUserToSysUser(User user) { SysUser sysUser = new SysUser(); sysUser.setDelFlag(0); + sysUser.setStatus(1); // 通过 username 来关联 sysUser.setUsername(user.getUserid()); // 密码默认为 “123456”,随机加盐 @@ -680,7 +685,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { return count; } LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysThirdAccount::getThirdType, ThirdAppConfig.WECHAT_ENTERPRISE.toLowerCase()); + queryWrapper.eq(SysThirdAccount::getThirdType, THIRD_TYPE); queryWrapper.in(SysThirdAccount::getSysUserId, userIdList); // 根据userId,获取第三方用户的id List thirdAccountList = sysThirdAccountService.list(queryWrapper); @@ -781,11 +786,93 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { } else { String[] toUsers = origin.split(","); // 通过第三方账号表查询出第三方userId - List thirdAccountList = sysThirdAccountService.listThirdUserIdByUsername(toUsers, ThirdAppConfig.WECHAT_ENTERPRISE.toLowerCase()); + List thirdAccountList = sysThirdAccountService.listThirdUserIdByUsername(toUsers, THIRD_TYPE); List toUserList = thirdAccountList.stream().map(SysThirdAccount::getThirdUserId).collect(Collectors.toList()); // 多个接收者用‘|’分隔 return String.join("|", toUserList); } } + /** + * 根据第三方登录获取到的code来获取第三方app的用户ID + * + * @param code + * @return + */ + public String getUserIdByThirdCode(String code, String accessToken) { + JSONObject response = JwUserAPI.getUserInfoByCode(code, accessToken); + if (response != null) { + log.info("response: " + response.toJSONString()); + if (response.getIntValue("errcode") == 0) { + return response.getString("UserId"); + } + } + return null; + } + + /** + * OAuth2登录,成功返回登录的SysUser,失败返回null + */ + public SysUser oauth2Login(String code) { + String accessToken = this.getAppAccessToken(); + if (accessToken == null) { + return null; + } + String appUserId = this.getUserIdByThirdCode(code, accessToken); + if (appUserId != null) { + // 判断第三方用户表有没有这个人 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysThirdAccount::getThirdUserUuid, appUserId); + queryWrapper.or().eq(SysThirdAccount::getThirdUserId, appUserId); + queryWrapper.eq(SysThirdAccount::getThirdType, THIRD_TYPE); + SysThirdAccount thirdAccount = sysThirdAccountService.getOne(queryWrapper); + if (thirdAccount != null) { + return this.getSysUserByThird(thirdAccount, null, appUserId, accessToken); + } else { + // 直接创建新账号 + User appUser = JwUserAPI.getUserByUserid(appUserId, accessToken); + ThirdLoginModel tlm = new ThirdLoginModel(THIRD_TYPE, appUser.getUserid(), appUser.getName(), appUser.getAvatar()); + thirdAccount = sysThirdAccountService.saveThirdUser(tlm); + return this.getSysUserByThird(thirdAccount, appUser, null, null); + } + } + return null; + } + + /** + * 根据第三方账号获取本地账号,如果不存在就创建 + * + * @param thirdAccount + * @param appUser + * @param appUserId + * @param accessToken + * @return + */ + private SysUser getSysUserByThird(SysThirdAccount thirdAccount, User appUser, String appUserId, String accessToken) { + String sysUserId = thirdAccount.getSysUserId(); + if (oConvertUtils.isNotEmpty(sysUserId)) { + return sysUserService.getById(sysUserId); + } else { + // 如果没有 sysUserId ,说明没有绑定账号,获取到手机号之后进行绑定 + if (appUser == null) { + appUser = JwUserAPI.getUserByUserid(appUserId, accessToken); + } + // 判断系统里是否有这个手机号的用户 + SysUser sysUser = sysUserService.getUserByPhone(appUser.getMobile()); + if (sysUser != null) { + thirdAccount.setAvatar(appUser.getAvatar()); + thirdAccount.setRealname(appUser.getName()); + thirdAccount.setThirdUserId(appUser.getUserid()); + thirdAccount.setThirdUserUuid(appUser.getUserid()); + thirdAccount.setSysUserId(sysUser.getId()); + sysThirdAccountService.updateById(thirdAccount); + return sysUser; + } else { + // 没有就走创建逻辑 + return sysThirdAccountService.createUser(appUser.getMobile(), appUser.getUserid()); + } + + } + } + } diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/XSSUtils.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/XSSUtils.java new file mode 100644 index 00000000..e38b1c19 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/XSSUtils.java @@ -0,0 +1,44 @@ +package org.jeecg.modules.system.util; + +import org.springframework.web.util.HtmlUtils; + +import java.util.regex.Pattern; + +/** + * @Description: 工具类XSSUtils,现在的做法是替换成空字符,CSDN的是进行转义,比如文字开头的"<"转成< + * @author: lsq + * @date: 2021年07月26日 19:13 + */ +public class XSSUtils { + public static String striptXSS(String value) { + if (value != null) { + value = value.replaceAll(" ", ""); + Pattern scriptPattern = Pattern.compile("", Pattern.CASE_INSENSITIVE); + value = scriptPattern.matcher(value).replaceAll(""); + scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); + value = scriptPattern.matcher(value).replaceAll(""); + scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); + value = scriptPattern.matcher(value).replaceAll(""); + scriptPattern = Pattern.compile("", Pattern.CASE_INSENSITIVE); + value = scriptPattern.matcher(value).replaceAll(""); + scriptPattern = Pattern.compile("", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); + value = scriptPattern.matcher(value).replaceAll(""); + scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); + value = scriptPattern.matcher(value).replaceAll(""); + scriptPattern = Pattern.compile("e­xpression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); + value = scriptPattern.matcher(value).replaceAll(""); + scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE); + value = scriptPattern.matcher(value).replaceAll(""); + scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE); + value = scriptPattern.matcher(value).replaceAll(""); + scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); + value = scriptPattern.matcher(value).replaceAll(""); + } + return HtmlUtils.htmlEscape(value); + } + + public static void main(String[] args) { + String s = striptXSS("javascript:eval()\\\\."); + System.err.println("s======>" + s); + } +} diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/vo/SysUserOnlineVO.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/vo/SysUserOnlineVO.java new file mode 100644 index 00000000..cb5654b9 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/vo/SysUserOnlineVO.java @@ -0,0 +1,62 @@ +package org.jeecg.modules.system.vo; + +import java.util.Date; + +import org.jeecg.common.aspect.annotation.Dict; +import org.springframework.format.annotation.DateTimeFormat; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import lombok.Data; + +/** + * + * @Author: chenli + * @Date: 2020-06-07 + * @Version: V1.0 + */ +@Data +public class SysUserOnlineVO { + /** + * 会话id + */ + private String id; + + /** + * 会话编号 + */ + private String token; + + /** + * 用户名 + */ + private String username; + + /** + * 用户名 + */ + private String realname; + + /** + * 头像 + */ + private String avatar; + + /** + * 生日 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date birthday; + + /** + * 性别(1:男 2:女) + */ + @Dict(dicCode = "sex") + private Integer sex; + + /** + * 手机号 + */ + private String phone; +} diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-dev.yml b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-dev.yml index e3079570..193b8d1b 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-dev.yml +++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-dev.yml @@ -39,7 +39,7 @@ spring: quartz: job-store-type: jdbc initialize-schema: embedded - #设置自动启动,默认为 true + #定时任务启动开关,true-开 false-关 auto-startup: true #启动时更新己存在的Job overwrite-existing-jobs: true @@ -118,7 +118,7 @@ spring: timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 - validationQuery: SELECT 1 FROM DUAL + validationQuery: SELECT 1 testWhileIdle: true testOnBorrow: false testOnReturn: false @@ -131,7 +131,7 @@ spring: connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000 datasource: master: - url: jdbc:mysql://127.0.0.1:3306/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai + url: jdbc:mysql://127.0.0.1:3306/jeecg-boot-os-re?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver @@ -176,8 +176,10 @@ minidao : #DB类型(mysql | postgresql | oracle | sqlserver| other) db-type: mysql jeecg : + # 签名密钥串(前后端要一致,正式发布请自行修改) + signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a # 本地:local\Minio:minio\阿里云:alioss - uploadType: local + uploadType: minio path : #文件上传根目录 设置 upload: /opt/upFiles @@ -190,7 +192,7 @@ jeecg : accessKey: ?? secretKey: ?? endpoint: oss-cn-beijing.aliyuncs.com - bucketName: ?? + bucketName: jeecgdev # ElasticSearch 6设置 elasticsearch: cluster-name: jeecg-ES @@ -238,12 +240,12 @@ jeecg : port: 30007 logPath: logs/jeecg/job/jobhandler/ logRetentionDays: 30 - #自定义路由配置 yml nacos database route: config: data-id: jeecg-gateway-router group: DEFAULT_GROUP - data-type: yml + #自定义路由配置 yml nacos database + data-type: database #分布式锁配置 redisson: address: 127.0.0.1:6379 @@ -259,9 +261,12 @@ logging: org.jeecg.modules.system.mapper : info #swagger knife4j: + #开启增强配置 + enable: true + #开启生产环境屏蔽 production: false basic: - enable: true + enable: false username: jeecg password: jeecg1314 #第三方登录 diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml index ed2b190c..3105f9c5 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml +++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml @@ -39,7 +39,7 @@ spring: quartz: job-store-type: jdbc initialize-schema: embedded - #设置自动启动,默认为 true + #定时任务启动开关,true-开 false-关 auto-startup: true #启动时更新己存在的Job overwrite-existing-jobs: true @@ -176,6 +176,8 @@ minidao : #DB类型(mysql | postgresql | oracle | sqlserver| other) db-type: mysql jeecg : + # 签名密钥串(前后端要一致,正式发布请自行修改) + signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a # 本地:local\Minio:minio\阿里云:alioss uploadType: alioss path : @@ -190,12 +192,12 @@ jeecg : accessKey: ?? secretKey: ?? endpoint: oss-cn-beijing.aliyuncs.com - bucketName: ?? + bucketName: jeecgdev staticDomain: https://static.jeecg.com # ElasticSearch 设置 elasticsearch: cluster-name: jeecg-ES - cluster-nodes: ?? + cluster-nodes: 81.70.47.128:9200 check-enabled: true # 表单设计器配置 desform: @@ -213,7 +215,7 @@ jeecg : minio_url: http://minio.jeecg.com minio_name: ?? minio_pass: ?? - bucketName: ?? + bucketName: otatest #大屏报表参数设置 jmreport: mode: prod @@ -239,12 +241,12 @@ jeecg : port: 30007 logPath: logs/jeecg/job/jobhandler/ logRetentionDays: 30 - #自定义路由配置 yml nacos database route: config: data-id: jeecg-gateway-router group: DEFAULT_GROUP - data-type: yml + #自定义路由配置 yml nacos database + data-type: database #分布式锁配置 redisson: address: 127.0.0.1:6379 @@ -260,7 +262,10 @@ logging: org.jeecg.modules.system.mapper : info #swagger knife4j: - production: false + #开启增强配置 + enable: true + #开启生产环境屏蔽 + production: true basic: enable: true username: jeecg diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-test.yml b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-test.yml index 8759ed7e..5001010f 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-test.yml +++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-test.yml @@ -39,7 +39,7 @@ spring: quartz: job-store-type: jdbc initialize-schema: embedded - #设置自动启动,默认为 true + #定时任务启动开关,true-开 false-关 auto-startup: true #启动时更新己存在的Job overwrite-existing-jobs: true @@ -176,6 +176,8 @@ minidao : #DB类型(mysql | postgresql | oracle | sqlserver| other) db-type: mysql jeecg : + # 签名密钥串(前后端要一致,正式发布请自行修改) + signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a # 本地:local\Minio:minio\阿里云:alioss uploadType: local path : @@ -190,12 +192,12 @@ jeecg : accessKey: ?? secretKey: ?? endpoint: oss-cn-beijing.aliyuncs.com - bucketName: ?? + bucketName: jeecgdev staticDomain: https://static.jeecg.com # ElasticSearch 设置 elasticsearch: cluster-name: jeecg-ES - cluster-nodes: ?? + cluster-nodes: 81.70.47.128:9200 check-enabled: false # 表单设计器配置 desform: @@ -239,12 +241,12 @@ jeecg : port: 30007 logPath: logs/jeecg/job/jobhandler/ logRetentionDays: 30 - #自定义路由配置 yml nacos database route: config: data-id: jeecg-gateway-router group: DEFAULT_GROUP - data-type: yml + #自定义路由配置 yml nacos database + data-type: database #分布式锁配置 redisson: address: 127.0.0.1:6379 @@ -260,6 +262,9 @@ cas: prefixUrl: http://cas.example.org:8443/cas #swagger knife4j: + #开启增强配置 + enable: true + #开启生产环境屏蔽 production: false basic: enable: true diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt b/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt index a67118ea..3d1c0efb 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt +++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt @@ -9,6 +9,6 @@ ${AnsiColor.BRIGHT_BLUE} ${AnsiColor.BRIGHT_GREEN} -Jeecg Boot Version: 2.4.5 +Jeecg Boot Version: 2.4.6 Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version} ${AnsiColor.BLACK} diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/entity/${entityName}.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/entity/${entityName}.javai index c637759e..9bd5dfd1 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/entity/${entityName}.javai +++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/entity/${entityName}.javai @@ -45,7 +45,7 @@ public class ${entityName} implements Serializable { /**${po.filedComment}*/ <#if po.fieldName == primaryKeyField> - @TableId(type = IdType.ID_WORKER_STR) + @TableId(type = IdType.ASSIGN_ID) <#else> <#if po.fieldDbType =='Date'> <#if po.classType=='date'> diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/entity/[1-n]Entity.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/entity/[1-n]Entity.javai index 25e80fb6..c93099ca 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/entity/[1-n]Entity.javai +++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/entity/[1-n]Entity.javai @@ -46,7 +46,7 @@ public class ${subTab.entityName} implements Serializable { /**${po.filedComment}*/ <#if po.fieldName == primaryKeyField> - @TableId(type = IdType.ID_WORKER_STR) + @TableId(type = IdType.ASSIGN_ID) <#else> <#if po.fieldDbType =='Date'> <#if po.classType=='date'> diff --git a/jeecg-boot/jeecg-boot-module-system/src/test/java/org/jeecg/SecurityToolsTest.java b/jeecg-boot/jeecg-boot-module-system/src/test/java/org/jeecg/SecurityToolsTest.java index 172df054..e1ce9f68 100644 --- a/jeecg-boot/jeecg-boot-module-system/src/test/java/org/jeecg/SecurityToolsTest.java +++ b/jeecg-boot/jeecg-boot-module-system/src/test/java/org/jeecg/SecurityToolsTest.java @@ -1,6 +1,6 @@ package org.jeecg; -import cn.hutool.json.JSONObject; +import com.alibaba.fastjson.JSONObject; import org.jeecg.common.util.security.SecurityTools; import org.jeecg.common.util.security.entity.*; import org.junit.Test; @@ -30,7 +30,7 @@ public class SecurityToolsTest { // signData为签名数据 // data为aes加密数据 // asekey为ras加密过的aeskey - System.out.println(new JSONObject(sign).toStringPretty()); + System.out.println(JSONObject.toJSON(sign)); // 验签解密部分 SecurityReq req = new SecurityReq(); @@ -44,6 +44,6 @@ public class SecurityToolsTest { SecurityResp securityResp = SecurityTools.valid(req); //解密报文data为解密报文 //sucess 为验签成功失败标志 true代码验签成功,false代表失败 - System.out.println(new JSONObject(securityResp).toStringPretty()); + System.out.println(JSONObject.toJSON(securityResp)); } } diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/pom.xml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/pom.xml index 875a83de..e00262c9 100644 --- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/pom.xml +++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/pom.xml @@ -5,7 +5,7 @@ jeecg-boot-starter org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 jeecg-boot-starter-cloud diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/java/org/jeecg/config/FeignConfig.java b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/java/org/jeecg/config/FeignConfig.java index 3cc2b474..3a51a210 100644 --- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/java/org/jeecg/config/FeignConfig.java +++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/java/org/jeecg/config/FeignConfig.java @@ -55,13 +55,13 @@ public class FeignConfig { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (null != attributes) { HttpServletRequest request = attributes.getRequest(); - log.info("Feign request: {}", request.getRequestURI()); + log.debug("Feign request: {}", request.getRequestURI()); // 将token信息放入header中 String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN); if(token==null || "".equals(token)){ token = request.getParameter("token"); } - log.info("Feign request token: {}", token); + log.debug("Feign request token: {}", token); requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token); //根据URL地址过滤请求 【字典表参数签名验证】 diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-job/pom.xml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-job/pom.xml index 8ba9dec2..73354eec 100644 --- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-job/pom.xml +++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-job/pom.xml @@ -5,7 +5,7 @@ jeecg-boot-starter org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 jeecg-boot-starter-job diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/pom.xml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/pom.xml index b7d9602a..20dfc59f 100644 --- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/pom.xml +++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/pom.xml @@ -5,7 +5,7 @@ jeecg-boot-starter org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 jeecg-boot-starter-lock diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-rabbitmq/pom.xml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-rabbitmq/pom.xml index a6e9363f..2f65905b 100644 --- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-rabbitmq/pom.xml +++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-rabbitmq/pom.xml @@ -5,7 +5,7 @@ jeecg-boot-starter org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 jeecg-boot-starter-rabbitmq diff --git a/jeecg-boot/jeecg-boot-starter/pom.xml b/jeecg-boot/jeecg-boot-starter/pom.xml index 9914c091..a3a3ced0 100644 --- a/jeecg-boot/jeecg-boot-starter/pom.xml +++ b/jeecg-boot/jeecg-boot-starter/pom.xml @@ -4,7 +4,7 @@ org.jeecgframework.boot jeecg-boot-parent - 2.4.5 + 2.4.6 4.0.0 jeecg-boot-starter diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/Dockerfile b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/Dockerfile index 4202f89e..d1366ab6 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/Dockerfile +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/Dockerfile @@ -10,6 +10,6 @@ WORKDIR /jeecg-cloud-gateway EXPOSE 9999 -ADD ./target/jeecg-cloud-gateway-2.4.5.jar ./ +ADD ./target/jeecg-cloud-gateway-2.4.6.jar ./ -CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-gateway-2.4.5.jar \ No newline at end of file +CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-gateway-2.4.6.jar \ No newline at end of file diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/README.md b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/README.md new file mode 100644 index 00000000..b10d2a7e --- /dev/null +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/README.md @@ -0,0 +1,7 @@ +# 服务化改造手册 + +~~~ +注意 :启动服务跨域问题处理 +1、需要将common 模块的 WebMvcConfiguration corsFilter 注掉 后面做成注解切换 +2、org.jeecg.config.shiro.filters.JwtFilter类的 65行,跨域代码注释掉 +~~~ \ No newline at end of file diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/pom.xml index f6bd19bb..6a3ae8df 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/pom.xml +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/pom.xml @@ -5,7 +5,7 @@ jeecg-cloud-module org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 @@ -27,6 +27,19 @@ org.springframework.cloud spring-cloud-starter-gateway + + + com.alibaba.cloud + spring-cloud-alibaba-sentinel-gateway + + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + + + com.alibaba.csp + sentinel-web-servlet + org.springframework.boot diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/filter/SentinelFilterContextConfig.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/filter/SentinelFilterContextConfig.java new file mode 100644 index 00000000..ced27e37 --- /dev/null +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/filter/SentinelFilterContextConfig.java @@ -0,0 +1,24 @@ +package org.jeecg.filter; + +import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Administrator + */ +@Configuration +public class SentinelFilterContextConfig { + @Bean + public FilterRegistrationBean sentinelFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new CommonFilter()); + registration.addUrlPatterns("/*"); + // 入口资源关闭聚合 + registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false"); + registration.setName("sentinelFilter"); + registration.setOrder(1); + return registration; + } +} \ No newline at end of file diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/handler/MySwaggerResourceProvider.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/handler/MySwaggerResourceProvider.java index d1d84a72..d88d86c6 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/handler/MySwaggerResourceProvider.java +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/handler/MySwaggerResourceProvider.java @@ -1,5 +1,6 @@ package org.jeecg.handler; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.gateway.route.RouteLocator; @@ -13,6 +14,7 @@ import java.util.*; * 聚合各个服务的swagger接口 */ @Component +@Slf4j public class MySwaggerResourceProvider implements SwaggerResourcesProvider { /** * swagger2默认的url后缀 @@ -51,6 +53,7 @@ public class MySwaggerResourceProvider implements SwaggerResourcesProvider { String url = "/" + instance.toLowerCase() + SWAGGER2URL; if (!dealed.contains(url)) { dealed.add(url); + log.info(" Gateway add SwaggerResource: {}",url); SwaggerResource swaggerResource = new SwaggerResource(); swaggerResource.setUrl(url); swaggerResource.setSwaggerVersion("2.0"); diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/handler/SentinelBlockRequestHandler.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/handler/SentinelBlockRequestHandler.java new file mode 100644 index 00000000..fab2d2ac --- /dev/null +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/java/org/jeecg/handler/SentinelBlockRequestHandler.java @@ -0,0 +1,38 @@ +package org.jeecg.handler; +import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler; +import com.alibaba.csp.sentinel.transport.config.TransportConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import javax.annotation.PostConstruct; + +/** + * 自定义限流返回信息 + * @author Administrator + */ +@Slf4j +@Component +public class SentinelBlockRequestHandler implements BlockRequestHandler { + @Autowired + private InetUtils inetUtils; + + @PostConstruct + public void doInit() { + System.setProperty(TransportConfig.HEARTBEAT_CLIENT_IP, inetUtils.findFirstNonLoopbackAddress().getHostAddress()); + } + + @Override + public Mono handleRequest(ServerWebExchange exchange, Throwable ex) { + String resultString = "{\"code\":403,\"message\":\"服务开启限流保护,请稍后再试!\"}"; + return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(resultString)); + } + +} diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/resources/application.yml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/resources/application.yml index eeb8b697..16ca8a17 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/resources/application.yml +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/resources/application.yml @@ -4,6 +4,13 @@ spring: application: name: jeecg-gateway cloud: + #Sentinel配置 + sentinel: + web-context-unify: false + transport: + dashboard: localhost:8087 + # 懒加载Sentinel Dashboard菜单 + eager: false gateway: discovery: locator: diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-monitor/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-monitor/pom.xml index 0a478095..88995824 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-monitor/pom.xml +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-monitor/pom.xml @@ -5,7 +5,7 @@ jeecg-cloud-module org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 jeecg-cloud-monitor diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/Dockerfile b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/Dockerfile index 3800720a..1a8268e5 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/Dockerfile +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/Dockerfile @@ -10,6 +10,6 @@ WORKDIR /jeecg-cloud-nacos EXPOSE 8848 -ADD ./target/jeecg-cloud-nacos-2.4.5.jar ./ +ADD ./target/jeecg-cloud-nacos-2.4.6.jar ./ -CMD sleep 5;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-nacos-2.4.5.jar \ No newline at end of file +CMD sleep 5;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-nacos-2.4.6.jar \ No newline at end of file diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/pom.xml index 9df66ce0..0678ca33 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/pom.xml +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/pom.xml @@ -5,7 +5,7 @@ jeecg-cloud-module org.jeecgframework.boot - 2.4.5 + 2.4.6 jeecg-cloud-nacos jeecg-cloud-nacos @@ -15,7 +15,7 @@ aliyun aliyun Repository - http://maven.aliyun.com/nexus/content/groups/public + https://maven.aliyun.com/repository/public false @@ -23,7 +23,7 @@ jeecg jeecg Repository - http://maven.jeecg.org/nexus/content/repositories/jeecg + https://maven.jeecg.org/nexus/content/repositories/jeecg false diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/src/main/java/com/alibaba/nacos/JeecgNacosApplication.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/src/main/java/com/alibaba/nacos/JeecgNacosApplication.java index 959a4a84..7e819bc8 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/src/main/java/com/alibaba/nacos/JeecgNacosApplication.java +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/src/main/java/com/alibaba/nacos/JeecgNacosApplication.java @@ -1,5 +1,6 @@ package com.alibaba.nacos; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; @@ -30,6 +31,8 @@ public class JeecgNacosApplication { System.setProperty("nacos.standalone", standalone); System.setProperty("nacos.core.auth.enabled", enabled); System.setProperty("server.tomcat.basedir","logs"); + //自定义启动端口号 + System.setProperty("server.port","8848"); SpringApplication.run(JeecgNacosApplication.class, args); } } diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/src/main/resources/application.yml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/src/main/resources/application.yml index 1c5cadf0..ded1f18d 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/src/main/resources/application.yml +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/src/main/resources/application.yml @@ -1,5 +1,4 @@ server: - port: 8848 servlet: contextPath: /nacos tomcat: diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/pom.xml new file mode 100644 index 00000000..05ea1949 --- /dev/null +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/pom.xml @@ -0,0 +1,110 @@ + + + 4.0.0 + + jeecg-cloud-module + org.jeecgframework.boot + 2.4.6 + + jeecg-cloud-sentinel + jeecg-cloud-sentinel + sentinel启动模块 + + + + aliyun + aliyun Repository + https://maven.aliyun.com/repository/public + + false + + + + jeecg + jeecg Repository + https://maven.jeecg.org/nexus/content/repositories/jeecg + + false + + + + + + + org.jeecgframework.cloud + sentinel-dashboard + 1.8.2 + + + com.alibaba.csp + sentinel-datasource-nacos + + + com.alibaba.csp + sentinel-core + + + com.alibaba.csp + sentinel-web-servlet + + + com.alibaba.csp + sentinel-transport-simple-http + + + com.alibaba.csp + sentinel-parameter-flow-control + + + com.alibaba.csp + sentinel-api-gateway-adapter-common + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-undertow + + + + commons-lang + commons-lang + 2.6 + + + + org.apache.httpcomponents + httpclient + 4.5.3 + + + org.apache.httpcomponents + httpcore + 4.4.5 + + + org.apache.httpcomponents + httpasyncclient + 4.1.3 + + + org.apache.httpcomponents + httpcore-nio + 4.4.6 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/src/main/java/com/alibaba/csp/sentinel/dashboard/JeecgSentinelDashboardApplication.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/src/main/java/com/alibaba/csp/sentinel/dashboard/JeecgSentinelDashboardApplication.java new file mode 100644 index 00000000..df66cfa1 --- /dev/null +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/src/main/java/com/alibaba/csp/sentinel/dashboard/JeecgSentinelDashboardApplication.java @@ -0,0 +1,49 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; +import com.alibaba.csp.sentinel.init.InitExecutor; +import lombok.extern.slf4j.Slf4j; + +/** + * Sentinel dashboard application. + * + * @author Carpenter Lee + */ +@SpringBootApplication +@Slf4j +public class JeecgSentinelDashboardApplication { + + public static void main(String[] args) { + System.setProperty("csp.sentinel.app.type", "1"); + triggerSentinelInit(); + ConfigurableApplicationContext application = SpringApplication.run(JeecgSentinelDashboardApplication.class, args); + Environment env = application.getEnvironment(); + String port = env.getProperty("server.port"); + log.info("\n----------------------------------------------------------\n\t" + + "Application SentinelDashboard is running! Access URLs:\n\t" + + "Local: \t\thttp://localhost:" + port + "/\n\t" + + "----------------------------------------------------------"); + } + + private static void triggerSentinelInit() { + new Thread(() -> InitExecutor.doInit()).start(); + } +} diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/src/main/resources/application.properties b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/src/main/resources/application.properties new file mode 100644 index 00000000..1d74c179 --- /dev/null +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/src/main/resources/application.properties @@ -0,0 +1,28 @@ +#spring settings +spring.http.encoding.force=true +spring.http.encoding.charset=UTF-8 +spring.http.encoding.enabled=true + +#cookie name setting +server.servlet.session.cookie.name=sentinel_dashboard_cookie +#spring.cloud.nacos.config.server-addr=127.0.0.1:8848 +#spring.cloud.nacos.config.namespace= +#spring.cloud.nacos.config.group-id=DEFAULT_GROUP +server.port=8087 + +#logging settings +logging.level.org.springframework.web=INFO +logging.file=${user.home}/logs/csp/sentinel-dashboard.log +logging.pattern.file= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n +#logging.pattern.console= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + +#auth settings +auth.filter.exclude-urls=/,/auth/login,/auth/logout,/registry/machine,/version +auth.filter.exclude-url-suffixes=htm,html,js,css,map,ico,ttf,woff,png +# If auth.enabled=false, Sentinel console disable login +auth.username=sentinel +auth.password=sentinel + +# Inject the dashboard version. It's required to enable +# filtering in pom.xml for this resource file. +sentinel.dashboard.version=1.8.2 \ No newline at end of file diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/Dockerfile b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/Dockerfile index 36dc59a8..10bb2128 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/Dockerfile +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/Dockerfile @@ -10,6 +10,6 @@ WORKDIR /jeecg-cloud-system EXPOSE 7001 -ADD ./target/jeecg-cloud-system-start-2.4.5.jar ./ +ADD ./target/jeecg-cloud-system-start-2.4.6.jar ./ -CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-system-start-2.4.5.jar \ No newline at end of file +CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-system-start-2.4.6.jar \ No newline at end of file diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/pom.xml index fd976217..919265ab 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/pom.xml +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/pom.xml @@ -5,7 +5,7 @@ jeecg-cloud-module org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 jeecg-cloud-system-start diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/Dockerfile b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/Dockerfile index 26165129..2a0f6f01 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/Dockerfile +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/Dockerfile @@ -10,7 +10,7 @@ WORKDIR /jeecg-cloud-xxljob EXPOSE 9080 -ADD ./target/jeecg-cloud-xxljob-2.4.5.jar ./ +ADD ./target/jeecg-cloud-xxljob-2.4.6.jar ./ -CMD java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-xxljob-2.4.5.jar +CMD java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-xxljob-2.4.6.jar diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/pom.xml index f928993a..4a2beee5 100644 --- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/pom.xml +++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/pom.xml @@ -5,7 +5,7 @@ jeecg-cloud-module org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 diff --git a/jeecg-boot/jeecg-cloud-module/pom.xml b/jeecg-boot/jeecg-cloud-module/pom.xml index 658c3a94..9c13ae1f 100644 --- a/jeecg-boot/jeecg-cloud-module/pom.xml +++ b/jeecg-boot/jeecg-cloud-module/pom.xml @@ -5,18 +5,19 @@ jeecg-boot-parent org.jeecgframework.boot - 2.4.5 + 2.4.6 4.0.0 jeecg-cloud-module pom - jeecg-cloud-system-start jeecg-cloud-gateway + jeecg-cloud-nacos + jeecg-cloud-sentinel jeecg-cloud-monitor + jeecg-cloud-system-start jeecg-cloud-xxljob - jeecg-cloud-nacos diff --git a/jeecg-boot/pom.xml b/jeecg-boot/pom.xml index da30acba..88706574 100644 --- a/jeecg-boot/pom.xml +++ b/jeecg-boot/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.jeecgframework.boot jeecg-boot-parent - 2.4.5 + 2.4.6 pom @@ -13,25 +13,27 @@ - 2.4.5 + 2.4.6 1.8 UTF-8 Hoxton.SR8 2.2.3.RELEASE 2.2.0 - 1.2.75 - 2.0.8 - 2.0.8 + 1.2.76 + 2.0.9 + 2.0.9 + 42.2.6 11.2.0.3 4.0 8.0.21 + 3.2.0 - 5.3.8 - 3.13.6 + 5.3.8 + 3.16.1 1.9.4 29.0-jre - 3.4.1 + 3.4.3.1 1.1.22 2.6 2.1.0 @@ -39,8 +41,8 @@ 1.7.1 3.11.0 3.1.0 - 1.3.3 - 1.3.2 + 1.3.6 + 1.3.5 8.0.3 1.3.4 1.6.1 @@ -51,9 +53,8 @@ jeecg-boot-base jeecg-boot-module-demo jeecg-boot-module-system - - @@ -73,7 +74,7 @@ aliyun aliyun Repository - http://maven.aliyun.com/nexus/content/groups/public + https://maven.aliyun.com/repository/public false @@ -81,7 +82,7 @@ jeecg jeecg Repository - http://maven.jeecg.org/nexus/content/repositories/jeecg + https://maven.jeecg.org/nexus/content/repositories/jeecg false @@ -222,8 +223,13 @@ cn.hutool - hutool-all - ${hutool-all.version} + hutool-core + ${hutool.version} + + + cn.hutool + hutool-crypto + ${hutool.version}