diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/dto/message/MessageDTO.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/dto/message/MessageDTO.java
index 5e68fd7..777c2c4 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/dto/message/MessageDTO.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/dto/message/MessageDTO.java
@@ -4,6 +4,7 @@ import lombok.Data;
 import org.jeecg.common.constant.CommonConstant;
 
 import java.io.Serializable;
+import java.util.Map;
 
 /**
  * 普通消息
@@ -72,4 +73,18 @@ 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;
+
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java
index 292e209..ab2c940 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java
@@ -40,6 +40,8 @@ public class PermissionDataAspect {
     @Autowired
     private CommonAPI commonApi;
 
+    private static final String SPOT_DO = ".do";
+
     @Pointcut("@annotation(org.jeecg.common.aspect.annotation.PermissionData)")
     public void pointCut() {
 
@@ -113,7 +115,7 @@ public class PermissionDataAspect {
             requestPath = requestPath.substring(0, requestPath.indexOf("&"));
         }
         if(requestPath.indexOf(QueryRuleEnum.EQ.getValue())!=-1){
-            if(requestPath.indexOf(CommonConstant.SPOT_DO)!=-1){
+            if(requestPath.indexOf(SPOT_DO)!=-1){
                 requestPath = requestPath.substring(0,requestPath.indexOf(".do")+3);
             }else{
                 requestPath = requestPath.substring(0,requestPath.indexOf("?"));
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/DynamicTable.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/DynamicTable.java
new file mode 100644
index 0000000..e377c8f
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/DynamicTable.java
@@ -0,0 +1,20 @@
+package org.jeecg.common.aspect.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 动态table切换
+ *
+ * @author :zyf
+ * @date:2020-04-25
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DynamicTable {
+    /**
+     * 需要动态解析的表名
+     * @return
+     */
+    String value();
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
index 507dd72..a818c67 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
@@ -9,320 +9,321 @@ public interface CommonConstant {
 	/**
 	 * 正常状态
 	 */
-	public static final Integer STATUS_NORMAL = 0;
+	Integer STATUS_NORMAL = 0;
 
 	/**
 	 * 禁用状态
 	 */
-	public static final Integer STATUS_DISABLE = -1;
+	Integer STATUS_DISABLE = -1;
 
 	/**
 	 * 删除标志
 	 */
-	public static final Integer DEL_FLAG_1 = 1;
+	Integer DEL_FLAG_1 = 1;
 
 	/**
 	 * 未删除
 	 */
-	public static final Integer DEL_FLAG_0 = 0;
+	Integer DEL_FLAG_0 = 0;
 
 	/**
 	 * 系统日志类型: 登录
 	 */
-	public static final int LOG_TYPE_1 = 1;
+	int LOG_TYPE_1 = 1;
 	
 	/**
 	 * 系统日志类型: 操作
 	 */
-	public static final int LOG_TYPE_2 = 2;
+	int LOG_TYPE_2 = 2;
 
 	/**
 	 * 操作日志类型: 查询
 	 */
-	public static final int OPERATE_TYPE_1 = 1;
+	int OPERATE_TYPE_1 = 1;
 	
 	/**
 	 * 操作日志类型: 添加
 	 */
-	public static final int OPERATE_TYPE_2 = 2;
+	int OPERATE_TYPE_2 = 2;
 	
 	/**
 	 * 操作日志类型: 更新
 	 */
-	public static final int OPERATE_TYPE_3 = 3;
+	int OPERATE_TYPE_3 = 3;
 	
 	/**
 	 * 操作日志类型: 删除
 	 */
-	public static final int OPERATE_TYPE_4 = 4;
+	int OPERATE_TYPE_4 = 4;
 	
 	/**
 	 * 操作日志类型: 倒入
 	 */
-	public static final int OPERATE_TYPE_5 = 5;
+	int OPERATE_TYPE_5 = 5;
 	
 	/**
 	 * 操作日志类型: 导出
 	 */
-	public static final int OPERATE_TYPE_6 = 6;
+	int OPERATE_TYPE_6 = 6;
 	
 	
 	/** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
-    public static final Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
+    Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
     /** {@code 200 OK} (HTTP/1.0 - RFC 1945) */
-    public static final Integer SC_OK_200 = 200;
+    Integer SC_OK_200 = 200;
     
     /**访问权限认证未通过 510*/
-    public static final Integer SC_JEECG_NO_AUTHZ=510;
+    Integer SC_JEECG_NO_AUTHZ=510;
 
     /** 登录用户Shiro权限缓存KEY前缀 */
     public static String PREFIX_USER_SHIRO_CACHE  = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
     /** 登录用户Token令牌缓存KEY前缀 */
-    public static final String PREFIX_USER_TOKEN  = "prefix_user_token_";
+    String PREFIX_USER_TOKEN  = "prefix_user_token_";
 //    /** Token缓存时间:3600秒即一小时 */
-//    public static final int  TOKEN_EXPIRE_TIME  = 3600;
+//    int  TOKEN_EXPIRE_TIME  = 3600;
 
     /** 登录二维码 */
-    public static final String  LOGIN_QRCODE_PRE  = "QRCODELOGIN:";
-    public static final String  LOGIN_QRCODE  = "LQ:";
+    String  LOGIN_QRCODE_PRE  = "QRCODELOGIN:";
+    String  LOGIN_QRCODE  = "LQ:";
     /** 登录二维码token */
-    public static final String  LOGIN_QRCODE_TOKEN  = "LQT:";
+    String  LOGIN_QRCODE_TOKEN  = "LQT:";
 
 
     /**
      *  0:一级菜单
      */
-    public static final Integer MENU_TYPE_0  = 0;
+    Integer MENU_TYPE_0  = 0;
    /**
     *  1:子菜单 
     */
-    public static final Integer MENU_TYPE_1  = 1;
+    Integer MENU_TYPE_1  = 1;
     /**
      *  2:按钮权限
      */
-    public static final Integer MENU_TYPE_2  = 2;
+    Integer MENU_TYPE_2  = 2;
 
     /**通告对象类型(USER:指定用户,ALL:全体用户)*/
-    public static final String MSG_TYPE_UESR  = "USER";
-    public static final String MSG_TYPE_ALL  = "ALL";
+    String MSG_TYPE_UESR  = "USER";
+    String MSG_TYPE_ALL  = "ALL";
     
     /**发布状态(0未发布,1已发布,2已撤销)*/
-    public static final String NO_SEND  = "0";
-    public static final String HAS_SEND  = "1";
-    public static final String HAS_CANCLE  = "2";
+    String NO_SEND  = "0";
+    String HAS_SEND  = "1";
+    String HAS_CANCLE  = "2";
     
     /**阅读状态(0未读,1已读)*/
-    public static final String HAS_READ_FLAG  = "1";
-    public static final String NO_READ_FLAG  = "0";
+    String HAS_READ_FLAG  = "1";
+    String NO_READ_FLAG  = "0";
     
     /**优先级(L低,M中,H高)*/
-    public static final String PRIORITY_L  = "L";
-    public static final String PRIORITY_M  = "M";
-    public static final String PRIORITY_H  = "H";
+    String PRIORITY_L  = "L";
+    String PRIORITY_M  = "M";
+    String PRIORITY_H  = "H";
     
     /**
      * 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
      */
-    public static final String SMS_TPL_TYPE_0  = "0";
-    public static final String SMS_TPL_TYPE_1  = "1";
-    public static final String SMS_TPL_TYPE_2  = "2";
+    String SMS_TPL_TYPE_0  = "0";
+    String SMS_TPL_TYPE_1  = "1";
+    String SMS_TPL_TYPE_2  = "2";
     
     /**
      * 状态(0无效1有效)
      */
-    public static final String STATUS_0 = "0";
-    public static final String STATUS_1 = "1";
+    String STATUS_0 = "0";
+    String STATUS_1 = "1";
     
     /**
      * 同步工作流引擎1同步0不同步
      */
-    public static final Integer ACT_SYNC_1 = 1;
-    public static final Integer ACT_SYNC_0 = 0;
+    Integer ACT_SYNC_1 = 1;
+    Integer ACT_SYNC_0 = 0;
 
     /**
      * 消息类型1:通知公告2:系统消息
      */
-    public static final String MSG_CATEGORY_1 = "1";
-    public static final String MSG_CATEGORY_2 = "2";
+    String MSG_CATEGORY_1 = "1";
+    String MSG_CATEGORY_2 = "2";
     
     /**
      * 是否配置菜单的数据权限 1是0否
      */
-    public static final Integer RULE_FLAG_0 = 0;
-    public static final Integer RULE_FLAG_1 = 1;
+    Integer RULE_FLAG_0 = 0;
+    Integer RULE_FLAG_1 = 1;
 
     /**
      * 是否用户已被冻结 1正常(解冻) 2冻结
      */
-    public static final Integer USER_UNFREEZE = 1;
-    public static final Integer USER_FREEZE = 2;
+    Integer USER_UNFREEZE = 1;
+    Integer USER_FREEZE = 2;
     
     /**字典翻译文本后缀*/
-    public static final String DICT_TEXT_SUFFIX = "_dictText";
+    String DICT_TEXT_SUFFIX = "_dictText";
 
     /**
      * 表单设计器主表类型
      */
-    public static final Integer DESIGN_FORM_TYPE_MAIN = 1;
+    Integer DESIGN_FORM_TYPE_MAIN = 1;
 
     /**
      * 表单设计器子表表类型
      */
-    public static final Integer DESIGN_FORM_TYPE_SUB = 2;
+    Integer DESIGN_FORM_TYPE_SUB = 2;
 
     /**
      * 表单设计器URL授权通过
      */
-    public static final Integer DESIGN_FORM_URL_STATUS_PASSED = 1;
+    Integer DESIGN_FORM_URL_STATUS_PASSED = 1;
 
     /**
      * 表单设计器URL授权未通过
      */
-    public static final Integer DESIGN_FORM_URL_STATUS_NOT_PASSED = 2;
+    Integer DESIGN_FORM_URL_STATUS_NOT_PASSED = 2;
 
     /**
      * 表单设计器新增 Flag
      */
-    public static final String DESIGN_FORM_URL_TYPE_ADD = "add";
+    String DESIGN_FORM_URL_TYPE_ADD = "add";
     /**
      * 表单设计器修改 Flag
      */
-    public static final String DESIGN_FORM_URL_TYPE_EDIT = "edit";
+    String DESIGN_FORM_URL_TYPE_EDIT = "edit";
     /**
      * 表单设计器详情 Flag
      */
-    public static final String DESIGN_FORM_URL_TYPE_DETAIL = "detail";
+    String DESIGN_FORM_URL_TYPE_DETAIL = "detail";
     /**
      * 表单设计器复用数据 Flag
      */
-    public static final String DESIGN_FORM_URL_TYPE_REUSE = "reuse";
+    String DESIGN_FORM_URL_TYPE_REUSE = "reuse";
     /**
      * 表单设计器编辑 Flag (已弃用)
      */
-    public static final String DESIGN_FORM_URL_TYPE_VIEW = "view";
+    String DESIGN_FORM_URL_TYPE_VIEW = "view";
 
     /**
      * online参数值设置(是:Y, 否:N)
      */
-    public static final String ONLINE_PARAM_VAL_IS_TURE = "Y";
-    public static final String ONLINE_PARAM_VAL_IS_FALSE = "N";
+    String ONLINE_PARAM_VAL_IS_TURE = "Y";
+    String ONLINE_PARAM_VAL_IS_FALSE = "N";
 
     /**
      * 文件上传类型(本地:local,Minio:minio,阿里云:alioss)
      */
-    public static final String UPLOAD_TYPE_LOCAL = "local";
-    public static final String UPLOAD_TYPE_MINIO = "minio";
-    public static final String UPLOAD_TYPE_OSS = "alioss";
+    String UPLOAD_TYPE_LOCAL = "local";
+    String UPLOAD_TYPE_MINIO = "minio";
+    String UPLOAD_TYPE_OSS = "alioss";
 
     /**
      * 文档上传自定义桶名称
      */
-    public static final String UPLOAD_CUSTOM_BUCKET = "eoafile";
+    String UPLOAD_CUSTOM_BUCKET = "eoafile";
     /**
      * 文档上传自定义路径
      */
-    public static final String UPLOAD_CUSTOM_PATH = "eoafile";
+    String UPLOAD_CUSTOM_PATH = "eoafile";
     /**
      * 文件外链接有效天数
      */
-    public static final Integer UPLOAD_EFFECTIVE_DAYS = 1;
+    Integer UPLOAD_EFFECTIVE_DAYS = 1;
 
     /**
      * 员工身份 (1:普通员工  2:上级)
      */
-    public static final Integer USER_IDENTITY_1 = 1;
-    public static final Integer USER_IDENTITY_2 = 2;
+    Integer USER_IDENTITY_1 = 1;
+    Integer USER_IDENTITY_2 = 2;
 
     /** sys_user 表 username 唯一键索引 */
-    public static final String SQL_INDEX_UNIQ_SYS_USER_USERNAME = "uniq_sys_user_username";
+    String SQL_INDEX_UNIQ_SYS_USER_USERNAME = "uniq_sys_user_username";
     /** sys_user 表 work_no 唯一键索引 */
-    public static final String SQL_INDEX_UNIQ_SYS_USER_WORK_NO = "uniq_sys_user_work_no";
+    String SQL_INDEX_UNIQ_SYS_USER_WORK_NO = "uniq_sys_user_work_no";
     /** sys_user 表 phone 唯一键索引 */
-    public static final String SQL_INDEX_UNIQ_SYS_USER_PHONE = "uniq_sys_user_phone";
+    String SQL_INDEX_UNIQ_SYS_USER_PHONE = "uniq_sys_user_phone";
     /** 达梦数据库升提示。违反表[SYS_USER]唯一性约束 */
-    public static final String SQL_INDEX_UNIQ_SYS_USER = "唯一性约束";
+    String SQL_INDEX_UNIQ_SYS_USER = "唯一性约束";
 
     /** sys_user 表 email 唯一键索引 */
-    public static final String SQL_INDEX_UNIQ_SYS_USER_EMAIL = "uniq_sys_user_email";
+    String SQL_INDEX_UNIQ_SYS_USER_EMAIL = "uniq_sys_user_email";
     /** sys_quartz_job 表 job_class_name 唯一键索引 */
-    public static final String SQL_INDEX_UNIQ_JOB_CLASS_NAME = "uniq_job_class_name";
+    String SQL_INDEX_UNIQ_JOB_CLASS_NAME = "uniq_job_class_name";
     /** sys_position 表 code 唯一键索引 */
-    public static final String SQL_INDEX_UNIQ_CODE = "uniq_code";
+    String SQL_INDEX_UNIQ_CODE = "uniq_code";
     /** sys_role 表 code 唯一键索引 */
-    public static final String SQL_INDEX_UNIQ_SYS_ROLE_CODE = "uniq_sys_role_role_code";
+    String SQL_INDEX_UNIQ_SYS_ROLE_CODE = "uniq_sys_role_role_code";
     /** sys_depart 表 code 唯一键索引 */
-    public static final String SQL_INDEX_UNIQ_DEPART_ORG_CODE = "uniq_depart_org_code";
+    String SQL_INDEX_UNIQ_DEPART_ORG_CODE = "uniq_depart_org_code";
     /** sys_category 表 code 唯一键索引 */
-    public static final String SQL_INDEX_UNIQ_CATEGORY_CODE = "idx_sc_code";
+    String SQL_INDEX_UNIQ_CATEGORY_CODE = "idx_sc_code";
     /**
      * 在线聊天 是否为默认分组
      */
-    public static final String IM_DEFAULT_GROUP = "1";
+    String IM_DEFAULT_GROUP = "1";
     /**
      * 在线聊天 图片文件保存路径
      */
-    public static final String IM_UPLOAD_CUSTOM_PATH = "imfile";
+    String IM_UPLOAD_CUSTOM_PATH = "imfile";
     /**
      * 在线聊天 用户状态
      */
-    public static final String IM_STATUS_ONLINE = "online";
+    String IM_STATUS_ONLINE = "online";
 
     /**
      * 在线聊天 SOCKET消息类型
      */
-    public static final String IM_SOCKET_TYPE = "chatMessage";
+    String IM_SOCKET_TYPE = "chatMessage";
 
     /**
      * 在线聊天 是否开启默认添加好友 1是 0否
      */
-    public static final String IM_DEFAULT_ADD_FRIEND = "1";
+    String IM_DEFAULT_ADD_FRIEND = "1";
 
     /**
      * 在线聊天 用户好友缓存前缀
      */
-    public static final String IM_PREFIX_USER_FRIEND_CACHE = "sys:cache:im:im_prefix_user_friend_";
+    String IM_PREFIX_USER_FRIEND_CACHE = "sys:cache:im:im_prefix_user_friend_";
 
     /**
      * 考勤补卡业务状态 (1:同意  2:不同意)
      */
-    public static final String SIGN_PATCH_BIZ_STATUS_1 = "1";
-    public static final String SIGN_PATCH_BIZ_STATUS_2 = "2";
+    String SIGN_PATCH_BIZ_STATUS_1 = "1";
+    String SIGN_PATCH_BIZ_STATUS_2 = "2";
 
     /**
      * 公文文档上传自定义路径
      */
-    public static final String UPLOAD_CUSTOM_PATH_OFFICIAL = "officialdoc";
+    String UPLOAD_CUSTOM_PATH_OFFICIAL = "officialdoc";
      /**
      * 公文文档下载自定义路径
      */
-    public static final String DOWNLOAD_CUSTOM_PATH_OFFICIAL = "officaldown";
+    String DOWNLOAD_CUSTOM_PATH_OFFICIAL = "officaldown";
 
     /**
      * WPS存储值类别(1 code文号 2 text(WPS模板还是公文发文模板))
      */
-    public static final String WPS_TYPE_1="1";
-    public static final String WPS_TYPE_2="2";
+    String WPS_TYPE_1="1";
+    String WPS_TYPE_2="2";
 
 
-    public final static String X_ACCESS_TOKEN = "X-Access-Token";
-    public final static String X_SIGN = "X-Sign";
-    public final static String X_TIMESTAMP = "X-TIMESTAMP";
-    public final static String TOKEN_IS_INVALID_MSG = "Token失效,请重新登录!";
+    String X_ACCESS_TOKEN = "X-Access-Token";
+    String X_SIGN = "X-Sign";
+    String X_TIMESTAMP = "X-TIMESTAMP";
+    String TOKEN_IS_INVALID_MSG = "Token失效,请重新登录!";
+    String X_FORWARDED_SCHEME = "X-Forwarded-Scheme";
 
     /**
      * 多租户 请求头
      */
-    public final static String TENANT_ID = "tenant-id";
+    String TENANT_ID = "tenant-id";
 
     /**
      * 微服务读取配置文件属性 服务地址
      */
-    public final static String CLOUD_SERVER_KEY = "spring.cloud.nacos.discovery.server-addr";
+    String CLOUD_SERVER_KEY = "spring.cloud.nacos.discovery.server-addr";
 
     /**
      * 第三方登录 验证密码/创建用户 都需要设置一个操作码 防止被恶意调用
      */
-    public final static String THIRD_LOGIN_CODE = "third_login_code";
+    String THIRD_LOGIN_CODE = "third_login_code";
 
     /**
      * 第三方APP同步方向:本地 --> 第三方APP
@@ -361,16 +362,43 @@ public interface CommonConstant {
     /**String 类型的空值*/
     String STRING_NULL = "null";
 
-    /**java.util.Date 包*/
-    String JAVA_UTIL_DATE = "java.util.Date";
+    /**前端vue3版本Header参数名*/
+    String VERSION="X-Version";
 
-    /**.do*/
-    String SPOT_DO = ".do";
+    /**存储在线程变量里的动态表名*/
+    String DYNAMIC_TABLE_NAME="DYNAMIC_TABLE_NAME";
+    /**
+     * http:// http协议
+     */
+    String HTTP_PROTOCOL = "http://";
 
+    /**
+     * https:// https协议
+     */
+    String HTTPS_PROTOCOL = "https://";
+    
+    /** 部门表唯一key,id */
+    String DEPART_KEY_ID = "id";
+    /** 部门表唯一key,orgCode */
+    String DEPART_KEY_ORG_CODE = "orgCode";
 
-    /**前端vue版本标识*/
-    String VERSION="X-Version";
+    /**
+     * 发消息 会传递一些信息到map
+     */
+    String NOTICE_MSG_SUMMARY = "NOTICE_MSG_SUMMARY";
 
-    /**前端vue版本*/
-    String VERSION_VUE3="vue3";
+    /**
+     * 发消息 会传递一个业务ID到map
+     */
+    String NOTICE_MSG_BUS_ID = "NOTICE_MSG_BUS_ID";
+
+    /**
+     * 邮箱消息中地址登录时地址后携带的token,需要替换成真实的token值
+     */
+    String LOGIN_TOKEN = "{LOGIN_TOKEN}";
+
+    /**
+     * 模板消息中 跳转地址的对应的key
+     */
+    String MSG_HREF_URL = "url";
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java
index 95f1bc3..e94a024 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java
@@ -153,4 +153,14 @@ public interface DataBaseConstant {
      * sql语句 where
      */
     String SQL_WHERE = "where";
+
+    /**
+     * sql语句 asc
+     */
+    String SQL_ASC = "asc";
+
+    /**
+     * sqlserver数据库,中间有空格
+     */
+    String DB_TYPE_SQL_SERVER_BLANK = "sql server";
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DynamicTableConstant.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DynamicTableConstant.java
new file mode 100644
index 0000000..0dbff6c
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DynamicTableConstant.java
@@ -0,0 +1,16 @@
+package org.jeecg.common.constant;
+
+/**
+ * 动态切换表配置常量
+ *
+ * @author: scott
+ * @date: 2022年04月25日 22:30
+ */
+public class DynamicTableConstant {
+    /**
+     * 角色首页配置表
+     * vue2表名: sys_role_index
+     * vue3表名: sys_role_index_vue3
+     */
+    public static final String SYS_ROLE_INDEX = "sys_role_index";
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java
index 2c4596b..6c2f170 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java
@@ -35,9 +35,13 @@ public class ProvinceCityArea {
         this.initAreaList();
         if(areaList!=null && areaList.size()>0){
             for(int i=areaList.size()-1;i>=0;i--){
-                if(text.indexOf(areaList.get(i).getText())>=0){
+                //update-begin-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
+                String areaText = areaList.get(i).getText();
+                String cityText = areaList.get(i).getAheadText();
+                if(text.indexOf(areaText)>=0 && (cityText!=null && text.indexOf(cityText)>=0)){
                     return areaList.get(i).getId();
                 }
+                //update-end-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
             }
         }
         return null;
@@ -145,6 +149,9 @@ public class ProvinceCityArea {
                             for(String areaKey:areaJson.keySet()){
                                 //System.out.println("········"+areaKey);
                                 Area area = new Area(areaKey,areaJson.getString(areaKey),cityKey);
+                                //update-begin-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
+                                area.setAheadText(cityJson.getString(cityKey));
+                                //update-end-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
                                 this.areaList.add(area);
                             }
                         }
@@ -180,6 +187,8 @@ public class ProvinceCityArea {
         String id;
         String text;
         String pid;
+        // 用于存储上级文本数据,区的上级文本 是市的数据
+        String aheadText;
 
         public Area(String id,String text,String pid){
             this.id = id;
@@ -198,5 +207,12 @@ public class ProvinceCityArea {
         public String getPid() {
             return pid;
         }
+
+        public String getAheadText() {
+            return aheadText;
+        }
+        public void setAheadText(String aheadText) {
+            this.aheadText = aheadText;
+        }
     }
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/SymbolConstant.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/SymbolConstant.java
index 5156a91..e18e6aa 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/SymbolConstant.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/SymbolConstant.java
@@ -86,4 +86,34 @@ public class SymbolConstant {
      * 符号:和 &
      */
     public static final String AND = "&";
+
+    /**
+     * 符号:../
+     */
+    public static final String SPOT_SINGLE_SLASH = "../";
+
+    /**
+     * 符号:..\\
+     */
+    public static final String SPOT_DOUBLE_BACKSLASH = "..\\";
+
+    /**
+     * 系统变量前缀 #{
+     */
+    public static final String SYS_VAR_PREFIX = "#{";
+
+    /**
+     * 符号 {{
+     */
+    public static final String DOUBLE_LEFT_CURLY_BRACKET = "{{";
+
+    /**
+     * 符号:[
+     */
+    public static final String SQUARE_BRACKETS_LEFT = "[";
+    /**
+     * 符号:]
+     */
+    public static final String SQUARE_BRACKETS_RIGHT = "]";
+
 }
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/CgformEnum.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/CgformEnum.java
index 0265e75..e97c553 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/CgformEnum.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/CgformEnum.java
@@ -20,13 +20,14 @@ public enum CgformEnum {
      */
     MANY(2, "many", "/jeecg/code-template-online", "default.onetomany", "经典风格"),
     /**
-     * 多表
-     */
-    ERP(2, "erp", "/jeecg/code-template-online", "erp.onetomany", "ERP风格"),
-    /**
      * 多表(jvxe风格)
      *  */
     JVXE_TABLE(2, "jvxe", "/jeecg/code-template-online", "jvxe.onetomany", "JVXE风格"),
+
+    /**
+     * 多表
+     */
+    ERP(2, "erp", "/jeecg/code-template-online", "erp.onetomany", "ERP风格"),
     /**
      * 多表(内嵌子表风格)
      */
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java
index b865cad..81c22aa 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java
@@ -15,6 +15,8 @@ public enum LowAppAopEnum {
      * 删除方法(包含单个和批量删除)
      */
     DELETE,
+    /** 复制表单操作 */
+    COPY,
 
     /**
      * Online表单专用:数据库表转Online表单
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/MessageTypeEnum.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/MessageTypeEnum.java
new file mode 100644
index 0000000..b2e65e0
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/MessageTypeEnum.java
@@ -0,0 +1,68 @@
+package org.jeecg.common.constant.enums;
+
+import org.jeecg.common.system.annotation.EnumDict;
+import org.jeecg.common.system.vo.DictModel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 消息类型
+ * @author: jeecg-boot
+ */
+@EnumDict("messageType")
+public enum MessageTypeEnum {
+
+    XT("system",  "系统消息"),
+    YJ("email",  "邮件消息"),
+    DD("dingtalk", "钉钉消息"),
+    QYWX("wechat_enterprise", "企业微信");
+
+    MessageTypeEnum(String type, String note){
+        this.type = type;
+        this.note = note;
+    }
+
+    /**
+     * 消息类型
+     */
+    String type;
+
+    /**
+     * 类型说明
+     */
+    String note;
+
+    public String getNote() {
+        return note;
+    }
+
+    public void setNote(String note) {
+        this.note = note;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+
+    /**
+     * 获取字典数据
+     * @return
+     */
+    public static List<DictModel> getDictList(){
+        List<DictModel> list = new ArrayList<>();
+        DictModel dictModel = null;
+        for(MessageTypeEnum e: MessageTypeEnum.values()){
+            dictModel = new DictModel();
+            dictModel.setValue(e.getType());
+            dictModel.setText(e.getNote());
+            list.add(dictModel);
+        }
+        return list;
+    }
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java
index 7140721..6d5d8ef 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java
@@ -123,7 +123,8 @@ public class JeecgBootExceptionHandler {
     @ExceptionHandler(DataIntegrityViolationException.class)
     public Result<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
     	log.error(e.getMessage(), e);
-        return Result.error("字段太长,超出数据库字段的长度");
+    	//【issues/3624】数据库执行异常handleDataIntegrityViolationException提示有误 #3624
+        return Result.error("执行数据库异常,违反了完整性例如:违反惟一约束、违反非空限制、字段内容超出长度等");
     }
 
     @ExceptionHandler(PoolException.class)
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/annotation/EnumDict.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/annotation/EnumDict.java
new file mode 100644
index 0000000..1ffb760
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/annotation/EnumDict.java
@@ -0,0 +1,19 @@
+package org.jeecg.common.system.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 将枚举类转化成字典数据
+ * @Author taoYan
+ * @Date 2022/7/8 10:34
+ **/
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface EnumDict {
+
+    /**
+     * 作为字典数据的唯一编码
+     */
+    String value() default "";
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java
index c665a09..fdb1506 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java
@@ -53,18 +53,14 @@ public class JeecgController<T, S extends IService<T>> {
         QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
         LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
 
-        // Step.2 获取导出数据
-        List<T> pageList = service.list(queryWrapper);
-        List<T> exportList = null;
-
         // 过滤选中数据
         String selections = request.getParameter("selections");
         if (oConvertUtils.isNotEmpty(selections)) {
             List<String> selectionList = Arrays.asList(selections.split(","));
-            exportList = pageList.stream().filter(item -> selectionList.contains(getId(item))).collect(Collectors.toList());
-        } else {
-            exportList = pageList;
+            queryWrapper.in("id",selectionList);
         }
+        // Step.2 获取导出数据
+        List<T> exportList = service.list(queryWrapper);
 
         // Step.3 AutoPoi 导出Excel
         ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
@@ -97,21 +93,20 @@ public class JeecgController<T, S extends IService<T>> {
         // Step.2 计算分页sheet数据
         double total = service.count();
         int count = (int)Math.ceil(total/pageNum);
-        // Step.3 多sheet处理
+        //update-begin-author:liusq---date:20220629--for: 多sheet导出根据选择导出写法调整 ---
+        // Step.3  过滤选中数据
+        String selections = request.getParameter("selections");
+        if (oConvertUtils.isNotEmpty(selections)) {
+            List<String> selectionList = Arrays.asList(selections.split(","));
+            queryWrapper.in("id",selectionList);
+        }
+        //update-end-author:liusq---date:20220629--for: 多sheet导出根据选择导出写法调整 ---
+        // Step.4 多sheet处理
         List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
         for (int i = 1; i <=count ; i++) {
             Page<T> page = new Page<T>(i, pageNum);
             IPage<T> pageList = service.page(page, queryWrapper);
-            List<T> records = pageList.getRecords();
-            List<T> exportList = null;
-            // 过滤选中数据
-            String selections = request.getParameter("selections");
-            if (oConvertUtils.isNotEmpty(selections)) {
-                List<String> selectionList = Arrays.asList(selections.split(","));
-                exportList = records.stream().filter(item -> selectionList.contains(getId(item))).collect(Collectors.toList());
-            } else {
-                exportList = records;
-            }
+            List<T> exportList = pageList.getRecords();
             Map<String, Object> map = new HashMap<>(5);
             ExportParams  exportParams=new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title+i,upLoadPath);
             exportParams.setType(ExcelType.XSSF);
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java
index 523ffd0..4a1411f 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java
@@ -16,6 +16,7 @@ import org.apache.commons.beanutils.PropertyUtils;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.DataBaseConstant;
 import org.jeecg.common.constant.SymbolConstant;
+import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.system.util.JeecgDataAutorUtils;
 import org.jeecg.common.system.util.JwtUtil;
 import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
@@ -191,8 +192,8 @@ public class QueryGenerator {
 				log.error(e.getMessage(), e);
 			}
 		}
-		// 排序逻辑 处理 
-		doMultiFieldsOrder(queryWrapper, parameterMap);
+		// 排序逻辑 处理
+		doMultiFieldsOrder(queryWrapper, parameterMap, fieldColumnMap.keySet());
 				
 		//高级查询
 		doSuperQuery(queryWrapper, parameterMap, fieldColumnMap);
@@ -228,8 +229,7 @@ public class QueryGenerator {
 		}
 	}
 	
-	/**多字段排序 TODO 需要修改前端*/
-	private static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap) {
+	private static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap, Set<String> allFields) {
 		String column=null,order=null;
 		if(parameterMap!=null&& parameterMap.containsKey(ORDER_COLUMN)) {
 			column = parameterMap.get(ORDER_COLUMN)[0];
@@ -243,6 +243,15 @@ public class QueryGenerator {
 			if(column.endsWith(CommonConstant.DICT_TEXT_SUFFIX)) {
 				column = column.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX));
 			}
+
+			//update-begin-author:taoyan date:2022-5-16 for: issues/3676 获取系统用户列表时,使用SQL注入生效
+			//判断column是不是当前实体的
+			log.info("当前字段有:"+ allFields);
+			if (!allColumnExist(column, allFields)) {
+				throw new JeecgBootException("请注意,将要排序的列字段不存在:" + column);
+			}
+			//update-end-author:taoyan date:2022-5-16 for: issues/3676 获取系统用户列表时,使用SQL注入生效
+
 			//SQL注入check
 			SqlInjectionUtil.filterContent(column);
 
@@ -264,6 +273,28 @@ public class QueryGenerator {
 			//update-end--Author:scott  Date:20210531 for:36 多条件排序无效问题修正-------
 		}
 	}
+
+	//update-begin-author:taoyan date:2022-5-23 for: issues/3676 获取系统用户列表时,使用SQL注入生效
+	/**
+	 * 多字段排序 判断所传字段是否存在
+	 * @return
+	 */
+	private static boolean allColumnExist(String columnStr, Set<String> allFields){
+		boolean exist = true;
+		if(columnStr.indexOf(COMMA)>=0){
+			String[] arr = columnStr.split(COMMA);
+			for(String column: arr){
+				if(!allFields.contains(column)){
+					exist = false;
+					break;
+				}
+			}
+		}else{
+			exist = allFields.contains(columnStr);
+		}
+		return exist;
+	}
+	//update-end-author:taoyan date:2022-5-23 for: issues/3676 获取系统用户列表时,使用SQL注入生效
 	
 	/**
 	 * 高级查询
@@ -825,13 +856,13 @@ public class QueryGenerator {
 			res = field + " in "+getInConditionValue(value, isString);
 			break;
 		case LIKE:
-			res = field + " like "+getLikeConditionValue(value);
+			res = field + " like "+getLikeConditionValue(value, QueryRuleEnum.LIKE);
 			break;
 		case LEFT_LIKE:
-			res = field + " like "+getLikeConditionValue(value);
+			res = field + " like "+getLikeConditionValue(value, QueryRuleEnum.LEFT_LIKE);
 			break;
 		case RIGHT_LIKE:
-			res = field + " like "+getLikeConditionValue(value);
+			res = field + " like "+getLikeConditionValue(value, QueryRuleEnum.RIGHT_LIKE);
 			break;
 		default:
 			res = field+" = "+getFieldConditionValue(value, isString, dataBaseType);
@@ -914,8 +945,15 @@ public class QueryGenerator {
 		}
 		//update-end-author:taoyan date:20210628 for: 查询条件如果输入,导致sql报错
 	}
-	
-	private static String getLikeConditionValue(Object value) {
+
+	/**
+	 * 先根据值判断 走左模糊还是右模糊
+	 * 最后如果值不带任何标识(*或者%),则再根据ruleEnum判断
+	 * @param value
+	 * @param ruleEnum
+	 * @return
+	 */
+	private static String getLikeConditionValue(Object value, QueryRuleEnum ruleEnum) {
 		String str = value.toString().trim();
 		if(str.startsWith(SymbolConstant.ASTERISK) && str.endsWith(SymbolConstant.ASTERISK)) {
 			if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
@@ -951,11 +989,30 @@ public class QueryGenerator {
 					}
 				}
 			}else {
-				if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
-					return "N'%"+str+"%'";
-				}else{
-					return "'%"+str+"%'";
+
+				//update-begin-author:taoyan date:2022-6-30 for: issues/3810 数据权限规则问题
+				// 走到这里说明 value不带有任何模糊查询的标识(*或者%)
+				if (ruleEnum == QueryRuleEnum.LEFT_LIKE) {
+					if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) {
+						return "N'%" + str + "'";
+					} else {
+						return "'%" + str + "'";
+					}
+				} else if (ruleEnum == QueryRuleEnum.RIGHT_LIKE) {
+					if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) {
+						return "N'" + str + "%'";
+					} else {
+						return "'" + str + "%'";
+					}
+				} else {
+					if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) {
+						return "N'%" + str + "%'";
+					} else {
+						return "'%" + str + "%'";
+					}
 				}
+				//update-end-author:taoyan date:2022-6-30 for: issues/3810 数据权限规则问题
+
 			}
 		}
 	}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java
index 73fc14a..4c82608 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java
@@ -54,7 +54,7 @@ public class JwtUtil {
         try {
             os = httpServletResponse.getOutputStream();
 			httpServletResponse.setCharacterEncoding("UTF-8");
-			httpServletResponse.setStatus(401);
+			httpServletResponse.setStatus(code);
             os.write(new ObjectMapper().writeValueAsString(jsonResult).getBytes("UTF-8"));
             os.flush();
             os.close();
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/ResourceUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/ResourceUtil.java
new file mode 100644
index 0000000..d3260c6
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/ResourceUtil.java
@@ -0,0 +1,111 @@
+package org.jeecg.common.system.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.system.annotation.EnumDict;
+import org.jeecg.common.system.vo.DictModel;
+import org.jeecg.common.util.oConvertUtils;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.util.ClassUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 资源加载工具类
+ * @Author taoYan
+ * @Date 2022/7/8 10:40
+ **/
+@Slf4j
+public class ResourceUtil {
+
+
+    /**
+     * 枚举字典数据
+     */
+    private final static Map<String, List<DictModel>> enumDictData = new HashMap<>(5);
+
+    /**
+     * 所有java类
+     */
+    private final static String CLASS_PATTERN="/**/*.class";
+
+    /**
+     * 包路径 org.jeecg
+     */
+    private final static String BASE_PACKAGE = "org.jeecg";
+
+    /**
+     * 枚举类中获取字典数据的方法名
+     */
+    private final static String METHOD_NAME = "getDictList";
+
+    /**
+     * 获取枚举类对应的字典数据 SysDictServiceImpl#queryAllDictItems()
+     * @return
+     */
+    public static Map<String, List<DictModel>> getEnumDictData(){
+        if(enumDictData.keySet().size()>0){
+            return enumDictData;
+        }
+        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
+        String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + CLASS_PATTERN;
+        try {
+            Resource[] resources = resourcePatternResolver.getResources(pattern);
+            MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
+            for (Resource resource : resources) {
+                MetadataReader reader = readerFactory.getMetadataReader(resource);
+                String classname = reader.getClassMetadata().getClassName();
+                Class<?> clazz = Class.forName(classname);
+                EnumDict enumDict = clazz.getAnnotation(EnumDict.class);
+                if (enumDict != null) {
+                    EnumDict annotation = clazz.getAnnotation(EnumDict.class);
+                    String key = annotation.value();
+                    if(oConvertUtils.isNotEmpty(key)){
+                        List<DictModel> list = (List<DictModel>) clazz.getDeclaredMethod(METHOD_NAME).invoke(null);
+                        enumDictData.put(key, list);
+                    }
+                }
+            }
+        }catch (Exception e){
+            log.error("获取枚举类字典数据异常", e.getMessage());
+            // e.printStackTrace();
+        }
+        return enumDictData;
+    }
+
+    /**
+     * 用于后端字典翻译 SysDictServiceImpl#queryManyDictByKeys(java.util.List, java.util.List)
+     * @param dictCodeList
+     * @param keys
+     * @return
+     */
+    public static Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> keys){
+        if(enumDictData.keySet().size()==0){
+            getEnumDictData();
+        }
+        Map<String, List<DictModel>> map = new HashMap<>();
+        for (String code : enumDictData.keySet()) {
+            if(dictCodeList.indexOf(code)>=0){
+                List<DictModel> dictItemList = enumDictData.get(code);
+                for(DictModel dm: dictItemList){
+                    String value = dm.getValue();
+                    if(keys.indexOf(value)>=0){
+                        List<DictModel> list = new ArrayList<>();
+                        list.add(new DictModel(value, dm.getText()));
+                        map.put(code,list);
+                        break;
+                    }
+                }
+            }
+        }
+        return map;
+    }
+
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/LoginUser.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/LoginUser.java
index c40f2e6..251db42 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/LoginUser.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/LoginUser.java
@@ -2,6 +2,7 @@ package org.jeecg.common.system.vo;
 
 import java.util.Date;
 
+import org.jeecg.common.desensitization.annotation.SensitiveField;
 import org.springframework.format.annotation.DateTimeFormat;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
@@ -26,21 +27,25 @@ public class LoginUser {
 	/**
 	 * 登录人id
 	 */
+	@SensitiveField
 	private String id;
 
 	/**
 	 * 登录人账号
 	 */
+	@SensitiveField
 	private String username;
 
 	/**
 	 * 登录人名字
 	 */
+	@SensitiveField
 	private String realname;
 
 	/**
 	 * 登录人密码
 	 */
+	@SensitiveField
 	private String password;
 
      /**
@@ -50,11 +55,13 @@ public class LoginUser {
 	/**
 	 * 头像
 	 */
+	@SensitiveField
 	private String avatar;
 
 	/**
 	 * 生日
 	 */
+	@SensitiveField
 	@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
 	@DateTimeFormat(pattern = "yyyy-MM-dd")
 	private Date birthday;
@@ -67,11 +74,13 @@ public class LoginUser {
 	/**
 	 * 电子邮件
 	 */
+	@SensitiveField
 	private String email;
 
 	/**
 	 * 电话
 	 */
+	@SensitiveField
 	private String phone;
 
 	/**
@@ -103,11 +112,13 @@ public class LoginUser {
 	/**
 	 * 职务,关联职务表
 	 */
+	@SensitiveField
 	private String post;
 
 	/**
 	 * 座机号
 	 */
+	@SensitiveField
 	private String telephone;
 
 	/**多租户id配置,编辑用户的时候设置*/
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java
index 89acf02..80672f3 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java
@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.DataBaseConstant;
+import org.jeecg.common.constant.ServiceNameConstants;
 import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.util.filter.FileTypeFilter;
 import org.jeecg.common.util.oss.OssBootUtil;
@@ -314,14 +315,14 @@ public class CommonUtils {
      */
     public static String getBaseUrl(HttpServletRequest request) {
         //1.【兼容】兼容微服务下的 base path-------
-        String xGatewayBasePath = request.getHeader("X_GATEWAY_BASE_PATH");
+        String xGatewayBasePath = request.getHeader(ServiceNameConstants.X_GATEWAY_BASE_PATH);
         if(oConvertUtils.isNotEmpty(xGatewayBasePath)){
             log.info("x_gateway_base_path = "+ xGatewayBasePath);
             return  xGatewayBasePath;
         }
         //2.【兼容】SSL认证之后,request.getScheme()获取不到https的问题
         // https://blog.csdn.net/weixin_34376986/article/details/89767950
-        String scheme = request.getHeader("X-Forwarded-Scheme");
+        String scheme = request.getHeader(CommonConstant.X_FORWARDED_SCHEME);
         if(oConvertUtils.isEmpty(scheme)){
             scheme = request.getScheme();
         }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestUtil.java
index e0ec2e6..0fb4606 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestUtil.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestUtil.java
@@ -214,7 +214,7 @@ public class RestUtil {
             }
         }
         // 拼接 url 参数
-        if (variables != null) {
+        if (variables != null && !variables.isEmpty()) {
             url += ("?" + asUrlVariables(variables));
         }
         // 发送请求
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
index f2ac657..99c4caf 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
@@ -4,6 +4,8 @@ import cn.hutool.crypto.SecureUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.exception.JeecgBootException;
 import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Field;
+import java.util.Set;
 import java.util.regex.Pattern;
 
 /**
@@ -20,7 +22,11 @@ public class SqlInjectionUtil {
 	private final static String TABLE_DICT_SIGN_SALT = "20200501";
 	private final static String XSS_STR = "and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|user()";
 
-    /**show tables*/
+	/**
+	 * 正则 user() 匹配更严谨
+	 */
+	private final static String REGULAR_EXPRE_USER = "user[\\s]*\\([\\s]*\\)";
+    /**正则 show tables*/
 	private final static String SHOW_TABLES = "show\\s+tables";
 
 	/**
@@ -42,6 +48,13 @@ public class SqlInjectionUtil {
 		log.info(" 表字典,SQL注入漏洞签名校验成功!sign=" + sign + ",dictCode=" + dictCode);
 	}
 
+	/**
+	 * sql注入过滤处理,遇到注入关键字抛异常
+	 * @param value
+	 */
+	public static void filterContent(String value) {
+		filterContent(value, null);
+	}
 
 	/**
 	 * sql注入过滤处理,遇到注入关键字抛异常
@@ -49,7 +62,7 @@ public class SqlInjectionUtil {
 	 * @param value
 	 * @return
 	 */
-	public static void filterContent(String value) {
+	public static void filterContent(String value, String customXssString) {
 		if (value == null || "".equals(value)) {
 			return;
 		}
@@ -66,7 +79,19 @@ public class SqlInjectionUtil {
 				throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
 			}
 		}
-		if(Pattern.matches(SHOW_TABLES, value)){
+		//update-begin-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
+		if (customXssString != null) {
+			String[] xssArr2 = customXssString.split("\\|");
+			for (int i = 0; i < xssArr2.length; i++) {
+				if (value.indexOf(xssArr2[i]) > -1) {
+					log.error("请注意,存在SQL注入关键词---> {}", xssArr2[i]);
+					log.error("请注意,值可能存在SQL注入风险!---> {}", value);
+					throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
+				}
+			}
+		}
+		//update-end-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
+		if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
 			throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
 		}
 		return;
@@ -74,11 +99,19 @@ public class SqlInjectionUtil {
 
 	/**
 	 * sql注入过滤处理,遇到注入关键字抛异常
+	 * @param values
+	 */
+	public static void filterContent(String[] values) {
+		filterContent(values, null);
+	}
+
+	/**
+	 * sql注入过滤处理,遇到注入关键字抛异常
 	 * 
 	 * @param values
 	 * @return
 	 */
-	public static void filterContent(String[] values) {
+	public static void filterContent(String[] values, String customXssString) {
 		String[] xssArr = XSS_STR.split("\\|");
 		for (String value : values) {
 			if (value == null || "".equals(value)) {
@@ -96,7 +129,19 @@ public class SqlInjectionUtil {
 					throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
 				}
 			}
-			if(Pattern.matches(SHOW_TABLES, value)){
+			//update-begin-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
+			if (customXssString != null) {
+				String[] xssArr2 = customXssString.split("\\|");
+				for (int i = 0; i < xssArr2.length; i++) {
+					if (value.indexOf(xssArr2[i]) > -1) {
+						log.error("请注意,存在SQL注入关键词---> {}", xssArr2[i]);
+						log.error("请注意,值可能存在SQL注入风险!---> {}", value);
+						throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
+					}
+				}
+			}
+			//update-end-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
+			if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
 				throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
 			}
 		}
@@ -111,8 +156,8 @@ public class SqlInjectionUtil {
 	 * @return
 	 */
 	//@Deprecated
-	public static void specialFilterContent(String value) {
-		String specialXssStr = " exec | insert | select | delete | update | drop | count | chr | mid | master | truncate | char | declare |;|+|";
+	public static void specialFilterContentForDictSql(String value) {
+		String specialXssStr = " exec | insert | select | delete | update | drop | count | chr | mid | master | truncate | char | declare |;|+|user()";
 		String[] xssArr = specialXssStr.split("\\|");
 		if (value == null || "".equals(value)) {
 			return;
@@ -129,7 +174,7 @@ public class SqlInjectionUtil {
 				throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
 			}
 		}
-		if(Pattern.matches(SHOW_TABLES, value)){
+		if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
 			throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
 		}
 		return;
@@ -144,7 +189,7 @@ public class SqlInjectionUtil {
      */
 	//@Deprecated
 	public static void specialFilterContentForOnlineReport(String value) {
-		String specialXssStr = " exec | insert | delete | update | drop | chr | mid | master | truncate | char | declare |";
+		String specialXssStr = " exec | insert | delete | update | drop | chr | mid | master | truncate | char | declare |user()";
 		String[] xssArr = specialXssStr.split("\\|");
 		if (value == null || "".equals(value)) {
 			return;
@@ -162,10 +207,53 @@ public class SqlInjectionUtil {
 			}
 		}
 
-		if(Pattern.matches(SHOW_TABLES, value)){
+		if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
 			throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
 		}
 		return;
 	}
 
+
+	/**
+	 * 判断给定的字段是不是类中的属性
+	 * @param field 字段名
+	 * @param clazz 类对象
+	 * @return
+	 */
+	public static boolean isClassField(String field, Class clazz){
+		Field[] fields = clazz.getDeclaredFields();
+		for(int i=0;i<fields.length;i++){
+			String fieldName = fields[i].getName();
+			String tableColumnName = oConvertUtils.camelToUnderline(fieldName);
+			if(fieldName.equalsIgnoreCase(field) || tableColumnName.equalsIgnoreCase(field)){
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * 判断给定的多个字段是不是类中的属性
+	 * @param fieldSet 字段名set
+	 * @param clazz 类对象
+	 * @return
+	 */
+	public static boolean isClassField(Set<String> fieldSet, Class clazz){
+		Field[] fields = clazz.getDeclaredFields();
+		for(String field: fieldSet){
+			boolean exist = false;
+			for(int i=0;i<fields.length;i++){
+				String fieldName = fields[i].getName();
+				String tableColumnName = oConvertUtils.camelToUnderline(fieldName);
+				if(fieldName.equalsIgnoreCase(field) || tableColumnName.equalsIgnoreCase(field)){
+					exist = true;
+					break;
+				}
+			}
+			if(!exist){
+				return false;
+			}
+		}
+		return true;
+	}
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java
index b85615c..bd2fa07 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java
@@ -5,6 +5,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.jeecg.common.api.CommonAPI;
 import org.jeecg.common.constant.CacheConstant;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.desensitization.util.SensitiveInfoUtil;
 import org.jeecg.common.exception.JeecgBoot401Exception;
 import org.jeecg.common.system.util.JwtUtil;
 import org.jeecg.common.system.vo.LoginUser;
@@ -106,9 +107,16 @@ public class TokenUtils {
     public static LoginUser getLoginUser(String username, CommonAPI commonApi, RedisUtil redisUtil) {
         LoginUser loginUser = null;
         String loginUserKey = CacheConstant.SYS_USERS_CACHE + "::" + username;
-        if(redisUtil.hasKey(loginUserKey)){
-            loginUser = (LoginUser) redisUtil.get(loginUserKey);
-        }else{
+        //【重要】此处通过redis原生获取缓存用户,是为了解决微服务下system服务挂了,其他服务互调不通问题---
+        if (redisUtil.hasKey(loginUserKey)) {
+            try {
+                loginUser = (LoginUser) redisUtil.get(loginUserKey);
+                //解密用户
+                SensitiveInfoUtil.handlerObject(loginUser, false);
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        } else {
             // 查询用户信息
             loginUser = commonApi.getUserByName(username);
         }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/AesEncryptUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/AesEncryptUtil.java
index ea628dd..670f3eb 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/AesEncryptUtil.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/AesEncryptUtil.java
@@ -66,22 +66,20 @@ public class AesEncryptUtil {
      * @throws Exception
      */
     public static String desEncrypt(String data, String key, String iv) throws Exception {
-        try {
-			byte[] encrypted1 = Base64.decode(data);
+        //update-begin-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去,在外面处理
+        byte[] encrypted1 = Base64.decode(data);
 
-            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
-            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
-            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
+        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+        SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
+        IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
 
-            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
+        cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
 
-            byte[] original = cipher.doFinal(encrypted1);
-            String originalString = new String(original);
-            return originalString;
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
+        byte[] original = cipher.doFinal(encrypted1);
+        String originalString = new String(original);
+        //加密解码后的字符串会出现\u0000
+        return originalString.replaceAll("\\u0000", "");
+        //update-end-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去,在外面处理
     }
 
     /**
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/AbstractQueryBlackListHandler.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/AbstractQueryBlackListHandler.java
index 2806f31..85af28d 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/AbstractQueryBlackListHandler.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/AbstractQueryBlackListHandler.java
@@ -168,7 +168,7 @@ public abstract class AbstractQueryBlackListHandler {
 
     public String getError(){
         // TODO
-        return "sql黑名单校验不通过,请联系管理员!";
+        return "系统设置了安全规则,敏感表和敏感字段禁止查询,联系管理员授权!";
     }
 
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeeccgBaseConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeecgBaseConfig.java
index 6f8a345..12a9cc0 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeeccgBaseConfig.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeecgBaseConfig.java
@@ -1,5 +1,7 @@
 package org.jeecg.config;
 
+import org.jeecg.config.vo.DomainUrl;
+import org.jeecg.config.vo.Path;
 import org.jeecg.config.vo.Shiro;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
@@ -9,9 +11,15 @@ import org.springframework.stereotype.Component;
  * 加载项目配置
  * @author: jeecg-boot
  */
-@Component("jeeccgBaseConfig")
+@Component("jeecgBaseConfig")
 @ConfigurationProperties(prefix = "jeecg")
-public class JeeccgBaseConfig {
+public class JeecgBaseConfig {
+    /**
+     * 签名密钥串(字典等敏感接口)
+     * @TODO 降低使用成本加的默认值,实际以 yml配置 为准
+     */
+    private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a";
+
     /**
      * 是否启用安全模式
      */
@@ -21,10 +29,16 @@ public class JeeccgBaseConfig {
      */
     private Shiro shiro;
     /**
-     * 签名密钥串(字典等敏感接口)
-     * @TODO 降低使用成本加的默认值,实际以 yml配置 为准
+     * 上传文件配置
      */
-    private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a";
+    private Path path;
+
+    /**
+     * 前端页面访问地址
+     * pc: http://localhost:3100
+     * app: http://localhost:8051
+     */
+    private DomainUrl domainUrl;
 
     public Boolean getSafeMode() {
         return safeMode;
@@ -49,4 +63,20 @@ public class JeeccgBaseConfig {
     public void setShiro(Shiro shiro) {
         this.shiro = shiro;
     }
+
+    public Path getPath() {
+        return path;
+    }
+
+    public void setPath(Path path) {
+        this.path = path;
+    }
+
+    public DomainUrl getDomainUrl() {
+        return domainUrl;
+    }
+
+    public void setDomainUrl(DomainUrl domainUrl) {
+        this.domainUrl = domainUrl;
+    }
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/WebMvcConfiguration.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/WebMvcConfiguration.java
index a56b79b..69d804e 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/WebMvcConfiguration.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/WebMvcConfiguration.java
@@ -145,4 +145,13 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
         return () -> meterRegistryPostProcessor.postProcessAfterInitialization(prometheusMeterRegistry, "");
     }
 
+//    /**
+//     * 注册拦截器【拦截器拦截参数,自动切换数据源——后期实现多租户切换数据源功能】
+//     * @param registry
+//     */
+//    @Override
+//    public void addInterceptors(InterceptorRegistry registry) {
+//        registry.addInterceptor(new DynamicDatasourceInterceptor()).addPathPatterns("/test/dynamic/**");
+//    }
+
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java
index 99c075a..0960fc3 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java
@@ -3,6 +3,9 @@ package org.jeecg.config.mybatis;
 import java.util.ArrayList;
 import java.util.List;
 
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.util.oConvertUtils;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.context.annotation.Bean;
@@ -71,9 +74,35 @@ public class MybatisPlusSaasConfig {
             }
         }));
         interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
+        //update-begin-author:zyf date:20220425 for:【VUEN-606】注入动态表名适配拦截器解决多表名问题
+        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor());
+        //update-end-author:zyf date:20220425 for:【VUEN-606】注入动态表名适配拦截器解决多表名问题
         return interceptor;
     }
 
+    /**
+     * 动态表名切换拦截器,用于适配vue2和vue3同一个表有多个的情况,如sys_role_index在vue3情况下表名为sys_role_index_v3
+     * @return
+     */
+    private DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() {
+        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
+        dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
+            //获取需要动态解析的表名
+            String dynamicTableName = ThreadLocalDataHelper.get(CommonConstant.DYNAMIC_TABLE_NAME);
+            //当dynamicTableName不为空时才走动态表名处理逻辑,否则返回原始表名
+            if (ObjectUtil.isNotEmpty(dynamicTableName) && dynamicTableName.equals(tableName)) {
+                // 获取前端传递的版本号标识
+                Object version = ThreadLocalDataHelper.get(CommonConstant.VERSION);
+                if (ObjectUtil.isNotEmpty(version)) {
+                    //拼接表名规则(原始表名+下划线+前端传递的版本号)
+                    return tableName + "_" + version;
+                }
+            }
+            return tableName;
+        });
+        return dynamicTableNameInnerInterceptor;
+    }
+
 //    /**
 //     * 下个版本会删除,现在为了避免缓存出现问题不得不配置
 //     * @return
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/ThreadLocalDataHelper.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/ThreadLocalDataHelper.java
new file mode 100644
index 0000000..0b60721
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/ThreadLocalDataHelper.java
@@ -0,0 +1,62 @@
+package org.jeecg.config.mybatis;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * @Description: 本地线程变量存储工具类
+ * @author: lsq
+ * @date: 2022年03月25日 11:42
+ */
+public class ThreadLocalDataHelper {
+    /**
+     * 线程的本地变量
+     */
+    private static final ThreadLocal<ConcurrentHashMap> REQUEST_DATA = new ThreadLocal<>();
+
+    /**
+     * 存储本地参数
+     */
+    private static final ConcurrentHashMap DATA_MAP = new ConcurrentHashMap<>();
+
+    /**
+     * 设置请求参数
+     *
+     * @param key  参数key
+     * @param value 参数值
+     */
+    public static void put(String key, Object value) {
+        if(ObjectUtil.isNotEmpty(value)) {
+            DATA_MAP.put(key, value);
+            REQUEST_DATA.set(DATA_MAP);
+        }
+    }
+
+    /**
+     * 获取请求参数值
+     *
+     * @param key 请求参数
+     * @return
+     */
+    public static <T> T get(String key) {
+        ConcurrentHashMap dataMap = REQUEST_DATA.get();
+        if (CollectionUtils.isNotEmpty(dataMap)) {
+            return (T) dataMap.get(key);
+        }
+        return null;
+    }
+
+    /**
+     * 获取请求参数
+     *
+     * @return 请求参数 MAP 对象
+     */
+    public static void clear() {
+        DATA_MAP.clear();
+        REQUEST_DATA.remove();
+    }
+
+}
+
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/aspect/DynamicTableAspect.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/aspect/DynamicTableAspect.java
new file mode 100644
index 0000000..b0d67cb
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/aspect/DynamicTableAspect.java
@@ -0,0 +1,55 @@
+package org.jeecg.config.mybatis.aspect;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.jeecg.common.aspect.annotation.DynamicTable;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.config.mybatis.ThreadLocalDataHelper;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+
+/**
+ * 动态table切换 切面处理
+ *
+ * @author :zyf
+ * @date:2020-04-25
+ */
+@Aspect
+@Component
+public class DynamicTableAspect {
+
+
+    /**
+     * 定义切面拦截切入点
+     */
+    @Pointcut("@annotation(org.jeecg.common.aspect.annotation.DynamicTable)")
+    public void dynamicTable() {
+    }
+
+
+    @Around("dynamicTable()")
+    public Object around(ProceedingJoinPoint point) throws Throwable {
+        MethodSignature signature = (MethodSignature) point.getSignature();
+        Method method = signature.getMethod();
+        DynamicTable dynamicTable = method.getAnnotation(DynamicTable.class);
+        HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
+        //获取前端传递的版本标记
+        String version = request.getHeader(CommonConstant.VERSION);
+        //存储版本号到本地线程变量
+        ThreadLocalDataHelper.put(CommonConstant.VERSION, version);
+        //存储表名到本地线程变量
+        ThreadLocalDataHelper.put(CommonConstant.DYNAMIC_TABLE_NAME, dynamicTable.value());
+        //执行方法
+        Object result = point.proceed();
+        //清空本地变量
+        ThreadLocalDataHelper.clear();
+        return result;
+    }
+
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/interceptor/DynamicDatasourceInterceptor.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/interceptor/DynamicDatasourceInterceptor.java
new file mode 100644
index 0000000..3461cbd
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/interceptor/DynamicDatasourceInterceptor.java
@@ -0,0 +1,55 @@
+package org.jeecg.config.mybatis.interceptor;
+
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 动态数据源切换拦截器
+ *
+ * 测试:拦截参数,自动切换数据源
+ * 未来规划:后面通过此机制,实现多租户切换数据源功能
+ * @author zyf
+ */
+@Slf4j
+public class DynamicDatasourceInterceptor implements HandlerInterceptor {
+
+    /**
+     * 在请求处理之前进行调用(Controller方法调用之前)
+     */
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
+        String requestURI = request.getRequestURI();
+        log.info("经过多数据源Interceptor,当前路径是{}", requestURI);
+        //获取动态数据源名称
+        String dsName = request.getParameter("dsName");
+        String dsKey = "master";
+        if (StringUtils.isNotEmpty(dsName)) {
+            dsKey = dsName;
+        }
+        DynamicDataSourceContextHolder.push(dsKey);
+        return true;
+    }
+
+    /**
+     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
+     */
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
+
+    }
+
+    /**
+     * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
+     */
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
+        DynamicDataSourceContextHolder.clear();
+    }
+
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
index f0fe2d2..b31f538 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
@@ -15,7 +15,7 @@ import org.crazycake.shiro.RedisClusterManager;
 import org.crazycake.shiro.RedisManager;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.util.oConvertUtils;
-import org.jeecg.config.JeeccgBaseConfig;
+import org.jeecg.config.JeecgBaseConfig;
 import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean;
 import org.jeecg.config.shiro.filters.JwtFilter;
 import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
@@ -45,11 +45,11 @@ import java.util.*;
 public class ShiroConfig {
 
     @Resource
-    LettuceConnectionFactory lettuceConnectionFactory;
+    private LettuceConnectionFactory lettuceConnectionFactory;
     @Autowired
     private Environment env;
-    @Autowired
-    JeeccgBaseConfig jeeccgBaseConfig;
+    @Resource
+    private JeecgBaseConfig jeecgBaseConfig;
 
     /**
      * Filter Chain定义说明
@@ -64,11 +64,15 @@ public class ShiroConfig {
         shiroFilterFactoryBean.setSecurityManager(securityManager);
         // 拦截器
         Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
-        String shiroExcludeUrls = jeeccgBaseConfig.getShiro().getExcludeUrls();
-        if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){
-            String[] permissionUrl = shiroExcludeUrls.split(",");
-            for(String url : permissionUrl){
-                filterChainDefinitionMap.put(url,"anon");
+
+        //支持yml方式,配置拦截排除
+        if(jeecgBaseConfig.getShiro()!=null){
+            String shiroExcludeUrls = jeecgBaseConfig.getShiro().getExcludeUrls();
+            if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){
+                String[] permissionUrl = shiroExcludeUrls.split(",");
+                for(String url : permissionUrl){
+                    filterChainDefinitionMap.put(url,"anon");
+                }
             }
         }
         // 配置不会被拦截的链接 顺序判断
@@ -125,9 +129,11 @@ public class ShiroConfig {
         filterChainDefinitionMap.put("/jmreport/**", "anon");
         filterChainDefinitionMap.put("/**/*.js.map", "anon");
         filterChainDefinitionMap.put("/**/*.css.map", "anon");
-
-        //测试示例
-        filterChainDefinitionMap.put("/test/bigScreen/**", "anon"); //大屏模板例子
+        
+        //大屏模板例子
+        filterChainDefinitionMap.put("/test/bigScreen/**", "anon");
+        filterChainDefinitionMap.put("/bigscreen/template1/**", "anon");
+        filterChainDefinitionMap.put("/bigscreen/template1/**", "anon");
         //filterChainDefinitionMap.put("/test/jeecgDemo/rabbitMqClientTest/**", "anon"); //MQ测试
         //filterChainDefinitionMap.put("/test/jeecgDemo/html", "anon"); //模板页面
         //filterChainDefinitionMap.put("/test/jeecgDemo/redis/**", "anon"); //redis测试
@@ -137,8 +143,6 @@ public class ShiroConfig {
         filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块
         filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例
 
-        //wps
-        filterChainDefinitionMap.put("/v1/**","anon");
 
         //性能监控  TODO 存在安全漏洞泄露TOEKN(durid连接池也有)
         filterChainDefinitionMap.put("/actuator/**", "anon");
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
index acf80f8..6c203dc 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
@@ -69,13 +69,13 @@ public class ShiroRealm extends AuthorizingRealm {
 
         // 设置用户拥有的角色集合,比如“admin,test”
         Set<String> roleSet = commonApi.queryUserRoles(username);
-        System.out.println(roleSet.toString());
+        //System.out.println(roleSet.toString());
         info.setRoles(roleSet);
 
         // 设置用户拥有的权限集合,比如“sys:role:add,sys:user:add”
         Set<String> permissionSet = commonApi.queryUserAuths(username);
         info.addStringPermissions(permissionSet);
-        System.out.println(permissionSet);
+        //System.out.println(permissionSet);
         log.info("===============Shiro权限认证成功==============");
         return info;
     }
@@ -123,7 +123,7 @@ public class ShiroRealm extends AuthorizingRealm {
 
         // 查询用户信息
         log.debug("———校验token是否有效————checkUserTokenIsEffect——————— "+ token);
-        LoginUser loginUser = TokenUtils.getLoginUser(username,commonApi,redisUtil);
+        LoginUser loginUser = TokenUtils.getLoginUser(username, commonApi, redisUtil);
         //LoginUser loginUser = commonApi.getUserByName(username);
         if (loginUser == null) {
             throw new AuthenticationException("用户不存在!");
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java
index ded143f..ca8de21 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java
@@ -107,4 +107,18 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
 
         return super.preHandle(request, response);
     }
+
+    /**
+     * JwtFilter中ThreadLocal需要及时清除 #3634
+     *
+     * @param request
+     * @param response
+     * @param exception
+     * @throws Exception
+     */
+    @Override
+    public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
+        //log.info("------清空线程中多租户的ID={}------",TenantContext.getTenant());
+        TenantContext.clear();
+    }
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthConfiguration.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthConfiguration.java
index e78fa35..137ecc5 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthConfiguration.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthConfiguration.java
@@ -1,5 +1,7 @@
 package org.jeecg.config.sign.interceptor;
 
+import org.jeecg.config.filter.RequestBodyReserveFilter;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@@ -24,4 +26,22 @@ public class SignAuthConfiguration implements WebMvcConfigurer {
     public void addInterceptors(InterceptorRegistry registry) {
         registry.addInterceptor(signAuthInterceptor()).addPathPatterns(SIGN_URL_LIST);
     }
+
+    //update-begin-author:taoyan date:20220427 for: issues/I53J5E post请求X_SIGN签名拦截校验后报错, request body 为空
+    @Bean
+    public RequestBodyReserveFilter requestBodyReserveFilter(){
+        return new RequestBodyReserveFilter();
+    }
+
+    @Bean
+    public FilterRegistrationBean reqBodyFilterRegistrationBean(){
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setFilter(requestBodyReserveFilter());
+        registration.setName("requestBodyReserveFilter");
+        // 建议此处只添加post请求地址而不是所有的都需要走过滤器
+        registration.addUrlPatterns(SIGN_URL_LIST);
+        return registration;
+    }
+    //update-end-author:taoyan date:20220427 for: issues/I53J5E post请求X_SIGN签名拦截校验后报错, request body 为空
+
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java
index 3cdbaea..27fb811 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java
@@ -32,7 +32,7 @@ public class SignAuthInterceptor implements HandlerInterceptor {
 
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-        log.info("request URI = " + request.getRequestURI());
+        log.info("Sign Interceptor request URI = " + request.getRequestURI());
         HttpServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
         //获取全部参数(包括URL和body上的)
         SortedMap<String, String> allParams = HttpUtils.getAllParams(requestWrapper);
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java
index 3f82822..54cc320 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java
@@ -6,7 +6,7 @@ import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.util.SpringContextUtils;
 import org.jeecg.common.util.oConvertUtils;
-import org.jeecg.config.JeeccgBaseConfig;
+import org.jeecg.config.JeecgBaseConfig;
 import org.springframework.util.DigestUtils;
 import org.springframework.util.StringUtils;
 
@@ -48,8 +48,8 @@ public class SignUtil {
         String paramsJsonStr = JSONObject.toJSONString(params);
         log.info("Param paramsJsonStr : {}", paramsJsonStr);
         //设置签名秘钥
-        JeeccgBaseConfig jeeccgBaseConfig = SpringContextUtils.getBean(JeeccgBaseConfig.class);
-        String signatureSecret = jeeccgBaseConfig.getSignatureSecret();
+        JeecgBaseConfig jeecgBaseConfig = SpringContextUtils.getBean(JeecgBaseConfig.class);
+        String signatureSecret = jeecgBaseConfig.getSignatureSecret();
         String curlyBracket = SymbolConstant.DOLLAR + SymbolConstant.LEFT_CURLY_BRACKET;
         if(oConvertUtils.isEmpty(signatureSecret) || signatureSecret.contains(curlyBracket)){
             throw new JeecgBootException("签名密钥 ${jeecg.signatureSecret} 缺少配置 !!");
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/DomainUrl.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/DomainUrl.java
new file mode 100644
index 0000000..df6b8c3
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/DomainUrl.java
@@ -0,0 +1,15 @@
+package org.jeecg.config.vo;
+
+import lombok.Data;
+
+/**
+ * @Author taoYan
+ * @Date 2022/7/5 21:16
+ **/
+@Data
+public class DomainUrl {
+
+    private String pc;
+
+    private String app;
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Path.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Path.java
new file mode 100644
index 0000000..9227a84
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Path.java
@@ -0,0 +1,29 @@
+package org.jeecg.config.vo;
+
+import javax.print.DocFlavor;
+
+/**
+ *
+ * @author: scott
+ * @date: 2022年04月18日 20:35
+ */
+public class Path {
+    private String upload;
+    private String webapp;
+
+    public String getUpload() {
+        return upload;
+    }
+
+    public void setUpload(String upload) {
+        this.upload = upload;
+    }
+
+    public String getWebapp() {
+        return webapp;
+    }
+
+    public void setWebapp(String webapp) {
+        this.webapp = webapp;
+    }
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/xml/BaseCommonMapper.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/xml/BaseCommonMapper.xml
index 1bf49d9..e558e3a 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/xml/BaseCommonMapper.xml
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/xml/BaseCommonMapper.xml
@@ -4,19 +4,22 @@
 
     <!-- 保存日志11 -->
     <insert id="saveLog" parameterType="Object">
-        insert into sys_log (id, log_type, log_content, method, operate_type, request_param, ip, userid, username, cost_time, create_time)
+        insert into sys_log (id, log_type, log_content, method, operate_type, request_url, request_type, request_param, ip, userid, username, cost_time, create_time,create_by)
         values(
             #{dto.id,jdbcType=VARCHAR},
             #{dto.logType,jdbcType=INTEGER},
             #{dto.logContent,jdbcType=VARCHAR},
             #{dto.method,jdbcType=VARCHAR},
             #{dto.operateType,jdbcType=INTEGER},
+            #{dto.requestUrl,jdbcType=VARCHAR},
+            #{dto.requestType,jdbcType=VARCHAR},
             #{dto.requestParam,jdbcType=VARCHAR},
             #{dto.ip,jdbcType=VARCHAR},
             #{dto.userid,jdbcType=VARCHAR},
             #{dto.username,jdbcType=VARCHAR},
             #{dto.costTime,jdbcType=BIGINT},
-            #{dto.createTime,jdbcType=TIMESTAMP}
+            #{dto.createTime,jdbcType=TIMESTAMP},
+            #{dto.createBy,jdbcType=VARCHAR}
         )
     </insert>
 
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/service/impl/BaseCommonServiceImpl.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/service/impl/BaseCommonServiceImpl.java
index 2c1919d..3bd057c 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/service/impl/BaseCommonServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/service/impl/BaseCommonServiceImpl.java
@@ -34,6 +34,7 @@ public class BaseCommonServiceImpl implements BaseCommonService {
         }
         //保存日志(异常捕获处理,防止数据太大存储失败,导致业务失败)JT-238
         try {
+            logDTO.setCreateTime(new Date());
             baseCommonMapper.saveLog(logDTO);
         } catch (Exception e) {
             log.warn(" LogContent length : "+logDTO.getLogContent().length());