mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
【v3.8.3】底层core的一些功能修改
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
package org.jeecg.common.api;
|
package org.jeecg.common.api;
|
||||||
|
|
||||||
|
import org.jeecg.common.api.dto.AiragFlowDTO;
|
||||||
import org.jeecg.common.system.vo.*;
|
import org.jeecg.common.system.vo.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -144,4 +145,15 @@ public interface CommonAPI {
|
|||||||
List<DictModel> translateDictFromTableByKeys(String table, String text, String code, String keys, String dataSource);
|
List<DictModel> translateDictFromTableByKeys(String table, String text, String code, String keys, String dataSource);
|
||||||
//update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------
|
//update-end---author:chenrui ---date:20231221 for:[issues/#5643]解决分布式下表字典跨库无法查询问题------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16 运行AIRag流程
|
||||||
|
* for [QQYUN-13634]在baseapi里面封装方法,方便其他模块调用
|
||||||
|
*
|
||||||
|
* @param airagFlowDTO
|
||||||
|
* @return 流程执行结果,可能是String或者Map
|
||||||
|
* @author chenrui
|
||||||
|
* @date 2025/9/2 11:43
|
||||||
|
*/
|
||||||
|
Object runAiragFlow(AiragFlowDTO airagFlowDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
package org.jeecg.common.api.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用AI流程入参
|
||||||
|
* for [QQYUN-13634]在baseapi里面封装方法,方便其他模块调用
|
||||||
|
* @author chenrui
|
||||||
|
* @date 2025/9/2 14:11
|
||||||
|
*/
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class AiragFlowDTO implements Serializable {
|
||||||
|
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 7431775881170684867L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程id
|
||||||
|
*/
|
||||||
|
private String flowId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入参数
|
||||||
|
*/
|
||||||
|
private Map<String, Object> inputParams;
|
||||||
|
}
|
||||||
@ -642,11 +642,12 @@ public interface CommonConstant {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义首页关联关系(ROLE:表示角色 USER:表示用户)
|
* 自定义首页关联关系(ROLE:表示角色 USER:表示用户 DEFAULT:默认首页)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
String HOME_RELATION_ROLE = "ROLE";
|
String HOME_RELATION_ROLE = "ROLE";
|
||||||
String HOME_RELATION_USER = "USER";
|
String HOME_RELATION_USER = "USER";
|
||||||
|
String HOME_RELATION_DEFAULT = "DEFAULT";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否置顶(0否 1是)
|
* 是否置顶(0否 1是)
|
||||||
@ -659,4 +660,53 @@ public interface CommonConstant {
|
|||||||
String FLOW_FOCUS_NOTICE_PREFIX = "flow:runtimeData:focus:notice:";
|
String FLOW_FOCUS_NOTICE_PREFIX = "flow:runtimeData:focus:notice:";
|
||||||
//任务缓办时间缓存前缀
|
//任务缓办时间缓存前缀
|
||||||
String FLOW_TASK_DELAY_PREFIX = "flow:runtimeData:task:delay:";
|
String FLOW_TASK_DELAY_PREFIX = "flow:runtimeData:task:delay:";
|
||||||
|
/**
|
||||||
|
* 用户代理类型:离职:quit 代理:agent
|
||||||
|
*/
|
||||||
|
String USER_AGENT_TYPE_QUIT = "quit";
|
||||||
|
String USER_AGENT_TYPE_AGENT = "agent";
|
||||||
|
/**
|
||||||
|
* 督办流程首节点任务taskKey
|
||||||
|
*/
|
||||||
|
String SUPERVISE_FIRST_TASK_KEY = "Task_1bhxpt0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wps模板预览数据缓存前缀
|
||||||
|
*/
|
||||||
|
String EOA_WPS_TEMPLATE_VIEW_DATA ="eoa:wps:templateViewData:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wps模板预览版本号缓存前缀
|
||||||
|
*/
|
||||||
|
String EOA_WPS_TEMPLATE_VIEW_VERSION ="eoa:wps:templateViewVersion:";
|
||||||
|
/**
|
||||||
|
* 表单设计器oa新增字段
|
||||||
|
* x_oa_timeout_date:逾期时间
|
||||||
|
* x_oa_archive_status:归档状态
|
||||||
|
*/
|
||||||
|
String X_OA_TIMEOUT_DATE ="x_oa_timeout_date";
|
||||||
|
String X_OA_ARCHIVE_STATUS ="x_oa_archive_status";
|
||||||
|
/**
|
||||||
|
* 流程状态
|
||||||
|
* 待提交: 1
|
||||||
|
* 处理中: 2
|
||||||
|
* 已完成: 3
|
||||||
|
* 已作废: 4
|
||||||
|
* 已挂起: 5
|
||||||
|
*/
|
||||||
|
String BPM_STATUS_1 ="1";
|
||||||
|
String BPM_STATUS_2 ="2";
|
||||||
|
String BPM_STATUS_3 ="3";
|
||||||
|
String BPM_STATUS_4 ="4";
|
||||||
|
String BPM_STATUS_5 ="5";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认租户产品包
|
||||||
|
*/
|
||||||
|
String TENANT_PACK_DEFAULT = "default";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门名称redisKey(全路径)
|
||||||
|
*/
|
||||||
|
String DEPART_NAME_REDIS_KEY_PRE = "sys:cache:departPathName:";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
package org.jeecg.common.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 密码常量类
|
||||||
|
*
|
||||||
|
* @author: wangshuai
|
||||||
|
* @date: 2025/8/27 20:10
|
||||||
|
*/
|
||||||
|
public interface PasswordConstant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入用户默认密码
|
||||||
|
*/
|
||||||
|
String DEFAULT_PASSWORD = "123456";
|
||||||
|
}
|
||||||
@ -121,7 +121,7 @@ public class ProvinceCityArea {
|
|||||||
|
|
||||||
public void getAreaByCode(String code,List<String> ls){
|
public void getAreaByCode(String code,List<String> ls){
|
||||||
for(Area area: areaList){
|
for(Area area: areaList){
|
||||||
if(area.getId().equals(code)){
|
if(null != area && area.getId().equals(code)){
|
||||||
String pid = area.getPid();
|
String pid = area.getPid();
|
||||||
ls.add(0,area.getText());
|
ls.add(0,area.getText());
|
||||||
getAreaByCode(pid,ls);
|
getAreaByCode(pid,ls);
|
||||||
|
|||||||
@ -8,21 +8,30 @@ import java.util.List;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息类型
|
* 消息类型
|
||||||
|
*
|
||||||
* @author: jeecg-boot
|
* @author: jeecg-boot
|
||||||
*/
|
*/
|
||||||
@EnumDict("messageType")
|
@EnumDict("messageType")
|
||||||
public enum MessageTypeEnum {
|
public enum MessageTypeEnum {
|
||||||
|
|
||||||
/** 系统消息 */
|
/**
|
||||||
XT("system", "系统消息"),
|
* 系统消息
|
||||||
/** 邮件消息 */
|
*/
|
||||||
YJ("email", "邮件消息"),
|
XT("system", "系统消息"),
|
||||||
/** 钉钉消息 */
|
/**
|
||||||
|
* 邮件消息
|
||||||
|
*/
|
||||||
|
YJ("email", "邮件消息"),
|
||||||
|
/**
|
||||||
|
* 钉钉消息
|
||||||
|
*/
|
||||||
DD("dingtalk", "钉钉消息"),
|
DD("dingtalk", "钉钉消息"),
|
||||||
/** 企业微信 */
|
/**
|
||||||
|
* 企业微信
|
||||||
|
*/
|
||||||
QYWX("wechat_enterprise", "企业微信");
|
QYWX("wechat_enterprise", "企业微信");
|
||||||
|
|
||||||
MessageTypeEnum(String type, String note){
|
MessageTypeEnum(String type, String note) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.note = note;
|
this.note = note;
|
||||||
}
|
}
|
||||||
@ -56,12 +65,13 @@ public enum MessageTypeEnum {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取字典数据
|
* 获取字典数据
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static List<DictModel> getDictList(){
|
public static List<DictModel> getDictList() {
|
||||||
List<DictModel> list = new ArrayList<>();
|
List<DictModel> list = new ArrayList<>();
|
||||||
DictModel dictModel = null;
|
DictModel dictModel = null;
|
||||||
for(MessageTypeEnum e: MessageTypeEnum.values()){
|
for (MessageTypeEnum e : MessageTypeEnum.values()) {
|
||||||
dictModel = new DictModel();
|
dictModel = new DictModel();
|
||||||
dictModel.setValue(e.getType());
|
dictModel.setValue(e.getType());
|
||||||
dictModel.setText(e.getNote());
|
dictModel.setText(e.getNote());
|
||||||
|
|||||||
@ -14,7 +14,16 @@ public enum NoticeTypeEnum {
|
|||||||
NOTICE_TYPE_PLAN("日程消息","plan"),
|
NOTICE_TYPE_PLAN("日程消息","plan"),
|
||||||
//暂时没用到
|
//暂时没用到
|
||||||
NOTICE_TYPE_MEETING("会议消息","meeting"),
|
NOTICE_TYPE_MEETING("会议消息","meeting"),
|
||||||
NOTICE_TYPE_SYSTEM("系统消息","system");
|
NOTICE_TYPE_SYSTEM("系统消息","system"),
|
||||||
|
/**
|
||||||
|
* 协同工作
|
||||||
|
* for [JHHB-136]【vue3】协同工作系统消息需要添加一个类型
|
||||||
|
*/
|
||||||
|
NOTICE_TYPE_COLLABORATION("协同工作", "collab"),
|
||||||
|
/**
|
||||||
|
* 督办
|
||||||
|
*/
|
||||||
|
NOTICE_TYPE_SUPERVISE("督办管理", "supe");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件类型名称
|
* 文件类型名称
|
||||||
|
|||||||
@ -23,7 +23,25 @@ public enum SysAnnmentTypeEnum {
|
|||||||
/**
|
/**
|
||||||
* 邀请用户跳转到个人设置
|
* 邀请用户跳转到个人设置
|
||||||
*/
|
*/
|
||||||
TENANT_INVITE("tenant_invite", "url", "/system/usersetting");
|
TENANT_INVITE("tenant_invite", "url", "/system/usersetting"),
|
||||||
|
/**
|
||||||
|
* 协同工作-待办通知
|
||||||
|
* for [JHHB-136]【vue3】协同工作系统消息需要添加一个类型
|
||||||
|
*/
|
||||||
|
EOA_CO_NOTIFY("eoa_co_notify", "url", "/collaboration/pending"),
|
||||||
|
/**
|
||||||
|
* 协同工作-催办通知
|
||||||
|
* for [JHHB-136]【vue3】协同工作系统消息需要添加一个类型
|
||||||
|
*/
|
||||||
|
EOA_CO_REMIND("eoa_co_remind", "url", "/collaboration/pending"),
|
||||||
|
/**
|
||||||
|
* 督办管理-催办
|
||||||
|
*/
|
||||||
|
EOA_SUP_REMIND("eoa_sup_remind", "url", "/superivse/list"),
|
||||||
|
/**
|
||||||
|
* 督办管理-通知
|
||||||
|
*/
|
||||||
|
EOA_SUP_NOTIFY("eoa_sup_notify", "url", "/superivse/list");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 业务类型(email:邮件 bpm:流程)
|
* 业务类型(email:邮件 bpm:流程)
|
||||||
|
|||||||
@ -414,9 +414,11 @@ public class QueryGenerator {
|
|||||||
}
|
}
|
||||||
// update-begin-author:sunjianlei date:20220119 for: 【JTC-573】 过滤空条件查询,防止 sql 拼接多余的 and
|
// update-begin-author:sunjianlei date:20220119 for: 【JTC-573】 过滤空条件查询,防止 sql 拼接多余的 and
|
||||||
List<QueryCondition> filterConditions = conditions.stream().filter(
|
List<QueryCondition> filterConditions = conditions.stream().filter(
|
||||||
rule -> oConvertUtils.isNotEmpty(rule.getField())
|
rule -> (oConvertUtils.isNotEmpty(rule.getField())
|
||||||
&& oConvertUtils.isNotEmpty(rule.getRule())
|
&& oConvertUtils.isNotEmpty(rule.getRule())
|
||||||
&& oConvertUtils.isNotEmpty(rule.getVal())
|
&& oConvertUtils.isNotEmpty(rule.getVal())
|
||||||
|
)
|
||||||
|
|| "empty".equals(rule.getRule())
|
||||||
).collect(Collectors.toList());
|
).collect(Collectors.toList());
|
||||||
if (filterConditions.size() == 0) {
|
if (filterConditions.size() == 0) {
|
||||||
return;
|
return;
|
||||||
@ -427,9 +429,12 @@ public class QueryGenerator {
|
|||||||
queryWrapper.and(andWrapper -> {
|
queryWrapper.and(andWrapper -> {
|
||||||
for (int i = 0; i < filterConditions.size(); i++) {
|
for (int i = 0; i < filterConditions.size(); i++) {
|
||||||
QueryCondition rule = filterConditions.get(i);
|
QueryCondition rule = filterConditions.get(i);
|
||||||
if (oConvertUtils.isNotEmpty(rule.getField())
|
if (
|
||||||
&& oConvertUtils.isNotEmpty(rule.getRule())
|
(
|
||||||
&& oConvertUtils.isNotEmpty(rule.getVal())) {
|
oConvertUtils.isNotEmpty(rule.getField()) && oConvertUtils.isNotEmpty(rule.getRule()) && oConvertUtils.isNotEmpty(rule.getVal())
|
||||||
|
)
|
||||||
|
|| "empty".equals(rule.getRule())
|
||||||
|
) {
|
||||||
|
|
||||||
log.debug("SuperQuery ==> " + rule.toString());
|
log.debug("SuperQuery ==> " + rule.toString());
|
||||||
|
|
||||||
@ -716,7 +721,11 @@ public class QueryGenerator {
|
|||||||
* @param value 查询条件值
|
* @param value 查询条件值
|
||||||
*/
|
*/
|
||||||
public static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) {
|
public static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) {
|
||||||
if (name==null || value == null || rule == null || oConvertUtils.isEmpty(value)) {
|
if (
|
||||||
|
(
|
||||||
|
name==null || value == null || rule == null || oConvertUtils.isEmpty(value)
|
||||||
|
)
|
||||||
|
&& !QueryRuleEnum.EMPTY.equals(rule)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
name = oConvertUtils.camelToUnderline(name);
|
name = oConvertUtils.camelToUnderline(name);
|
||||||
@ -728,6 +737,9 @@ public class QueryGenerator {
|
|||||||
case GE:
|
case GE:
|
||||||
queryWrapper.ge(name, value);
|
queryWrapper.ge(name, value);
|
||||||
break;
|
break;
|
||||||
|
case EMPTY:
|
||||||
|
queryWrapper.isNull(name);
|
||||||
|
break;
|
||||||
case LT:
|
case LT:
|
||||||
queryWrapper.lt(name, value);
|
queryWrapper.lt(name, value);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -49,24 +49,24 @@ public class JwtUtil {
|
|||||||
* @param code
|
* @param code
|
||||||
* @param errorMsg
|
* @param errorMsg
|
||||||
*/
|
*/
|
||||||
public static void responseError(ServletResponse response, Integer code, String errorMsg) {
|
public static void responseError(HttpServletResponse response, Integer code, String errorMsg) {
|
||||||
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
try {
|
||||||
// issues/I4YH95浏览器显示乱码问题
|
Result jsonResult = new Result(code, errorMsg);
|
||||||
httpServletResponse.setHeader("Content-type", "text/html;charset=UTF-8");
|
jsonResult.setSuccess(false);
|
||||||
Result jsonResult = new Result(code, errorMsg);
|
|
||||||
jsonResult.setSuccess(false);
|
// 设置响应头和内容类型
|
||||||
OutputStream os = null;
|
response.setStatus(code);
|
||||||
try {
|
response.setHeader("Content-type", "text/html;charset=UTF-8");
|
||||||
os = httpServletResponse.getOutputStream();
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
httpServletResponse.setCharacterEncoding("UTF-8");
|
// 使用 ObjectMapper 序列化为 JSON 字符串
|
||||||
httpServletResponse.setStatus(code);
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
os.write(new ObjectMapper().writeValueAsString(jsonResult).getBytes("UTF-8"));
|
String json = objectMapper.writeValueAsString(jsonResult);
|
||||||
os.flush();
|
response.getWriter().write(json);
|
||||||
os.close();
|
response.getWriter().flush();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验token是否正确
|
* 校验token是否正确
|
||||||
@ -99,7 +99,7 @@ public class JwtUtil {
|
|||||||
DecodedJWT jwt = JWT.decode(token);
|
DecodedJWT jwt = JWT.decode(token);
|
||||||
return jwt.getClaim("username").asString();
|
return jwt.getClaim("username").asString();
|
||||||
} catch (JWTDecodeException e) {
|
} catch (JWTDecodeException e) {
|
||||||
log.warn(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,8 @@ import java.time.LocalDate;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
@ -814,4 +816,44 @@ public class DateUtils extends PropertyEditorSupport {
|
|||||||
return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR);
|
return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取两个日期之间的所有日期列表,包含开始和结束日期
|
||||||
|
*
|
||||||
|
* @param begin
|
||||||
|
* @param end
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static List<Date> getDateRangeList(Date begin, Date end) {
|
||||||
|
List<Date> dateList = new ArrayList<>();
|
||||||
|
if (begin == null || end == null) {
|
||||||
|
return dateList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除时间部分,只比较日期
|
||||||
|
Calendar beginCal = Calendar.getInstance();
|
||||||
|
beginCal.setTime(begin);
|
||||||
|
beginCal.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
beginCal.set(Calendar.MINUTE, 0);
|
||||||
|
beginCal.set(Calendar.SECOND, 0);
|
||||||
|
beginCal.set(Calendar.MILLISECOND, 0);
|
||||||
|
|
||||||
|
Calendar endCal = Calendar.getInstance();
|
||||||
|
endCal.setTime(end);
|
||||||
|
endCal.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
endCal.set(Calendar.MINUTE, 0);
|
||||||
|
endCal.set(Calendar.SECOND, 0);
|
||||||
|
endCal.set(Calendar.MILLISECOND, 0);
|
||||||
|
|
||||||
|
if (endCal.before(beginCal)) {
|
||||||
|
return dateList;
|
||||||
|
}
|
||||||
|
|
||||||
|
dateList.add(beginCal.getTime());
|
||||||
|
while (beginCal.before(endCal)) {
|
||||||
|
beginCal.add(Calendar.DAY_OF_YEAR, 1);
|
||||||
|
dateList.add(beginCal.getTime());
|
||||||
|
}
|
||||||
|
return dateList;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,14 +1,22 @@
|
|||||||
package org.jeecg.common.util;
|
package org.jeecg.common.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
import org.jeecg.common.exception.JeecgBootException;
|
||||||
|
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
@ -203,4 +211,150 @@ public class FileDownloadUtils {
|
|||||||
dir.mkdirs();
|
dir.mkdirs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载单个文件到ZIP流
|
||||||
|
* 核心功能:获取文件流,写入ZIP条目
|
||||||
|
* @param fileUrl 文件URL(可以是HTTP URL或本地路径)
|
||||||
|
* @param fileName ZIP内的文件名
|
||||||
|
* @param zous ZIP输出流
|
||||||
|
*/
|
||||||
|
public static void downLoadSingleFile(String fileUrl, String fileName, String uploadUrl,ZipArchiveOutputStream zous) {
|
||||||
|
InputStream inputStream = null;
|
||||||
|
try {
|
||||||
|
// 创建ZIP条目:每个文件在ZIP中都是一个独立条目
|
||||||
|
ZipArchiveEntry entry = new ZipArchiveEntry(fileName);
|
||||||
|
zous.putArchiveEntry(entry);
|
||||||
|
|
||||||
|
// 获取文件输入流:区分普通文件和快捷方式
|
||||||
|
if (fileUrl.endsWith(".url")) {
|
||||||
|
// 处理快捷方式:生成.url文件内容
|
||||||
|
inputStream = FileDownloadUtils.createInternetShortcut(fileName, fileUrl, "");
|
||||||
|
} else {
|
||||||
|
// 普通文件下载:从URL或本地路径获取流
|
||||||
|
inputStream = getDownInputStream(fileUrl,uploadUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputStream != null) {
|
||||||
|
// 将文件流写入ZIP
|
||||||
|
IOUtils.copy(inputStream, zous);
|
||||||
|
}
|
||||||
|
// 关闭当前ZIP条目
|
||||||
|
zous.closeArchiveEntry();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("文件下载失败: {}", e);
|
||||||
|
} finally {
|
||||||
|
// 确保输入流关闭
|
||||||
|
IoUtil.close(inputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下载文件输入流
|
||||||
|
* 功能:根据URL类型(HTTP或本地)获取文件流
|
||||||
|
* @param fileUrl 文件URL(支持HTTP和本地路径)
|
||||||
|
* @return 文件输入流,失败返回null
|
||||||
|
*/
|
||||||
|
public static InputStream getDownInputStream(String fileUrl, String uploadUrl) {
|
||||||
|
try {
|
||||||
|
// 处理HTTP URL:通过网络下载
|
||||||
|
if (oConvertUtils.isNotEmpty(fileUrl) && fileUrl.startsWith(CommonConstant.STR_HTTP)) {
|
||||||
|
URL url = new URL(fileUrl);
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setConnectTimeout(5000); // 连接超时5秒
|
||||||
|
connection.setReadTimeout(30000); // 读取超时30秒
|
||||||
|
return connection.getInputStream();
|
||||||
|
} else {
|
||||||
|
// 处理本地文件:直接读取文件系统
|
||||||
|
String downloadFilePath = uploadUrl + File.separator + fileUrl;
|
||||||
|
// 安全检查:防止下载危险文件类型
|
||||||
|
SsrfFileTypeFilter.checkDownloadFileType(downloadFilePath);
|
||||||
|
return new BufferedInputStream(new FileInputStream(downloadFilePath));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// 异常时返回null,上层会处理空流情况
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件扩展名
|
||||||
|
* 功能:从文件名中提取扩展名
|
||||||
|
* @param fileName 文件名
|
||||||
|
* @return 文件扩展名(不含点),如"txt"、"png"
|
||||||
|
*/
|
||||||
|
public static String getFileExtension(String fileName) {
|
||||||
|
int dotIndex = fileName.lastIndexOf('.');
|
||||||
|
return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建快捷方式(.url文件内容)
|
||||||
|
* 功能:生成Internet快捷方式文件内容
|
||||||
|
* @param name 快捷方式名称
|
||||||
|
* @param url 目标URL地址
|
||||||
|
* @param icon 图标路径(可选)
|
||||||
|
* @return 包含.url文件内容的输入流
|
||||||
|
*/
|
||||||
|
public static InputStream createInternetShortcut(String name, String url, String icon) {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
try {
|
||||||
|
// 按照Windows快捷方式格式写入内容
|
||||||
|
sw.write("[InternetShortcut]\n");
|
||||||
|
sw.write("URL=" + url + "\n");
|
||||||
|
if (oConvertUtils.isNotEmpty(icon)) {
|
||||||
|
sw.write("IconFile=" + icon + "\n");
|
||||||
|
}
|
||||||
|
// 将字符串内容转换为输入流
|
||||||
|
return new ByteArrayInputStream(sw.toString().getBytes(StandardCharsets.UTF_8));
|
||||||
|
} finally {
|
||||||
|
IoUtil.close(sw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 从URL中提取文件名
|
||||||
|
* 功能:从HTTP URL或本地路径中提取纯文件名
|
||||||
|
* @param fileUrl 文件URL
|
||||||
|
* @return 文件名(不含路径)
|
||||||
|
*/
|
||||||
|
public static String getFileNameFromUrl(String fileUrl) {
|
||||||
|
try {
|
||||||
|
// 处理HTTP URL:从路径部分提取文件名
|
||||||
|
if (fileUrl.startsWith(CommonConstant.STR_HTTP)) {
|
||||||
|
URL url = new URL(fileUrl);
|
||||||
|
String path = url.getPath();
|
||||||
|
return path.substring(path.lastIndexOf('/') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理本地文件路径:从文件路径提取文件名
|
||||||
|
return fileUrl.substring(fileUrl.lastIndexOf(File.separator) + 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 如果解析失败,使用时间戳作为文件名
|
||||||
|
return "file_" + System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 生成ZIP中的文件名
|
||||||
|
* 功能:避免文件名冲突,为多个文件添加序号
|
||||||
|
* @param fileUrl 文件URL(用于提取原始文件名)
|
||||||
|
* @param index 文件序号(从0开始)
|
||||||
|
* @param total 文件总数
|
||||||
|
* @return 处理后的文件名(带序号)
|
||||||
|
*/
|
||||||
|
public static String generateFileName(String fileUrl, int index, int total) {
|
||||||
|
// 从URL中提取原始文件名
|
||||||
|
String originalFileName = getFileNameFromUrl(fileUrl);
|
||||||
|
|
||||||
|
// 如果只有一个文件,直接使用原始文件名
|
||||||
|
if (total == 1) {
|
||||||
|
return originalFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多个文件时,使用序号+原始文件名
|
||||||
|
String extension = getFileExtension(originalFileName);
|
||||||
|
String nameWithoutExtension = originalFileName.replace("." + extension, "");
|
||||||
|
|
||||||
|
return String.format("%s_%d.%s", nameWithoutExtension, index + 1, extension);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.jeecg.common.util;
|
|||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
@ -16,6 +17,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
|
@Lazy(false)
|
||||||
public class PmsUtil {
|
public class PmsUtil {
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -221,6 +221,63 @@ public class RestUtil {
|
|||||||
return RT.exchange(url, method, request, responseType);
|
return RT.exchange(url, method, request, responseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送请求(支持自定义超时时间)
|
||||||
|
*
|
||||||
|
* @param url 请求地址
|
||||||
|
* @param method 请求方式
|
||||||
|
* @param headers 请求头 可空
|
||||||
|
* @param variables 请求url参数 可空
|
||||||
|
* @param params 请求body参数 可空
|
||||||
|
* @param responseType 返回类型
|
||||||
|
* @param timeout 超时时间(毫秒),如果为0或负数则使用默认超时
|
||||||
|
* @return ResponseEntity<responseType>
|
||||||
|
*/
|
||||||
|
public static <T> ResponseEntity<T> request(String url, HttpMethod method, HttpHeaders headers,
|
||||||
|
JSONObject variables, Object params, Class<T> responseType, int timeout) {
|
||||||
|
log.info(" RestUtil --- request --- url = "+ url + ", timeout = " + timeout);
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(url)) {
|
||||||
|
throw new RuntimeException("url 不能为空");
|
||||||
|
}
|
||||||
|
if (method == null) {
|
||||||
|
throw new RuntimeException("method 不能为空");
|
||||||
|
}
|
||||||
|
if (headers == null) {
|
||||||
|
headers = new HttpHeaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建自定义RestTemplate(如果需要设置超时)
|
||||||
|
RestTemplate restTemplate = RT;
|
||||||
|
if (timeout > 0) {
|
||||||
|
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||||
|
requestFactory.setConnectTimeout(timeout);
|
||||||
|
requestFactory.setReadTimeout(timeout);
|
||||||
|
restTemplate = new RestTemplate(requestFactory);
|
||||||
|
// 解决乱码问题
|
||||||
|
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求体
|
||||||
|
String body = "";
|
||||||
|
if (params != null) {
|
||||||
|
if (params instanceof JSONObject) {
|
||||||
|
body = ((JSONObject) params).toJSONString();
|
||||||
|
} else {
|
||||||
|
body = params.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拼接 url 参数
|
||||||
|
if (variables != null && !variables.isEmpty()) {
|
||||||
|
url += ("?" + asUrlVariables(variables));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
HttpEntity<String> request = new HttpEntity<>(body, headers);
|
||||||
|
return restTemplate.exchange(url, method, request, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取JSON请求头
|
* 获取JSON请求头
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
package org.jeecg.common.util;
|
||||||
|
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.mgt.SecurityManager;
|
||||||
|
import org.apache.shiro.subject.Subject;
|
||||||
|
import org.apache.shiro.util.ThreadContext;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @date 2025-09-04
|
||||||
|
* @author scott
|
||||||
|
*
|
||||||
|
* @Description: 支持shiro的API,获取当前登录人方法的线程池
|
||||||
|
*/
|
||||||
|
public class ShiroThreadPoolExecutor extends ThreadPoolExecutor {
|
||||||
|
|
||||||
|
public ShiroThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
|
||||||
|
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Runnable command) {
|
||||||
|
Subject subject = SecurityUtils.getSubject();
|
||||||
|
SecurityManager securityManager = SecurityUtils.getSecurityManager();
|
||||||
|
super.execute(() -> {
|
||||||
|
try {
|
||||||
|
ThreadContext.bind(securityManager);
|
||||||
|
ThreadContext.bind(subject);
|
||||||
|
command.run();
|
||||||
|
} finally {
|
||||||
|
ThreadContext.unbindSubject();
|
||||||
|
ThreadContext.unbindSecurityManager();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -65,6 +65,10 @@ public class TokenUtils {
|
|||||||
if (tenantId == null) {
|
if (tenantId == null) {
|
||||||
tenantId = oConvertUtils.getString(request.getHeader(CommonConstant.TENANT_ID));
|
tenantId = oConvertUtils.getString(request.getHeader(CommonConstant.TENANT_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oConvertUtils.isNotEmpty(tenantId) && "undefined".equals(tenantId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return tenantId;
|
return tenantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -474,6 +474,23 @@ public class oConvertUtils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断字符串是否为JSON格式
|
||||||
|
* @param str
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isJson(String str) {
|
||||||
|
if (str == null || str.trim().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
com.alibaba.fastjson.JSON.parse(str);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Map对象
|
* 获取Map对象
|
||||||
*/
|
*/
|
||||||
@ -1132,7 +1149,15 @@ public class oConvertUtils {
|
|||||||
* @date 2020/9/12 15:50
|
* @date 2020/9/12 15:50
|
||||||
*/
|
*/
|
||||||
public static <T> boolean isIn(T obj, T... objs) {
|
public static <T> boolean isIn(T obj, T... objs) {
|
||||||
return isIn(obj, objs);
|
if (isEmpty(objs)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (T obj1 : objs) {
|
||||||
|
if (isEqual(obj, obj1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -3,13 +3,14 @@ package org.jeecg.config;
|
|||||||
import org.jeecgframework.core.util.ApplicationContextUtil;
|
import org.jeecgframework.core.util.ApplicationContextUtil;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: Scott
|
* @Author: Scott
|
||||||
* @Date: 2018/2/7
|
* @Date: 2018/2/7
|
||||||
* @description: autopoi 配置类
|
* @description: autopoi 配置类
|
||||||
*/
|
*/
|
||||||
|
@Lazy(false)
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AutoPoiConfig {
|
public class AutoPoiConfig {
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
* @Version:1.0
|
* @Version:1.0
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@Lazy(false)
|
||||||
@Service
|
@Service
|
||||||
public class AutoPoiDictConfig implements AutoPoiDictServiceI {
|
public class AutoPoiDictConfig implements AutoPoiDictServiceI {
|
||||||
final static String EXCEL_SPLIT_TAG = "_";
|
final static String EXCEL_SPLIT_TAG = "_";
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
package org.jeecg.config;
|
||||||
|
|
||||||
|
import org.jeecg.config.vo.GaoDeApi;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高德账号配置
|
||||||
|
*/
|
||||||
|
@Lazy(false)
|
||||||
|
@Configuration("jeecgGaodeBaseConfig")
|
||||||
|
@ConfigurationProperties(prefix = "jeecg.jmreport")
|
||||||
|
public class JeecgGaodeBaseConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高德开放API配置
|
||||||
|
*/
|
||||||
|
private GaoDeApi gaoDeApi;
|
||||||
|
|
||||||
|
public GaoDeApi getGaoDeApi() {
|
||||||
|
return gaoDeApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGaoDeApi(GaoDeApi gaoDeApi) {
|
||||||
|
this.gaoDeApi = gaoDeApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,12 +2,14 @@ package org.jeecg.config;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置静态参数初始化
|
* 设置静态参数初始化
|
||||||
* @author: jeecg-boot
|
* @author: jeecg-boot
|
||||||
*/
|
*/
|
||||||
|
@Lazy(false)
|
||||||
@Component
|
@Component
|
||||||
@Data
|
@Data
|
||||||
public class StaticConfig {
|
public class StaticConfig {
|
||||||
|
|||||||
@ -88,7 +88,7 @@ public class Swagger3Config implements WebMvcConfigurer {
|
|||||||
return new OpenAPI()
|
return new OpenAPI()
|
||||||
.info(new Info()
|
.info(new Info()
|
||||||
.title("JeecgBoot 后台服务API接口文档")
|
.title("JeecgBoot 后台服务API接口文档")
|
||||||
.version("3.8.2")
|
.version("3.8.3")
|
||||||
.contact(new Contact().name("北京国炬信息技术有限公司").url("www.jeccg.com").email("jeecgos@163.com"))
|
.contact(new Contact().name("北京国炬信息技术有限公司").url("www.jeccg.com").email("jeecgos@163.com"))
|
||||||
.description( "后台API接口")
|
.description( "后台API接口")
|
||||||
.termsOfService("NO terms of service")
|
.termsOfService("NO terms of service")
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
package org.jeecg.config.mybatis;
|
package org.jeecg.config.mybatis;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.baomidou.mybatisplus.annotation.DbType;
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
|
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.zhyd.oauth.log.Log;
|
import me.zhyd.oauth.log.Log;
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
import net.sf.jsqlparser.expression.LongValue;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.TenantConstant;
|
import org.jeecg.common.constant.TenantConstant;
|
||||||
@ -22,14 +24,10 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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;
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单数据源配置(jeecg.datasource.open = false时生效)
|
* 单数据源配置(jeecg.datasource.open = false时生效)
|
||||||
|
|||||||
@ -8,11 +8,13 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minio文件上传配置文件
|
* Minio文件上传配置文件
|
||||||
* @author: jeecg-boot
|
* @author: jeecg-boot
|
||||||
*/
|
*/
|
||||||
|
@Lazy(false)
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnProperty(prefix = "jeecg.minio", name = "minio_url")
|
@ConditionalOnProperty(prefix = "jeecg.minio", name = "minio_url")
|
||||||
|
|||||||
@ -5,11 +5,13 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 云存储 配置
|
* 云存储 配置
|
||||||
* @author: jeecg-boot
|
* @author: jeecg-boot
|
||||||
*/
|
*/
|
||||||
|
@Lazy(false)
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnProperty(prefix = "jeecg.oss", name = "endpoint")
|
@ConditionalOnProperty(prefix = "jeecg.oss", name = "endpoint")
|
||||||
public class OssConfiguration {
|
public class OssConfiguration {
|
||||||
|
|||||||
@ -126,6 +126,7 @@ public class ShiroConfig {
|
|||||||
filterChainDefinitionMap.put("/**/*.ttf", "anon");
|
filterChainDefinitionMap.put("/**/*.ttf", "anon");
|
||||||
filterChainDefinitionMap.put("/**/*.woff", "anon");
|
filterChainDefinitionMap.put("/**/*.woff", "anon");
|
||||||
filterChainDefinitionMap.put("/**/*.woff2", "anon");
|
filterChainDefinitionMap.put("/**/*.woff2", "anon");
|
||||||
|
|
||||||
filterChainDefinitionMap.put("/**/*.glb", "anon");
|
filterChainDefinitionMap.put("/**/*.glb", "anon");
|
||||||
filterChainDefinitionMap.put("/**/*.wasm", "anon");
|
filterChainDefinitionMap.put("/**/*.wasm", "anon");
|
||||||
//update-end--Author:scott Date:20221116 for:排除静态资源后缀
|
//update-end--Author:scott Date:20221116 for:排除静态资源后缀
|
||||||
@ -177,6 +178,8 @@ public class ShiroConfig {
|
|||||||
filterChainDefinitionMap.put("/sys/version/app3version", "anon");
|
filterChainDefinitionMap.put("/sys/version/app3version", "anon");
|
||||||
//仪表盘(按钮通信)
|
//仪表盘(按钮通信)
|
||||||
filterChainDefinitionMap.put("/dragChannelSocket/**","anon");
|
filterChainDefinitionMap.put("/dragChannelSocket/**","anon");
|
||||||
|
//App vue3版本查询版本接口
|
||||||
|
filterChainDefinitionMap.put("/sys/version/app3version", "anon");
|
||||||
|
|
||||||
//性能监控——安全隐患泄露TOEKN(durid连接池也有)
|
//性能监控——安全隐患泄露TOEKN(durid连接池也有)
|
||||||
//filterChainDefinitionMap.put("/actuator/**", "anon");
|
//filterChainDefinitionMap.put("/actuator/**", "anon");
|
||||||
@ -228,6 +231,7 @@ public class ShiroConfig {
|
|||||||
registration.addUrlPatterns("/airag/chat/send");
|
registration.addUrlPatterns("/airag/chat/send");
|
||||||
registration.addUrlPatterns("/airag/app/debug");
|
registration.addUrlPatterns("/airag/app/debug");
|
||||||
registration.addUrlPatterns("/airag/app/prompt/generate");
|
registration.addUrlPatterns("/airag/app/prompt/generate");
|
||||||
|
registration.addUrlPatterns("/airag/chat/receive/**");
|
||||||
//支持异步
|
//支持异步
|
||||||
registration.setAsyncSupported(true);
|
registration.setAsyncSupported(true);
|
||||||
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
|
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
|
||||||
|
|||||||
@ -106,8 +106,8 @@ public class ShiroRealm extends AuthorizingRealm {
|
|||||||
try {
|
try {
|
||||||
loginUser = this.checkUserTokenIsEffect(token);
|
loginUser = this.checkUserTokenIsEffect(token);
|
||||||
} catch (AuthenticationException e) {
|
} catch (AuthenticationException e) {
|
||||||
|
log.error("—————校验 check token 失败——————————"+ e.getMessage(), e);
|
||||||
JwtUtil.responseError(SpringContextUtils.getHttpServletResponse(),401,e.getMessage());
|
JwtUtil.responseError(SpringContextUtils.getHttpServletResponse(),401,e.getMessage());
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new SimpleAuthenticationInfo(loginUser, token, getName());
|
return new SimpleAuthenticationInfo(loginUser, token, getName());
|
||||||
@ -122,7 +122,7 @@ public class ShiroRealm extends AuthorizingRealm {
|
|||||||
// 解密获得username,用于和数据库进行对比
|
// 解密获得username,用于和数据库进行对比
|
||||||
String username = JwtUtil.getUsername(token);
|
String username = JwtUtil.getUsername(token);
|
||||||
if (username == null) {
|
if (username == null) {
|
||||||
throw new AuthenticationException("token非法无效!");
|
throw new AuthenticationException("Token非法无效!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询用户信息
|
// 查询用户信息
|
||||||
|
|||||||
@ -56,7 +56,7 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
|
|||||||
executeLogin(request, response);
|
executeLogin(request, response);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
JwtUtil.responseError(response,401,CommonConstant.TOKEN_IS_INVALID_MSG);
|
JwtUtil.responseError((HttpServletResponse)response,401,CommonConstant.TOKEN_IS_INVALID_MSG);
|
||||||
return false;
|
return false;
|
||||||
//throw new AuthenticationException("Token失效,请重新登录", e);
|
//throw new AuthenticationException("Token失效,请重新登录", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,7 +64,7 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
|
|||||||
*/
|
*/
|
||||||
@Operation(summary = "获取Demo数据列表")
|
@Operation(summary = "获取Demo数据列表")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
@PermissionData(pageComponent = "jeecg/JeecgDemoList")
|
@PermissionData(pageComponent = "system/examples/demo/index")
|
||||||
public Result<?> list(JeecgDemo jeecgDemo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
public Result<?> list(JeecgDemo jeecgDemo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||||
HttpServletRequest req) {
|
HttpServletRequest req) {
|
||||||
QueryWrapper<JeecgDemo> queryWrapper = QueryGenerator.initQueryWrapper(jeecgDemo, req.getParameterMap());
|
QueryWrapper<JeecgDemo> queryWrapper = QueryGenerator.initQueryWrapper(jeecgDemo, req.getParameterMap());
|
||||||
|
|||||||
@ -409,4 +409,30 @@ public class DlMockController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取车辆最后一个位置
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("/findLatestCarLngLat")
|
||||||
|
public List findLatestCarLngLat() {
|
||||||
|
// 模拟JSON数据路径
|
||||||
|
String path = "classpath:org/jeecg/modules/dlglong/json/CarLngLat.json";
|
||||||
|
// 读取JSON数据
|
||||||
|
return readJsonData(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取车辆最后一个位置
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("/findCarTrace")
|
||||||
|
public List findCarTrace() {
|
||||||
|
// 模拟JSON数据路径
|
||||||
|
String path = "classpath:org/jeecg/modules/dlglong/json/CarTrace.json";
|
||||||
|
// 读取JSON数据
|
||||||
|
return readJsonData(path);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "6891ba44421aa907bcb7390c",
|
||||||
|
"alarm": "0",
|
||||||
|
"altitude": "13",
|
||||||
|
"direction": "0",
|
||||||
|
"latitude": "38.918739",
|
||||||
|
"longitude": "117.758737",
|
||||||
|
"speed": "11",
|
||||||
|
"status": "4980739",
|
||||||
|
"timestamp": "2025-08-05T16:01:07",
|
||||||
|
"imei": "18441136860"
|
||||||
|
}
|
||||||
|
]
|
||||||
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>jeecg-system-api</artifactId>
|
<artifactId>jeecg-system-api</artifactId>
|
||||||
<groupId>org.jeecgframework.boot</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<version>3.8.2</version>
|
<version>3.8.3</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import lombok.experimental.Accessors;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接口表
|
* 接口表
|
||||||
|
|||||||
@ -322,7 +322,7 @@ public class SysAnnouncementController {
|
|||||||
try {
|
try {
|
||||||
// 同步企业微信、钉钉的消息通知
|
// 同步企业微信、钉钉的消息通知
|
||||||
Response<String> dtResponse = dingtalkService.sendActionCardMessage(sysAnnouncement, null, true);
|
Response<String> dtResponse = dingtalkService.sendActionCardMessage(sysAnnouncement, null, true);
|
||||||
wechatEnterpriseService.sendTextCardMessage(sysAnnouncement, true);
|
wechatEnterpriseService.sendTextCardMessage(sysAnnouncement, null,true);
|
||||||
|
|
||||||
if (dtResponse != null && dtResponse.isSuccess()) {
|
if (dtResponse != null && dtResponse.isSuccess()) {
|
||||||
String taskId = dtResponse.getResult();
|
String taskId = dtResponse.getResult();
|
||||||
@ -726,6 +726,18 @@ public class SysAnnouncementController {
|
|||||||
return Result.ok("公告消息访问次数+1次");
|
return Result.ok("公告消息访问次数+1次");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量下载文件
|
||||||
|
* @param id
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
*/
|
||||||
|
@GetMapping("/downLoadFiles")
|
||||||
|
public void downLoadFiles(@RequestParam(name="id") String id,
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response){
|
||||||
|
sysAnnouncementService.downLoadFiles(id,request,response);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 根据异常信息确定友好的错误提示
|
* 根据异常信息确定友好的错误提示
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,14 +1,19 @@
|
|||||||
package org.jeecg.modules.system.service.impl;
|
package org.jeecg.modules.system.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.compress.archivers.zip.Zip64Mode;
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
import org.jeecg.common.util.FileDownloadUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.modules.system.entity.SysAnnouncement;
|
import org.jeecg.modules.system.entity.SysAnnouncement;
|
||||||
import org.jeecg.modules.system.entity.SysAnnouncementSend;
|
import org.jeecg.modules.system.entity.SysAnnouncementSend;
|
||||||
@ -23,6 +28,10 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URLEncoder;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.SynchronousQueue;
|
import java.util.concurrent.SynchronousQueue;
|
||||||
@ -51,6 +60,8 @@ public class SysAnnouncementServiceImpl extends ServiceImpl<SysAnnouncementMappe
|
|||||||
private SysAnnouncementSendMapper sysAnnouncementSendMapper;
|
private SysAnnouncementSendMapper sysAnnouncementSendMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysAnnouncementSendService sysAnnouncementSendService;
|
private ISysAnnouncementSendService sysAnnouncementSendService;
|
||||||
|
@Autowired
|
||||||
|
private JeecgBaseConfig jeecgBaseConfig;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
@ -251,4 +262,64 @@ public class SysAnnouncementServiceImpl extends ServiceImpl<SysAnnouncementMappe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量下载文件
|
||||||
|
* @param id
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void downLoadFiles(String id, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
// 参数校验
|
||||||
|
if (oConvertUtils.isEmpty(id)) {
|
||||||
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文章信息
|
||||||
|
SysAnnouncement sysAnnouncement = this.baseMapper.selectById(id);
|
||||||
|
if (oConvertUtils.isEmpty(sysAnnouncement)) {
|
||||||
|
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//设置HTTP响应头:准备文件下载
|
||||||
|
response.reset();
|
||||||
|
response.setCharacterEncoding("utf-8");
|
||||||
|
response.setContentType("application/force-download");
|
||||||
|
ZipArchiveOutputStream zous = null;
|
||||||
|
try {
|
||||||
|
// 生成ZIP文件名:使用文章标题+时间戳避免重名
|
||||||
|
String title = sysAnnouncement.getTitile() + new Date().getTime();
|
||||||
|
String zipName = URLEncoder.encode( title + ".zip", "UTF-8").replaceAll("\\+", "%20");
|
||||||
|
response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + zipName);
|
||||||
|
// 创建ZIP输出流:直接输出到HTTP响应流
|
||||||
|
zous = new ZipArchiveOutputStream(response.getOutputStream());
|
||||||
|
zous.setUseZip64(Zip64Mode.AsNeeded);// 支持大文件
|
||||||
|
|
||||||
|
// 批量下载文件
|
||||||
|
String[] fileUrls = sysAnnouncement.getFiles().split(",");
|
||||||
|
// 遍历所有文件URL
|
||||||
|
for (int i = 0; i < fileUrls.length; i++) {
|
||||||
|
String fileUrl = fileUrls[i].trim();
|
||||||
|
if (oConvertUtils.isEmpty(fileUrl)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 生成ZIP内文件名:避免重名,添加序号
|
||||||
|
String fileName = FileDownloadUtils.generateFileName(fileUrl, i, fileUrls.length);
|
||||||
|
String uploadUrl = jeecgBaseConfig.getPath().getUpload();
|
||||||
|
// 下载单个文件并添加到ZIP
|
||||||
|
FileDownloadUtils.downLoadSingleFile(fileUrl,fileName,uploadUrl, zous);
|
||||||
|
}
|
||||||
|
// 完成ZIP写入
|
||||||
|
zous.finish();
|
||||||
|
// 刷新缓冲区确保数据发送
|
||||||
|
response.flushBuffer();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("文件下载失败"+e.getMessage(), e);
|
||||||
|
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
|
} finally {
|
||||||
|
// 确保流关闭,防止资源泄漏
|
||||||
|
IoUtil.close(zous);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,19 +3,21 @@ package org.jeecg.modules.openapi.test;
|
|||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.client.methods.*;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import java.security.MessageDigest;
|
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
|
||||||
public class SampleOpenApiTest {
|
public class SampleOpenApiTest {
|
||||||
private final String base_url = "http://localhost:8080/jeecg-boot";
|
private final String base_url = "http://localhost:8080/jeecg-boot";
|
||||||
private final String appKey = "ak-pFjyNHWRsJEFWlu6";
|
private final String appKey = "ak-pFjyNHWRsJEFWlu6";
|
||||||
private final String searchKey = "4hV5dBrZtmGAtPdbA5yseaeKRYNpzGsS";
|
private final String searchKey = "4hV5dBrZtmGAtPdbA5yseaeKRYNpzGsS";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
// 根据部门ID查询用户
|
// 根据部门ID查询用户
|
||||||
|
|||||||
Reference in New Issue
Block a user