版本合并,升级springboot3分支到3.7.3

This commit is contained in:
JEECG
2025-02-20 17:56:16 +08:00
230 changed files with 23438 additions and 12308 deletions

View File

@ -84,6 +84,12 @@ public class MessageDTO implements Serializable {
* 邮件抄送地址
*/
protected Set<String> ccEmailList;
/**
* 是否为定时任务推送email
*/
private Boolean isTimeJob = false;
//---【邮件相关参数】-------------------------------------------------------------
public MessageDTO(){

View File

@ -604,6 +604,11 @@ public interface CommonConstant {
*/
String CHANGE_PHONE_REDIS_KEY_PRE = "sys:cache:phone:change_phone_msg:";
/**
* 手机号短信验证码redis-key的前缀
*/
String LOG_OFF_PHONE_REDIS_KEY_PRE = "sys:cache:phone:qqy_log_off_user_msg:";
/**
* 缓存用户最后一次收到消息通知的时间 KEY
*/

View File

@ -15,15 +15,7 @@ public enum DySmsEnum {
/**修改密码短信模板编码*/
CHANGE_PASSWORD_TEMPLATE_CODE("SMS_465391221","敲敲云","code"),
/**注册账号短信模板编码*/
REGISTER_TEMPLATE_CODE("SMS_175430166","敲敲云","code"),
/**会议通知*/
MEET_NOTICE_TEMPLATE_CODE("SMS_201480469","JEECG","username,title,minute,time"),
/**我的计划通知*/
PLAN_NOTICE_TEMPLATE_CODE("SMS_201470515","JEECG","username,title,time"),
/**支付成功短信通知*/
PAY_SUCCESS_NOTICE_CODE("SMS_461735163","敲敲云","realname,money,endTime"),
/**会员到期通知提醒*/
VIP_EXPIRE_NOTICE_CODE("SMS_461885023","敲敲云","realname,endTime");
REGISTER_TEMPLATE_CODE("SMS_175430166","敲敲云","code");
/**
* 短信模板编码

View File

@ -805,7 +805,9 @@ public class QueryGenerator {
addEasyQuery(queryWrapper, name, rule, DateUtils.str2Date(dateStr,DateUtils.datetimeFormat.get()));
}
}else {
addEasyQuery(queryWrapper, name, rule, NumberUtils.parseNumber(dataRule.getRuleValue(), propertyType));
//update-begin---author:chenrui ---date:20241125 for[issues/7481]多租户模式下 数据权限使用变量:#{tenant_id} 报错------------
addEasyQuery(queryWrapper, name, rule, NumberUtils.parseNumber(converRuleValue(dataRule.getRuleValue()), propertyType));
//update-end---author:chenrui ---date:20241125 for[issues/7481]多租户模式下 数据权限使用变量:#{tenant_id} 报错------------
}
}
}
@ -859,7 +861,9 @@ public class QueryGenerator {
return null;
}
Set<String> varParams = new HashSet<String>();
String regex = "\\#\\{\\w+\\}";
//update-begin---author:chenrui ---date:20250108 for[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
String regex = "#\\{\\[*\\w+]*}";
//update-end---author:chenrui ---date:20250108 for[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(sql);

View File

@ -54,8 +54,10 @@ public enum QueryRuleEnum {
NOT_EMPTY("NOT_EMPTY","not_empty","值不为空"),
/**查询规则 不包含*/
NOT_IN("NOT_IN","not_in","不包含"),
/**查询规则 多词匹配*/
/**查询规则 多词精确匹配*/
ELE_MATCH("ELE_MATCH","elemMatch","多词匹配"),
/**查询规则 多词精确不匹配*/
ELE_NOT_MATCH("ELE_NOT_MATCH","elemNotMatch","多词精确不匹配"),
/**查询规则 范围查询*/
RANGE("RANGE","range","范围查询"),
/**查询规则 不在范围内查询*/

View File

@ -11,6 +11,9 @@ import com.google.common.base.Joiner;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Objects;
import java.util.stream.Collectors;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@ -63,7 +66,7 @@ public class JwtUtil {
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getMessage(), e);
}
}
@ -82,7 +85,8 @@ public class JwtUtil {
// 效验TOKEN
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception exception) {
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
@ -97,6 +101,7 @@ public class JwtUtil {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username").asString();
} catch (JWTDecodeException e) {
log.warn(e.getMessage(), e);
return null;
}
}
@ -195,6 +200,14 @@ public class JwtUtil {
} else {
key = key;
}
//update-begin---author:chenrui ---date:20250107 for[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
// 是否存在字符串标志
boolean multiStr = false;
if(oConvertUtils.isNotEmpty(key) && key.trim().matches("^\\[\\w+]$")){
key = key.substring(1,key.length()-1);
multiStr = true;
}
//update-end---author:chenrui ---date:20250107 for[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
//替换为当前系统时间(年月日)
if (key.equals(DataBaseConstant.SYS_DATE)|| key.toLowerCase().equals(DataBaseConstant.SYS_DATE_TABLE)) {
returnValue = DateUtils.formatDate();
@ -263,11 +276,22 @@ public class JwtUtil {
if(user==null){
//TODO 暂时使用用户登录部门,存在逻辑缺陷,不是用户所拥有的部门
returnValue = sysUser.getOrgCode();
//update-begin---author:chenrui ---date:20250107 for[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
returnValue = multiStr ? "'" + returnValue + "'" : returnValue;
//update-end---author:chenrui ---date:20250107 for[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
}else{
if(user.isOneDepart()) {
returnValue = user.getSysMultiOrgCode().get(0);
//update-begin---author:chenrui ---date:20250107 for[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
returnValue = multiStr ? "'" + returnValue + "'" : returnValue;
//update-end---author:chenrui ---date:20250107 for[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
}else {
returnValue = Joiner.on(",").join(user.getSysMultiOrgCode());
//update-begin---author:chenrui ---date:20250107 for[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
returnValue = user.getSysMultiOrgCode().stream()
.filter(Objects::nonNull)
.map(orgCode -> "'" + orgCode + "'")
.collect(Collectors.joining(", "));
//update-end---author:chenrui ---date:20250107 for[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
}
}
}

View File

@ -1,5 +1,6 @@
package org.jeecg.common.util;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
@ -8,11 +9,15 @@ import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.enums.DySmsEnum;
import org.jeecg.config.JeecgSmsTemplateConfig;
import org.jeecg.config.StaticConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* Created on 17/6/7.
* 短信API产品的DEMO程序,工程中包含了一个SmsDemo类直接通过
@ -75,15 +80,33 @@ public class DySmsHelper {
//验证json参数
validateParam(templateParamJson,dySmsEnum);
//update-begin---author:wangshuai---date:2024-11-05---for:【QQYUN-9422】短信模板管理阿里云---
String templateCode = dySmsEnum.getTemplateCode();
JeecgSmsTemplateConfig baseConfig = SpringContextUtils.getBean(JeecgSmsTemplateConfig.class);
if(baseConfig != null && CollectionUtil.isNotEmpty(baseConfig.getTemplateCode())){
Map<String, String> smsTemplate = baseConfig.getTemplateCode();
if(smsTemplate.containsKey(templateCode) && StringUtils.isNotEmpty(smsTemplate.get(templateCode))){
templateCode = smsTemplate.get(templateCode);
logger.info("yml中读取短信code{}",templateCode);
}
}
//签名名称
String signName = dySmsEnum.getSignName();
if(baseConfig != null && StringUtils.isNotEmpty(baseConfig.getSignature())){
logger.info("yml中读取签名名称{}",baseConfig.getSignature());
signName = baseConfig.getSignature();
}
//update-end---author:wangshuai---date:2024-11-05---for:【QQYUN-9422】短信模板管理阿里云---
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号
request.setPhoneNumbers(phone);
//必填:短信签名-可在短信控制台中找到
request.setSignName(dySmsEnum.getSignName());
request.setSignName(signName);
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode(dySmsEnum.getTemplateCode());
request.setTemplateCode(templateCode);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam(templateParamJson.toJSONString());

View File

@ -4,9 +4,13 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.handler.IFillRuleHandler;
import org.jeecg.common.system.query.QueryGenerator;
/**
@ -42,6 +46,30 @@ public class FillRuleUtil {
if (params == null) {
params = new JSONObject();
}
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
// 解析 params 中的变量
// 优先级queryString > 系统变量 > 默认值
for (String key : params.keySet()) {
// 1. 判断 queryString 中是否有该参数,如果有就优先取值
//noinspection ConstantValue
if (request != null) {
String parameter = request.getParameter(key);
if (oConvertUtils.isNotEmpty(parameter)) {
params.put(key, parameter);
continue;
}
}
String value = params.getString(key);
// 2. 用于替换 系统变量的值 #{sys_user_code}
if (value != null && value.contains(SymbolConstant.SYS_VAR_PREFIX)) {
value = QueryGenerator.getSqlRuleValue(value);
params.put(key, value);
}
}
if (formData == null) {
formData = new JSONObject();
}

View File

@ -57,8 +57,8 @@ public class RestUtil {
static {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(3000);
requestFactory.setReadTimeout(3000);
requestFactory.setConnectTimeout(30000);
requestFactory.setReadTimeout(30000);
RT = new RestTemplate(requestFactory);
// 解决乱码问题
RT.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));

View File

@ -84,6 +84,10 @@ public class DynamicDBUtil {
} else {
DruidDataSource dataSource = getJdbcDataSource(dbSource);
if(dataSource!=null && dataSource.isEnable()){
// 【TV360X-2060】设置超时时间 6秒
dataSource.setMaxWait(6000);
DataSourceCachePool.putCacheBasicDataSource(dbKey, dataSource);
}else{
throw new JeecgBootException("动态数据源连接失败dbKey"+dbKey);
@ -106,9 +110,10 @@ public class DynamicDBUtil {
dataSource.getConnection().commit();
dataSource.getConnection().close();
dataSource.close();
DataSourceCachePool.removeCache(dbKey);
}
} catch (SQLException e) {
e.printStackTrace();
log.warn(e.getMessage(), e);
}
}

View File

@ -73,6 +73,12 @@ public class JSqlParserUtils {
* @return
*/
private static SelectSqlInfo parseBySelectBody(SelectBody selectBody) {
// 判断是否使用了union等操作
if (selectBody instanceof SetOperationList) {
// 如果使用了union等操作则只解析第一个查询
List<SelectBody> selectBodyList = ((SetOperationList) selectBody).getSelects();
return JSqlParserUtils.parseBySelectBody(selectBodyList.get(0));
}
// 简单的select查询
if (selectBody instanceof PlainSelect) {
SelectSqlInfo sqlInfo = new SelectSqlInfo(selectBody);

View File

@ -0,0 +1,33 @@
package org.jeecg.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @Description: 短信模板
*
* @author: wangshuai
* @date: 2024/11/5 下午3:44
*/
@Data
@Component("jeecgSmsTemplateConfig")
@ConfigurationProperties(prefix = "jeecg.oss.sms-template")
public class JeecgSmsTemplateConfig {
/**
* 短信签名
*/
private String signature;
/**
* 短信模板code
*
* @return
*/
private Map<String,String> templateCode;
}

View File

@ -21,6 +21,12 @@ public class StaticConfig {
@Value(value = "${spring.mail.username:}")
private String emailFrom;
/**
* 是否开启定时发送
*/
@Value(value = "${spring.mail.timeJobSend:false}")
private Boolean timeJobSend;
// /**
// * 签名密钥串
// */

View File

@ -31,7 +31,7 @@ public class WebSocketConfig {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(websocketFilter());
//TODO 临时注释掉测试下线上socket总断的问题
bean.addUrlPatterns("/taskCountSocket/*", "/websocket/*","/eoaSocket/*","/eoaNewChatSocket/*", "/newsWebsocket/*", "/vxeSocket/*");
bean.addUrlPatterns("/taskCountSocket/*", "/websocket/*","/eoaSocket/*","/eoaNewChatSocket/*", "/newsWebsocket/*", "/dragChannelSocket/*", "/vxeSocket/*");
return bean;
}

View File

@ -1,6 +1,5 @@
package org.jeecg.config.shiro;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
@ -127,6 +126,8 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/**/*.ttf", "anon");
filterChainDefinitionMap.put("/**/*.woff", "anon");
filterChainDefinitionMap.put("/**/*.woff2", "anon");
filterChainDefinitionMap.put("/**/*.glb", "anon");
filterChainDefinitionMap.put("/**/*.wasm", "anon");
//update-end--Author:scott Date:20221116 for排除静态资源后缀
filterChainDefinitionMap.put("/druid/**", "anon");
@ -144,12 +145,18 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/**/*.js.map", "anon");
filterChainDefinitionMap.put("/**/*.css.map", "anon");
//拖拽仪表盘设计器排除
//积木BI大屏和仪表盘排除
filterChainDefinitionMap.put("/drag/view", "anon");
filterChainDefinitionMap.put("/drag/page/queryById", "anon");
filterChainDefinitionMap.put("/drag/page/addVisitsNumber", "anon");
filterChainDefinitionMap.put("/drag/page/queryTemplateList", "anon");
filterChainDefinitionMap.put("/drag/share/view/**", "anon");
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getAllChartData", "anon");
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getTotalData", "anon");
filterChainDefinitionMap.put("/drag/mock/json/**", "anon");
filterChainDefinitionMap.put("/jimubi/view", "anon");
filterChainDefinitionMap.put("/jimubi/share/view/**", "anon");
//大屏模板例子
filterChainDefinitionMap.put("/test/bigScreen/**", "anon");
filterChainDefinitionMap.put("/bigscreen/template1/**", "anon");
@ -173,6 +180,8 @@ public class ShiroConfig {
// 企业微信证书排除
filterChainDefinitionMap.put("/WW_verify*", "anon");
filterChainDefinitionMap.put("/openapi/call/**", "anon");
// 添加自己的过滤器并且取名为jwt
Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
//如果cloudServer为空 则说明是单体 需要加载跨域配置【微服务跨域切换】
@ -190,12 +199,24 @@ public class ShiroConfig {
}
//update-begin---author:chenrui ---date:20240126 for【QQYUN-7932】AI助手------------
/**
* spring过滤装饰器 <br/>
* 因为shiro的filter不支持异步请求,导致所有的异步请求都会报错. <br/>
* 所以需要用spring的FilterRegistrationBean再代理一下shiro的filter.为他扩展异步支持. <br/>
* 后续所有异步的接口都需要再这里增加registration.addUrlPatterns("/xxx/xxx");
* @return
* @author chenrui
* @date 2024/12/3 19:49
*/
@Bean
public FilterRegistrationBean shiroFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new DelegatingFilterProxy("shiroFilterFactoryBean"));
registration.setEnabled(true);
registration.addUrlPatterns("/*");
//update-begin---author:chenrui ---date:20241202 for[issues/7491]运行时间好长,效率慢 ------------
registration.addUrlPatterns("/test/ai/chat/send");
//update-end---author:chenrui ---date:20241202 for[issues/7491]运行时间好长,效率慢 ------------
//支持异步
registration.setAsyncSupported(true);
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);

View File

@ -168,8 +168,8 @@ public class ShiroRealm extends AuthorizingRealm {
//*********************************************
if(!isAuthorization){
log.warn("租户异常——当前登录租户" + contextTenantId);
log.warn("租户异常——用户拥有租户" + userTenantIds);
log.info("租户异常——登录租户:" + contextTenantId);
log.info("租户异常——用户拥有租户" + userTenantIds);
throw new AuthenticationException("登录租户授权变更,请重新登陆!");
}
//*********************************************