mirror of
https://github.com/jeecgboot/jeecg-boot.git
synced 2025-09-09 09:10:19 +00:00
jeecgboot3.4.2版本发布
This commit is contained in:
@@ -146,11 +146,6 @@
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
</exclusion>
|
||||
<!-- [issues/3596] 解决启动报错:Cannot resolve com.sun:tools:1.8.0 -->
|
||||
<exclusion>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
@@ -187,11 +182,6 @@
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里云短信 -->
|
||||
<dependency>
|
||||
|
@@ -0,0 +1,36 @@
|
||||
package org.jeecg.common.api.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author taoYan
|
||||
* @Date 2022/7/26 14:44
|
||||
**/
|
||||
@Data
|
||||
public class DataLogDTO {
|
||||
|
||||
private String tableName;
|
||||
|
||||
private String dataId;
|
||||
|
||||
private String content;
|
||||
|
||||
private String type;
|
||||
|
||||
public DataLogDTO(){
|
||||
|
||||
}
|
||||
|
||||
public DataLogDTO(String tableName, String dataId, String content, String type) {
|
||||
this.tableName = tableName;
|
||||
this.dataId = dataId;
|
||||
this.content = content;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public DataLogDTO(String tableName, String dataId, String type) {
|
||||
this.tableName = tableName;
|
||||
this.dataId = dataId;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@@ -6,8 +6,10 @@ import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 带业务参数的消息
|
||||
* @author: jeecg-boot
|
||||
*/
|
||||
*
|
||||
* @author: taoyan
|
||||
* @date: 2022/8/17
|
||||
*/
|
||||
@Data
|
||||
public class BusMessageDTO extends MessageDTO implements Serializable {
|
||||
|
||||
|
@@ -12,9 +12,8 @@ import java.util.Map;
|
||||
*/
|
||||
@Data
|
||||
public class MessageDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5690444483968058442L;
|
||||
|
||||
|
||||
/**
|
||||
* 发送人(用户登录账户)
|
||||
*/
|
||||
@@ -45,9 +44,36 @@ public class MessageDTO implements Serializable {
|
||||
*/
|
||||
protected String category;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
//update-begin---author:taoyan ---date:20220705 for:支持自定义推送类型,邮件、钉钉、企业微信、系统消息-----------
|
||||
|
||||
/**
|
||||
* 模板消息对应的模板编码
|
||||
*/
|
||||
protected String templateCode;
|
||||
/**
|
||||
* 消息类型:org.jeecg.common.constant.enums.MessageTypeEnum
|
||||
* XT("system", "系统消息")
|
||||
* YJ("email", "邮件消息")
|
||||
* DD("dingtalk", "钉钉消息")
|
||||
* QYWX("wechat_enterprise", "企业微信")
|
||||
*/
|
||||
protected String type;
|
||||
|
||||
/**
|
||||
* 是否发送Markdown格式的消息
|
||||
*/
|
||||
protected boolean isMarkdown;
|
||||
|
||||
/**
|
||||
* 解析模板内容 对应的数据
|
||||
*/
|
||||
protected Map<String, Object> data;
|
||||
//update-end---author:taoyan ---date::20220705 for:支持自定义推送类型,邮件、钉钉、企业微信、系统消息-----------
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
|
||||
public MessageDTO(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,18 +99,11 @@ public class MessageDTO implements Serializable {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板消息对应的模板编码
|
||||
*/
|
||||
protected String templateCode;
|
||||
/**
|
||||
* 消息类型:org.jeecg.common.constant.enums.MessageTypeEnum
|
||||
*/
|
||||
protected String type;
|
||||
|
||||
/**
|
||||
* 解析模板内容 对应的数据
|
||||
*/
|
||||
protected Map<String, Object> data;
|
||||
public boolean isMarkdown() {
|
||||
return this.isMarkdown;
|
||||
}
|
||||
|
||||
public void setIsMarkdown(boolean isMarkdown) {
|
||||
this.isMarkdown = isMarkdown;
|
||||
}
|
||||
}
|
||||
|
@@ -108,7 +108,7 @@ public class DictAspect {
|
||||
return result;
|
||||
}
|
||||
|
||||
log.info(" __ 进入字典翻译切面 DictAspect —— " );
|
||||
log.debug(" __ 进入字典翻译切面 DictAspect —— " );
|
||||
//update-end--Author:zyf -- Date:20220606 ----for:【VUEN-1230】 判断是否含有字典注解,没有注解返回-----
|
||||
for (Object record : records) {
|
||||
String json="{}";
|
||||
@@ -274,10 +274,10 @@ public class DictAspect {
|
||||
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);
|
||||
log.debug("translateDictFromTableByKeys.dictCode:" + dictCode);
|
||||
log.debug("translateDictFromTableByKeys.values:" + values);
|
||||
List<DictModel> texts = commonApi.translateDictFromTableByKeys(table, text, code, values);
|
||||
log.info("translateDictFromTableByKeys.result:" + texts);
|
||||
log.debug("translateDictFromTableByKeys.result:" + texts);
|
||||
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
|
||||
list.addAll(texts);
|
||||
|
||||
@@ -303,10 +303,10 @@ public class DictAspect {
|
||||
List<String> 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);
|
||||
log.debug("translateManyDict.dictCodes:" + dictCodes);
|
||||
log.debug("translateManyDict.values:" + values);
|
||||
Map<String, List<DictModel>> manyDict = commonApi.translateManyDict(dictCodes, values);
|
||||
log.info("translateManyDict.result:" + manyDict);
|
||||
log.debug("translateManyDict.result:" + manyDict);
|
||||
for (String dictCode : manyDict.keySet()) {
|
||||
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
|
||||
List<DictModel> newList = manyDict.get(dictCode);
|
||||
@@ -374,7 +374,7 @@ public class DictAspect {
|
||||
}
|
||||
//update-begin--Author:scott -- Date:20210531 ----for: !56 优化微服务应用下存在表字段需要字典翻译时加载缓慢问题-----
|
||||
if (!StringUtils.isEmpty(table)){
|
||||
log.info("--DictAspect------dicTable="+ table+" ,dicText= "+text+" ,dicCode="+code);
|
||||
log.debug("--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)){
|
||||
try {
|
||||
|
@@ -261,7 +261,7 @@ public interface CommonConstant {
|
||||
/**
|
||||
* 在线聊天 图片文件保存路径
|
||||
*/
|
||||
String IM_UPLOAD_CUSTOM_PATH = "imfile";
|
||||
String IM_UPLOAD_CUSTOM_PATH = "biz/user_imgs";
|
||||
/**
|
||||
* 在线聊天 用户状态
|
||||
*/
|
||||
@@ -406,4 +406,23 @@ public interface CommonConstant {
|
||||
* 模板消息中 跳转地址的对应的key
|
||||
*/
|
||||
String MSG_HREF_URL = "url";
|
||||
|
||||
/**
|
||||
* sys_data_log表的类型 用于区别评论区域的日志数据
|
||||
*/
|
||||
String DATA_LOG_TYPE_COMMENT = "comment";
|
||||
|
||||
/**
|
||||
* sys_data_log表的类型 老的数据比较 类型都设置为json
|
||||
*/
|
||||
String DATA_LOG_TYPE_JSON = "json";
|
||||
|
||||
/** 消息模板:markdown */
|
||||
String MSG_TEMPLATE_TYPE_MD = "5";
|
||||
|
||||
/**
|
||||
* 短信验证码redis-key的前缀
|
||||
*/
|
||||
String PHONE_REDIS_KEY_PRE = "phone_msg";
|
||||
|
||||
}
|
||||
|
@@ -30,6 +30,8 @@ public interface CommonSendStatus {
|
||||
|
||||
/**流程催办——系统通知消息模板*/
|
||||
public static final String TZMB_BPM_CUIBAN = "bpm_cuiban";
|
||||
/**流程催办——邮件通知消息模板*/
|
||||
public static final String TZMB_BPM_CUIBAN_EMAIL = "bpm_cuiban_email";
|
||||
/**标准模板—系统消息通知*/
|
||||
public static final String TZMB_SYS_TS_NOTE = "sys_ts_note";
|
||||
/**流程超时提醒——系统通知消息模板*/
|
||||
|
@@ -30,7 +30,7 @@ public interface ServiceNameConstants {
|
||||
*/
|
||||
String SERVICE_SYSTEM = "jeecg-system";
|
||||
/**
|
||||
* 微服务名:Demo模块
|
||||
* 微服务名: demo模块
|
||||
*/
|
||||
String SERVICE_DEMO = "jeecg-demo";
|
||||
|
||||
|
@@ -0,0 +1,22 @@
|
||||
package org.jeecg.common.constant;
|
||||
|
||||
/**
|
||||
* @Description: TenantConstant
|
||||
* @author: scott
|
||||
* @date: 2022年08月29日 15:29
|
||||
*/
|
||||
public interface TenantConstant {
|
||||
|
||||
/**
|
||||
* 应用ID——表字段
|
||||
*/
|
||||
String DB_FIELD_LOW_APP_ID = "low_app_id";
|
||||
/**
|
||||
* 应用ID——实体字段
|
||||
*/
|
||||
String FIELD_LOW_APP_ID = "lowAppId";
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
String TENANT_ID = "tenantId";
|
||||
}
|
@@ -2,8 +2,6 @@ package org.jeecg.common.constant;
|
||||
|
||||
/**
|
||||
* VXESocket 常量
|
||||
*
|
||||
* update: 【类名改了大小写】 date: 2022-04-18
|
||||
* @author: jeecg-boot
|
||||
*/
|
||||
public class VxeSocketConst {
|
||||
|
@@ -28,6 +28,11 @@ public class WebsocketConst {
|
||||
*/
|
||||
public static final String MSG_USER_ID = "userId";
|
||||
|
||||
/**
|
||||
* 消息json key:chat
|
||||
*/
|
||||
public static final String MSG_CHAT = "chat";
|
||||
|
||||
/**
|
||||
* 消息类型 heartcheck
|
||||
*/
|
||||
|
@@ -0,0 +1,75 @@
|
||||
package org.jeecg.common.constant.enums;
|
||||
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
|
||||
/**
|
||||
* 文件类型
|
||||
*/
|
||||
public enum FileTypeEnum {
|
||||
// 文档类型(folder:文件夹 excel:excel doc:word pp:ppt image:图片 archive:其他文档 video:视频)
|
||||
// FOLDER
|
||||
xls(".xls","excel","excel"),
|
||||
xlsx(".xlsx","excel","excel"),
|
||||
doc(".doc","doc","word"),
|
||||
docx(".docx","doc","word"),
|
||||
ppt(".ppt","pp","ppt"),
|
||||
pptx(".pptx","pp","ppt"),
|
||||
gif(".gif","image","图片"),
|
||||
jpg(".jpg","image","图片"),
|
||||
jpeg(".jpeg","image","图片"),
|
||||
png(".png","image","图片"),
|
||||
txt(".txt","text","文本"),
|
||||
avi(".avi","video","视频"),
|
||||
mov(".mov","video","视频"),
|
||||
rmvb(".rmvb","video","视频"),
|
||||
rm(".rm","video","视频"),
|
||||
flv(".flv","video","视频"),
|
||||
mp4(".mp4","video","视频"),
|
||||
zip(".zip","zip","压缩包"),
|
||||
pdf(".pdf","pdf","pdf");
|
||||
|
||||
private String type;
|
||||
private String value;
|
||||
private String text;
|
||||
private FileTypeEnum(String type,String value,String text){
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.text = text;
|
||||
}
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public static FileTypeEnum getByType(String type){
|
||||
if (oConvertUtils.isEmpty(type)) {
|
||||
return null;
|
||||
}
|
||||
for (FileTypeEnum val : values()) {
|
||||
if (val.getType().equals(type)) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -13,9 +13,13 @@ import java.util.List;
|
||||
@EnumDict("messageType")
|
||||
public enum MessageTypeEnum {
|
||||
|
||||
/** 系统消息 */
|
||||
XT("system", "系统消息"),
|
||||
/** 邮件消息 */
|
||||
YJ("email", "邮件消息"),
|
||||
/** 钉钉消息 */
|
||||
DD("dingtalk", "钉钉消息"),
|
||||
/** 企业微信 */
|
||||
QYWX("wechat_enterprise", "企业微信");
|
||||
|
||||
MessageTypeEnum(String type, String note){
|
||||
@@ -65,4 +69,20 @@ public enum MessageTypeEnum {
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据type获取枚举
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static MessageTypeEnum valueOfType(String type) {
|
||||
for (MessageTypeEnum e : MessageTypeEnum.values()) {
|
||||
if (e.getType().equals(type)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -135,7 +135,7 @@ public class SensitiveInfoUtil {
|
||||
try {
|
||||
result = AesEncryptUtil.desEncrypt(data);
|
||||
} catch (Exception exception) {
|
||||
log.warn("数据解密错误,原数据:"+data);
|
||||
log.debug("数据解密错误,原数据:"+data);
|
||||
}
|
||||
//解决debug模式下,加解密失效导致中文被解密变成空的问题
|
||||
if(oConvertUtils.isEmpty(result) && oConvertUtils.isNotEmpty(data)){
|
||||
|
@@ -246,7 +246,7 @@ public class QueryGenerator {
|
||||
|
||||
//update-begin-author:taoyan date:2022-5-16 for: issues/3676 获取系统用户列表时,使用SQL注入生效
|
||||
//判断column是不是当前实体的
|
||||
log.info("当前字段有:"+ allFields);
|
||||
log.debug("当前字段有:"+ allFields);
|
||||
if (!allColumnExist(column, allFields)) {
|
||||
throw new JeecgBootException("请注意,将要排序的列字段不存在:" + column);
|
||||
}
|
||||
|
@@ -0,0 +1,70 @@
|
||||
package org.jeecg.common.system.vo;
|
||||
|
||||
|
||||
/**
|
||||
* @Description: 系统文件实体类
|
||||
* @author: wangshuai
|
||||
* @date: 2022年08月11日 9:48
|
||||
*/
|
||||
public class SysFilesModel {
|
||||
/**主键id*/
|
||||
private String id;
|
||||
/**文件名称*/
|
||||
private String fileName;
|
||||
/**文件地址*/
|
||||
private String url;
|
||||
/**文档类型(folder:文件夹 excel:excel doc:word pp:ppt image:图片 archive:其他文档 video:视频)*/
|
||||
private String fileType;
|
||||
/**文件上传类型(temp/本地上传(临时文件) manage/知识库)*/
|
||||
private String storeType;
|
||||
/**文件大小(kb)*/
|
||||
private Double fileSize;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getFileType() {
|
||||
return fileType;
|
||||
}
|
||||
|
||||
public void setFileType(String fileType) {
|
||||
this.fileType = fileType;
|
||||
}
|
||||
|
||||
public String getStoreType() {
|
||||
return storeType;
|
||||
}
|
||||
|
||||
public void setStoreType(String storeType) {
|
||||
this.storeType = storeType;
|
||||
}
|
||||
|
||||
public Double getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(Double fileSize) {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
}
|
@@ -127,10 +127,14 @@ public class CommonUtils {
|
||||
*/
|
||||
public static String upload(MultipartFile file, String bizPath, String uploadType) {
|
||||
String url = "";
|
||||
if(CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)){
|
||||
url = MinioUtil.upload(file,bizPath);
|
||||
}else{
|
||||
url = OssBootUtil.upload(file,bizPath);
|
||||
try {
|
||||
if (CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)) {
|
||||
url = MinioUtil.upload(file, bizPath);
|
||||
} else {
|
||||
url = OssBootUtil.upload(file, bizPath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
@@ -186,10 +190,14 @@ public class CommonUtils {
|
||||
*/
|
||||
public static String upload(MultipartFile file, String bizPath, String uploadType, String customBucket) {
|
||||
String url = "";
|
||||
if(CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)){
|
||||
url = MinioUtil.upload(file,bizPath,customBucket);
|
||||
}else{
|
||||
url = OssBootUtil.upload(file,bizPath,customBucket);
|
||||
try {
|
||||
if (CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)) {
|
||||
url = MinioUtil.upload(file, bizPath, customBucket);
|
||||
} else {
|
||||
url = OssBootUtil.upload(file, bizPath, customBucket);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
@@ -340,7 +348,7 @@ public class CommonUtils {
|
||||
}else{
|
||||
baseDomainPath = scheme + "://" + serverName + ":" + serverPort + contextPath ;
|
||||
}
|
||||
log.info("-----Common getBaseUrl----- : " + baseDomainPath);
|
||||
log.debug("-----Common getBaseUrl----- : " + baseDomainPath);
|
||||
return baseDomainPath;
|
||||
}
|
||||
}
|
@@ -671,4 +671,17 @@ public class DateUtils extends PropertyEditorSupport {
|
||||
return calendar.get(Calendar.YEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转成时间
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
public static Date parseDatetime(String str){
|
||||
try {
|
||||
return datetimeFormat.get().parse(str);
|
||||
}catch (Exception e){
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package org.jeecg.common.util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.pegdown.PegDownProcessor;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
/**
|
||||
@@ -29,4 +30,14 @@ public class HTMLUtils {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Markdown解析成Html
|
||||
* @param markdownContent
|
||||
* @return
|
||||
*/
|
||||
public static String parseMarkdown(String markdownContent) {
|
||||
PegDownProcessor pdp = new PegDownProcessor();
|
||||
return pdp.markdownToHtml(markdownContent);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -11,8 +11,6 @@ import org.slf4j.LoggerFactory;
|
||||
* IP地址
|
||||
*
|
||||
* @Author scott
|
||||
*
|
||||
* update: 【类名改了大小写】 date: 2022-04-18
|
||||
* @email jeecgos@163.com
|
||||
* @Date 2019年01月14日
|
||||
*/
|
||||
|
@@ -4,8 +4,6 @@ import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* @Description: 加密工具
|
||||
*
|
||||
* update: 【类名改了大小写】 date: 2022-04-18
|
||||
* @author: jeecg-boot
|
||||
*/
|
||||
public class Md5Util {
|
||||
|
@@ -53,11 +53,16 @@ public class MinioUtil {
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public static String upload(MultipartFile file, String bizPath, String customBucket) {
|
||||
public static String upload(MultipartFile file, String bizPath, String customBucket) throws Exception {
|
||||
String fileUrl = "";
|
||||
//update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击
|
||||
bizPath=StrAttackFilter.filter(bizPath);
|
||||
bizPath = StrAttackFilter.filter(bizPath);
|
||||
//update-end-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击
|
||||
|
||||
//update-begin-author:liusq date:20210809 for: 过滤上传文件类型
|
||||
FileTypeFilter.fileTypeFilter(file);
|
||||
//update-end-author:liusq date:20210809 for: 过滤上传文件类型
|
||||
|
||||
String newBucket = bucketName;
|
||||
if(oConvertUtils.isNotEmpty(customBucket)){
|
||||
newBucket = customBucket;
|
||||
@@ -72,9 +77,6 @@ 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();
|
||||
@@ -111,8 +113,8 @@ public class MinioUtil {
|
||||
* @param bizPath
|
||||
* @return
|
||||
*/
|
||||
public static String upload(MultipartFile file, String bizPath) {
|
||||
return upload(file,bizPath,null);
|
||||
public static String upload(MultipartFile file, String bizPath) throws Exception {
|
||||
return upload(file,bizPath,null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,6 +3,7 @@ package org.jeecg.common.util;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.config.JeecgBaseConfig;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
@@ -46,7 +47,18 @@ public class RestUtil {
|
||||
}
|
||||
|
||||
public static String getBaseUrl() {
|
||||
String basepath = getDomain() + getPath();
|
||||
String basepath = null;
|
||||
try {
|
||||
basepath = getDomain() + getPath();
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getMessage(),e);
|
||||
}
|
||||
|
||||
//定时任务情况下,通过request是获取不到domain的,这种情况下通过配置获取pc后台域名
|
||||
if(oConvertUtils.isEmpty(basepath)){
|
||||
JeecgBaseConfig jeecgBaseConfig = SpringContextUtils.getBean(JeecgBaseConfig.class);
|
||||
basepath = jeecgBaseConfig.getDomainUrl().getPc();
|
||||
}
|
||||
log.info(" RestUtil.getBaseUrl: " + basepath);
|
||||
return basepath;
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ public enum SysAnnmentTypeEnum {
|
||||
*/
|
||||
EMAIL("email", "component", "modules/eoa/email/modals/EoaEmailInForm"),
|
||||
/**
|
||||
* 工作流跳转链接我的办公
|
||||
* 流程跳转到我的任务
|
||||
*/
|
||||
BPM("bpm", "url", "/bpm/task/MyTaskList");
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package org.jeecg.common.util.dynamic.db;
|
||||
|
||||
import freemarker.cache.StringTemplateLoader;
|
||||
import freemarker.core.ParseException;
|
||||
import freemarker.core.TemplateClassResolver;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -53,6 +54,11 @@ public class FreemarkerParseFactory {
|
||||
SQL_CONFIG.setNumberFormat("0.#####################");
|
||||
//classic_compatible设置,解决报空指针错误
|
||||
SQL_CONFIG.setClassicCompatible(true);
|
||||
|
||||
//update-begin-author:taoyan date:2022-8-10 for: freemarker模板注入问题 禁止解析ObjectConstructor,Execute和freemarker.template.utility.JythonRuntime。
|
||||
//https://ackcent.com/in-depth-freemarker-template-injection/
|
||||
SQL_CONFIG.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
|
||||
//update-end-author:taoyan date:2022-8-10 for: freemarker模板注入问题 禁止解析ObjectConstructor,Execute和freemarker.template.utility.JythonRuntime。
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,8 +121,10 @@ public class FreemarkerParseFactory {
|
||||
* @param paras 参数
|
||||
* @return String 模板解析后内容
|
||||
*/
|
||||
public static String parseTemplateContent(String tplContent,
|
||||
Map<String, Object> paras) {
|
||||
public static String parseTemplateContent(String tplContent,Map<String, Object> paras) {
|
||||
return parseTemplateContent(tplContent, paras, false);
|
||||
}
|
||||
public static String parseTemplateContent(String tplContent, Map<String, Object> paras, boolean keepSpace) {
|
||||
try {
|
||||
String sqlUnderline="sql_";
|
||||
StringWriter swriter = new StringWriter();
|
||||
@@ -129,7 +137,7 @@ public class FreemarkerParseFactory {
|
||||
}
|
||||
paras.put(MINI_DAO_FORMAT, new SimpleFormat());
|
||||
mytpl.process(paras, swriter);
|
||||
String sql = getSqlText(swriter.toString());
|
||||
String sql = getSqlText(swriter.toString(), keepSpace);
|
||||
paras.remove(MINI_DAO_FORMAT);
|
||||
return sql;
|
||||
} catch (Exception e) {
|
||||
@@ -145,10 +153,16 @@ public class FreemarkerParseFactory {
|
||||
* 除去无效字段,去掉注释 不然批量处理可能报错 去除无效的等于
|
||||
*/
|
||||
private static String getSqlText(String sql) {
|
||||
return getSqlText(sql, false);
|
||||
}
|
||||
|
||||
private static String getSqlText(String sql, boolean keepSpace) {
|
||||
// 将注释替换成""
|
||||
sql = NOTES_PATTERN.matcher(sql).replaceAll("");
|
||||
sql = sql.replaceAll("\\n", " ").replaceAll("\\t", " ")
|
||||
.replaceAll("\\s{1,}", " ").trim();
|
||||
if (!keepSpace) {
|
||||
sql = sql.replaceAll("\\n", " ").replaceAll("\\t", " ")
|
||||
.replaceAll("\\s{1,}", " ").trim();
|
||||
}
|
||||
// 去掉 最后是 where这样的问题
|
||||
//where空格 "where "
|
||||
String whereSpace = DataBaseConstant.SQL_WHERE+" ";
|
||||
|
@@ -98,7 +98,7 @@ public class FileTypeFilter {
|
||||
String suffix = getFileType(file);
|
||||
for (String type : forbidType) {
|
||||
if (type.contains(suffix)) {
|
||||
throw new Exception("上传失败,文件类型异常:" + suffix);
|
||||
throw new Exception("上传失败,非法文件类型:" + suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -96,7 +96,11 @@ public class OssBootUtil {
|
||||
* @param fileDir 文件保存目录
|
||||
* @return oss 中的相对文件路径
|
||||
*/
|
||||
public static String upload(MultipartFile file, String fileDir,String customBucket) {
|
||||
public static String upload(MultipartFile file, String fileDir,String customBucket) throws Exception {
|
||||
//update-begin-author:liusq date:20210809 for: 过滤上传文件类型
|
||||
FileTypeFilter.fileTypeFilter(file);
|
||||
//update-end-author:liusq date:20210809 for: 过滤上传文件类型
|
||||
|
||||
String filePath = null;
|
||||
initOss(endPoint, accessKeyId, accessKeySecret);
|
||||
StringBuilder fileUrl = new StringBuilder();
|
||||
@@ -114,9 +118,6 @@ 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()
|
||||
@@ -169,7 +170,7 @@ public class OssBootUtil {
|
||||
* @param fileDir
|
||||
* @return
|
||||
*/
|
||||
public static String upload(MultipartFile file, String fileDir) {
|
||||
public static String upload(MultipartFile file, String fileDir) throws Exception {
|
||||
return upload(file, fileDir,null);
|
||||
}
|
||||
|
||||
@@ -235,6 +236,8 @@ public class OssBootUtil {
|
||||
} else {
|
||||
bucketUrl = "https://" + newBucket + "." + endPoint + SymbolConstant.SINGLE_SLASH;
|
||||
}
|
||||
//TODO 暂时不允许删除云存储的文件
|
||||
//initOss(endPoint, accessKeyId, accessKeySecret);
|
||||
url = url.replace(bucketUrl,"");
|
||||
ossClient.deleteObject(newBucket, url);
|
||||
}
|
||||
|
@@ -0,0 +1,46 @@
|
||||
package org.jeecg.common.util.security;
|
||||
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
|
||||
/**
|
||||
* jdbc连接校验
|
||||
* @Author taoYan
|
||||
* @Date 2022/8/10 18:15
|
||||
**/
|
||||
public class JdbcSecurityUtil {
|
||||
|
||||
/**
|
||||
* 连接驱动漏洞 最新版本修复后,可删除相应的key
|
||||
* postgre:authenticationPluginClassName, sslhostnameverifier, socketFactory, sslfactory, sslpasswordcallback
|
||||
* https://github.com/pgjdbc/pgjdbc/security/advisories/GHSA-v7wg-cpwc-24m4
|
||||
*
|
||||
*/
|
||||
public static final String[] notAllowedProps = new String[]{"authenticationPluginClassName", "sslhostnameverifier", "socketFactory", "sslfactory", "sslpasswordcallback"};
|
||||
|
||||
/**
|
||||
* 校验sql是否有特定的key
|
||||
* @param jdbcUrl
|
||||
* @return
|
||||
*/
|
||||
public static void validate(String jdbcUrl){
|
||||
if(oConvertUtils.isEmpty(jdbcUrl)){
|
||||
return;
|
||||
}
|
||||
String urlConcatChar = "?";
|
||||
if(jdbcUrl.indexOf(urlConcatChar)<0){
|
||||
return;
|
||||
}
|
||||
String argString = jdbcUrl.substring(jdbcUrl.indexOf(urlConcatChar)+1);
|
||||
String[] keyAndValues = argString.split("&");
|
||||
for(String temp: keyAndValues){
|
||||
String key = temp.split("=")[0];
|
||||
for(String prop: notAllowedProps){
|
||||
if(prop.equalsIgnoreCase(key)){
|
||||
throw new JeecgBootException("连接地址有安全风险,【"+key+"】");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -23,7 +23,11 @@ public class JeecgBaseConfig {
|
||||
* 需要加强校验的接口清单
|
||||
*/
|
||||
private String signUrls;
|
||||
|
||||
/**
|
||||
* 上传模式
|
||||
* 本地:local\Minio:minio\阿里云:alioss
|
||||
*/
|
||||
private String uploadType;
|
||||
/**
|
||||
* 是否启用安全模式
|
||||
*/
|
||||
@@ -44,6 +48,11 @@ public class JeecgBaseConfig {
|
||||
*/
|
||||
private DomainUrl domainUrl;
|
||||
|
||||
/**
|
||||
* 文件预览
|
||||
*/
|
||||
private String fileViewDomain;
|
||||
|
||||
public Boolean getSafeMode() {
|
||||
return safeMode;
|
||||
}
|
||||
@@ -83,7 +92,6 @@ public class JeecgBaseConfig {
|
||||
public void setDomainUrl(DomainUrl domainUrl) {
|
||||
this.domainUrl = domainUrl;
|
||||
}
|
||||
|
||||
public String getSignUrls() {
|
||||
return signUrls;
|
||||
}
|
||||
@@ -91,4 +99,13 @@ public class JeecgBaseConfig {
|
||||
public void setSignUrls(String signUrls) {
|
||||
this.signUrls = signUrls;
|
||||
}
|
||||
|
||||
|
||||
public String getFileViewDomain() {
|
||||
return fileViewDomain;
|
||||
}
|
||||
|
||||
public void setFileViewDomain(String fileViewDomain) {
|
||||
this.fileViewDomain = fileViewDomain;
|
||||
}
|
||||
}
|
||||
|
@@ -75,8 +75,8 @@ public class Swagger2Config implements WebMvcConfigurer {
|
||||
.paths(PathSelectors.any())
|
||||
.build()
|
||||
.securitySchemes(Collections.singletonList(securityScheme()))
|
||||
.securityContexts(securityContexts());
|
||||
//.globalOperationParameters(setHeaderToken());
|
||||
.securityContexts(securityContexts())
|
||||
.globalOperationParameters(setHeaderToken());
|
||||
}
|
||||
|
||||
/***
|
||||
@@ -109,7 +109,7 @@ public class Swagger2Config implements WebMvcConfigurer {
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
// //大标题
|
||||
.title("Jeecg-Boot 后台服务API接口文档")
|
||||
.title("JeecgBoot 后台服务API接口文档")
|
||||
// 版本号
|
||||
.version("1.0")
|
||||
// .termsOfServiceUrl("NO terms of service")
|
||||
@@ -117,7 +117,6 @@ public class Swagger2Config implements WebMvcConfigurer {
|
||||
.description("后台API接口")
|
||||
// 作者
|
||||
.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();
|
||||
|
@@ -29,6 +29,7 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -45,7 +46,7 @@ import java.util.List;
|
||||
@Configuration
|
||||
public class WebMvcConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
JeecgBaseConfig jeecgBaseConfig;
|
||||
@Value("${spring.resource.static-locations:}")
|
||||
private String staticLocations;
|
||||
|
@@ -30,7 +30,8 @@ public class WebSocketConfig {
|
||||
public FilterRegistrationBean getFilterRegistrationBean(){
|
||||
FilterRegistrationBean bean = new FilterRegistrationBean();
|
||||
bean.setFilter(websocketFilter());
|
||||
bean.addUrlPatterns("/websocket/*", "/eoaSocket/*", "/newsWebsocket/*", "/vxeSocket/*");
|
||||
//TODO 临时注释掉,测试下线上socket总断的问题
|
||||
bean.addUrlPatterns("/websocket/*","/eoaSocket/*", "/newsWebsocket/*", "/vxeSocket/*");
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,7 @@ import org.jeecg.common.api.CommonAPI;
|
||||
import org.jeecg.common.util.RedisUtil;
|
||||
import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.common.util.TokenUtils;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -36,12 +37,13 @@ public class WebsocketFilter implements Filter {
|
||||
HttpServletRequest request = (HttpServletRequest)servletRequest;
|
||||
String token = request.getHeader(TOKEN_KEY);
|
||||
|
||||
log.info("websocket连接 Token安全校验,Path = {},token:{}", request.getRequestURI(), token);
|
||||
log.debug("Websocket连接 Token安全校验,Path = {},token:{}", request.getRequestURI(), token);
|
||||
|
||||
try {
|
||||
TokenUtils.verifyToken(token, commonApi, redisUtil);
|
||||
} catch (Exception exception) {
|
||||
log.error("websocket连接校验失败,{},token:{}", exception.getMessage(), token);
|
||||
//log.error("Websocket连接 Token安全校验失败,IP:{}, Token:{}, Path = {},异常:{}", oConvertUtils.getIpAddrByRequest(request), token, request.getRequestURI(), exception.getMessage());
|
||||
log.debug("Websocket连接 Token安全校验失败,IP:{}, Token:{}, Path = {},异常:{}", oConvertUtils.getIpAddrByRequest(request), token, request.getRequestURI(), exception.getMessage());
|
||||
return;
|
||||
}
|
||||
HttpServletResponse response = (HttpServletResponse)servletResponse;
|
||||
|
@@ -66,7 +66,7 @@ public class ShiroConfig {
|
||||
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
|
||||
|
||||
//支持yml方式,配置拦截排除
|
||||
if(jeecgBaseConfig.getShiro()!=null){
|
||||
if(jeecgBaseConfig!=null && jeecgBaseConfig.getShiro()!=null){
|
||||
String shiroExcludeUrls = jeecgBaseConfig.getShiro().getExcludeUrls();
|
||||
if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){
|
||||
String[] permissionUrl = shiroExcludeUrls.split(",");
|
||||
@@ -109,6 +109,7 @@ public class ShiroConfig {
|
||||
filterChainDefinitionMap.put("/**/*.pdf", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.jpg", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.png", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.gif", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.ico", "anon");
|
||||
|
||||
// update-begin--Author:sunjianlei Date:20190813 for:排除字体格式的后缀
|
||||
|
@@ -2,7 +2,6 @@ package org.jeecg.config.sign.interceptor;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.common.util.PathMatcherUtil;
|
||||
import org.jeecg.common.util.SpringContextHolder;
|
||||
import org.jeecg.config.JeecgBaseConfig;
|
||||
import org.jeecg.config.filter.RequestBodyReserveFilter;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
@@ -12,8 +11,6 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 签名 拦截器配置
|
||||
|
@@ -10,6 +10,7 @@ import org.jeecg.config.JeecgBaseConfig;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.SortedMap;
|
||||
|
||||
/**
|
||||
@@ -54,6 +55,12 @@ public class SignUtil {
|
||||
if(oConvertUtils.isEmpty(signatureSecret) || signatureSecret.contains(curlyBracket)){
|
||||
throw new JeecgBootException("签名密钥 ${jeecg.signatureSecret} 缺少配置 !!");
|
||||
}
|
||||
return DigestUtils.md5DigestAsHex((paramsJsonStr + signatureSecret).getBytes()).toUpperCase();
|
||||
try {
|
||||
//【issues/I484RW】2.4.6部署后,下拉搜索框提示“sign签名检验失败”
|
||||
return DigestUtils.md5DigestAsHex((paramsJsonStr + signatureSecret).getBytes("UTF-8")).toUpperCase();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user