diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/init/SystemInitListener.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/init/SystemInitListener.java
index 40c6188..5862ea9 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/init/SystemInitListener.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/init/SystemInitListener.java
@@ -28,7 +28,8 @@ public class SystemInitListener implements ApplicationListener<ApplicationReadyE
     public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
 
         log.info(" 服务已启动,初始化路由配置 ###################");
-        if (applicationReadyEvent.getApplicationContext().getDisplayName().indexOf("AnnotationConfigServletWebServerApplicationContext") > -1) {
+        String context = "AnnotationConfigServletWebServerApplicationContext";
+        if (applicationReadyEvent.getApplicationContext().getDisplayName().indexOf(context) > -1) {
             sysGatewayRouteService.addRoute2Redis(CacheConstant.GATEWAY_ROUTES);
         }
 
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java
new file mode 100644
index 0000000..832d73a
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java
@@ -0,0 +1,663 @@
+package org.jeecg.modules.api.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.dto.OnlineAuthDTO;
+import org.jeecg.common.api.dto.message.*;
+import org.jeecg.common.system.vo.*;
+import org.jeecg.modules.system.service.ISysUserService;
+import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * 服务化 system模块 对外接口请求类
+ * @author: jeecg-boot
+ */
+@Slf4j
+@RestController
+@RequestMapping("/sys/api")
+public class SystemApiController {
+
+    @Autowired
+    private SysBaseApiImpl sysBaseApi;
+    @Autowired
+    private ISysUserService sysUserService;
+
+
+    /**
+     * 发送系统消息
+     * @param message 使用构造器赋值参数 如果不设置category(消息类型)则默认为2 发送系统消息
+     */
+    @PostMapping("/sendSysAnnouncement")
+    public void sendSysAnnouncement(@RequestBody MessageDTO message){
+        sysBaseApi.sendSysAnnouncement(message);
+    }
+
+    /**
+     * 发送消息 附带业务参数
+     * @param message 使用构造器赋值参数
+     */
+    @PostMapping("/sendBusAnnouncement")
+    public void sendBusAnnouncement(@RequestBody BusMessageDTO message){
+        sysBaseApi.sendBusAnnouncement(message);
+    }
+
+    /**
+     * 通过模板发送消息
+     * @param message 使用构造器赋值参数
+     */
+    @PostMapping("/sendTemplateAnnouncement")
+    public void sendTemplateAnnouncement(@RequestBody TemplateMessageDTO message){
+        sysBaseApi.sendTemplateAnnouncement(message);
+    }
+
+    /**
+     * 通过模板发送消息 附带业务参数
+     * @param message 使用构造器赋值参数
+     */
+    @PostMapping("/sendBusTemplateAnnouncement")
+    public void sendBusTemplateAnnouncement(@RequestBody BusTemplateMessageDTO message){
+        sysBaseApi.sendBusTemplateAnnouncement(message);
+    }
+
+    /**
+     * 通过消息中心模板,生成推送内容
+     * @param templateDTO 使用构造器赋值参数
+     * @return
+     */
+    @PostMapping("/parseTemplateByCode")
+    public String parseTemplateByCode(@RequestBody TemplateDTO templateDTO){
+        return sysBaseApi.parseTemplateByCode(templateDTO);
+    }
+
+    /**
+     * 根据业务类型busType及业务busId修改消息已读
+     */
+    @GetMapping("/updateSysAnnounReadFlag")
+    public void updateSysAnnounReadFlag(@RequestParam("busType") String busType, @RequestParam("busId")String busId){
+        sysBaseApi.updateSysAnnounReadFlag(busType, busId);
+    }
+
+    /**
+     * 根据用户账号查询用户信息
+     * @param username
+     * @return
+     */
+    @GetMapping("/getUserByName")
+    public LoginUser getUserByName(@RequestParam("username") String username){
+        return sysBaseApi.getUserByName(username);
+    }
+
+    /**
+     * 根据用户id查询用户信息
+     * @param id
+     * @return
+     */
+    @GetMapping("/getUserById")
+    LoginUser getUserById(@RequestParam("id") String id){
+        return sysBaseApi.getUserById(id);
+    }
+
+    /**
+     * 通过用户账号查询角色集合
+     * @param username
+     * @return
+     */
+    @GetMapping("/getRolesByUsername")
+    List<String> getRolesByUsername(@RequestParam("username") String username){
+        return sysBaseApi.getRolesByUsername(username);
+    }
+
+    /**
+     * 通过用户账号查询部门集合
+     * @param username
+     * @return 部门 id
+     */
+    @GetMapping("/getDepartIdsByUsername")
+    List<String> getDepartIdsByUsername(@RequestParam("username") String username){
+        return sysBaseApi.getDepartIdsByUsername(username);
+    }
+
+    /**
+     * 通过用户账号查询部门 name
+     * @param username
+     * @return 部门 name
+     */
+    @GetMapping("/getDepartNamesByUsername")
+    List<String> getDepartNamesByUsername(@RequestParam("username") String username){
+        return sysBaseApi.getDepartNamesByUsername(username);
+    }
+
+
+    /**
+     * 获取数据字典
+     * @param code
+     * @return
+     */
+    @GetMapping("/queryDictItemsByCode")
+    List<DictModel> queryDictItemsByCode(@RequestParam("code") String code){
+        return sysBaseApi.queryDictItemsByCode(code);
+    }
+
+    /**
+     * 获取有效的数据字典
+     * @param code
+     * @return
+     */
+    @GetMapping("/queryEnableDictItemsByCode")
+    List<DictModel> queryEnableDictItemsByCode(@RequestParam("code") String code){
+        return sysBaseApi.queryEnableDictItemsByCode(code);
+    }
+
+
+    /** 查询所有的父级字典,按照create_time排序 */
+    @GetMapping("/queryAllDict")
+    List<DictModel> queryAllDict(){
+//        try{
+//            //睡10秒,gateway网关5秒超时,会触发熔断降级操作
+//            Thread.sleep(10000);
+//        }catch (Exception e){
+//            e.printStackTrace();
+//        }
+
+        log.info("--我是jeecg-system服务节点,微服务接口queryAllDict被调用--");
+        return sysBaseApi.queryAllDict();
+    }
+
+    /**
+     * 查询所有分类字典
+     * @return
+     */
+    @GetMapping("/queryAllSysCategory")
+    List<SysCategoryModel> queryAllSysCategory(){
+        return sysBaseApi.queryAllSysCategory();
+    }
+
+
+    /**
+     * 查询所有部门 作为字典信息 id -->value,departName -->text
+     * @return
+     */
+    @GetMapping("/queryAllDepartBackDictModel")
+    List<DictModel> queryAllDepartBackDictModel(){
+        return sysBaseApi.queryAllDepartBackDictModel();
+    }
+
+    /**
+     * 获取所有角色 带参
+     * roleIds 默认选中角色
+     * @return
+     */
+    @GetMapping("/queryAllRole")
+    public List<ComboModel> queryAllRole(@RequestParam(name = "roleIds",required = false)String[] roleIds){
+        if(roleIds==null || roleIds.length==0){
+            return sysBaseApi.queryAllRole();
+        }else{
+            return sysBaseApi.queryAllRole(roleIds);
+        }
+    }
+
+    /**
+     * 通过用户账号查询角色Id集合
+     * @param username
+     * @return
+     */
+    @GetMapping("/getRoleIdsByUsername")
+    public List<String> getRoleIdsByUsername(@RequestParam("username")String username){
+        return sysBaseApi.getRoleIdsByUsername(username);
+    }
+
+    /**
+     * 通过部门编号查询部门id
+     * @param orgCode
+     * @return
+     */
+    @GetMapping("/getDepartIdsByOrgCode")
+    public String getDepartIdsByOrgCode(@RequestParam("orgCode")String orgCode){
+        return sysBaseApi.getDepartIdsByOrgCode(orgCode);
+    }
+
+    /**
+     * 查询所有部门
+     * @return
+     */
+    @GetMapping("/getAllSysDepart")
+    public List<SysDepartModel> getAllSysDepart(){
+        return sysBaseApi.getAllSysDepart();
+    }
+
+    /**
+     * 根据 id 查询数据库中存储的 DynamicDataSourceModel
+     *
+     * @param dbSourceId
+     * @return
+     */
+    @GetMapping("/getDynamicDbSourceById")
+    DynamicDataSourceModel getDynamicDbSourceById(@RequestParam("dbSourceId")String dbSourceId){
+        return sysBaseApi.getDynamicDbSourceById(dbSourceId);
+    }
+
+
+
+    /**
+     * 根据部门Id获取部门负责人
+     * @param deptId
+     * @return
+     */
+    @GetMapping("/getDeptHeadByDepId")
+    public List<String> getDeptHeadByDepId(@RequestParam("deptId") String deptId){
+        return sysBaseApi.getDeptHeadByDepId(deptId);
+    }
+
+    /**
+     * 查找父级部门
+     * @param departId
+     * @return
+     */
+    @GetMapping("/getParentDepartId")
+    public DictModel getParentDepartId(@RequestParam("departId")String departId){
+        return sysBaseApi.getParentDepartId(departId);
+    }
+
+    /**
+     * 根据 code 查询数据库中存储的 DynamicDataSourceModel
+     *
+     * @param dbSourceCode
+     * @return
+     */
+    @GetMapping("/getDynamicDbSourceByCode")
+    public DynamicDataSourceModel getDynamicDbSourceByCode(@RequestParam("dbSourceCode") String dbSourceCode){
+        return sysBaseApi.getDynamicDbSourceByCode(dbSourceCode);
+    }
+
+    /**
+     * 给指定用户发消息
+     * @param userIds
+     * @param cmd
+     */
+    @GetMapping("/sendWebSocketMsg")
+    public void sendWebSocketMsg(String[] userIds, String cmd){
+        sysBaseApi.sendWebSocketMsg(userIds, cmd);
+    }
+
+
+    /**
+     * 根据id获取所有参与用户
+     * userIds
+     * @return
+     */
+    @GetMapping("/queryAllUserByIds")
+    public List<LoginUser> queryAllUserByIds(@RequestParam("userIds") String[] userIds){
+        return sysBaseApi.queryAllUserByIds(userIds);
+    }
+
+    /**
+     * 查询所有用户 返回ComboModel
+     * @return
+     */
+    @GetMapping("/queryAllUserBackCombo")
+    public List<ComboModel> queryAllUserBackCombo(){
+        return sysBaseApi.queryAllUserBackCombo();
+    }
+
+    /**
+     * 分页查询用户 返回JSONObject
+     * @return
+     */
+    @GetMapping("/queryAllUser")
+    public JSONObject queryAllUser(@RequestParam(name="userIds",required=false)String userIds, @RequestParam(name="pageNo",required=false) Integer pageNo,@RequestParam(name="pageSize",required=false) int pageSize){
+        return sysBaseApi.queryAllUser(userIds, pageNo, pageSize);
+    }
+
+
+
+    /**
+     * 将会议签到信息推动到预览
+     * userIds
+     * @return
+     * @param userId
+     */
+    @GetMapping("/meetingSignWebsocket")
+    public void meetingSignWebsocket(@RequestParam("userId")String userId){
+        sysBaseApi.meetingSignWebsocket(userId);
+    }
+
+    /**
+     * 根据name获取所有参与用户
+     * userNames
+     * @return
+     */
+    @GetMapping("/queryUserByNames")
+    public List<LoginUser> queryUserByNames(@RequestParam("userNames")String[] userNames){
+        return sysBaseApi.queryUserByNames(userNames);
+    }
+
+    /**
+     * 获取用户的角色集合
+     * @param username
+     * @return
+     */
+    @GetMapping("/getUserRoleSet")
+    public Set<String> getUserRoleSet(@RequestParam("username")String username){
+        return sysBaseApi.getUserRoleSet(username);
+    }
+
+    /**
+     * 获取用户的权限集合
+     * @param username
+     * @return
+     */
+    @GetMapping("/getUserPermissionSet")
+    public Set<String> getUserPermissionSet(@RequestParam("username") String username){
+        return sysBaseApi.getUserPermissionSet(username);
+    }
+
+    //-----
+
+    /**
+     * 判断是否有online访问的权限
+     * @param onlineAuthDTO
+     * @return
+     */
+    @PostMapping("/hasOnlineAuth")
+    public boolean hasOnlineAuth(@RequestBody OnlineAuthDTO onlineAuthDTO){
+        return sysBaseApi.hasOnlineAuth(onlineAuthDTO);
+    }
+
+    /**
+     * 查询用户角色信息
+     * @param username
+     * @return
+     */
+    @GetMapping("/queryUserRoles")
+    public Set<String> queryUserRoles(@RequestParam("username") String username){
+        return sysUserService.getUserRolesSet(username);
+    }
+
+
+    /**
+     * 查询用户权限信息
+     * @param username
+     * @return
+     */
+    @GetMapping("/queryUserAuths")
+    public Set<String> queryUserAuths(@RequestParam("username") String username){
+        return sysUserService.getUserPermissionsSet(username);
+    }
+
+    /**
+     * 通过部门id获取部门全部信息
+     */
+    @GetMapping("/selectAllById")
+    public SysDepartModel selectAllById(@RequestParam("id") String id){
+        return sysBaseApi.selectAllById(id);
+    }
+
+    /**
+     * 根据用户id查询用户所属公司下所有用户ids
+     * @param userId
+     * @return
+     */
+    @GetMapping("/queryDeptUsersByUserId")
+    public List<String> queryDeptUsersByUserId(@RequestParam("userId") String userId){
+        return sysBaseApi.queryDeptUsersByUserId(userId);
+    }
+
+
+    /**
+     * 查询数据权限
+     * @return
+     */
+    @GetMapping("/queryPermissionDataRule")
+    public List<SysPermissionDataRuleModel> queryPermissionDataRule(@RequestParam("component") String component, @RequestParam("requestPath")String requestPath, @RequestParam("username") String username){
+        return sysBaseApi.queryPermissionDataRule(component, requestPath, username);
+    }
+
+    /**
+     * 查询用户信息
+     * @param username
+     * @return
+     */
+    @GetMapping("/getCacheUser")
+    public SysUserCacheInfo getCacheUser(@RequestParam("username") String username){
+        return sysBaseApi.getCacheUser(username);
+    }
+
+    /**
+     * 普通字典的翻译
+     * @param code
+     * @param key
+     * @return
+     */
+    @GetMapping("/translateDict")
+    public String translateDict(@RequestParam("code") String code, @RequestParam("key") String key){
+        return sysBaseApi.translateDict(code, key);
+    }
+
+
+    /**
+     * 36根据多个用户账号(逗号分隔),查询返回多个用户信息
+     * @param usernames
+     * @return
+     */
+    @RequestMapping("/queryUsersByUsernames")
+    List<JSONObject> queryUsersByUsernames(@RequestParam("usernames") String usernames){
+        return this.sysBaseApi.queryUsersByUsernames(usernames);
+    }
+
+    /**
+     * 37根据多个用户id(逗号分隔),查询返回多个用户信息
+     * @param ids
+     * @return
+     */
+    @RequestMapping("/queryUsersByIds")
+    List<JSONObject> queryUsersByIds(@RequestParam("ids") String ids){
+        return this.sysBaseApi.queryUsersByIds(ids);
+    }
+
+    /**
+     * 38根据多个部门编码(逗号分隔),查询返回多个部门信息
+     * @param orgCodes
+     * @return
+     */
+    @GetMapping("/queryDepartsByOrgcodes")
+    List<JSONObject> queryDepartsByOrgcodes(@RequestParam("orgCodes") String orgCodes){
+        return this.sysBaseApi.queryDepartsByOrgcodes(orgCodes);
+    }
+
+    /**
+     * 39根据多个部门ID(逗号分隔),查询返回多个部门信息
+     * @param ids
+     * @return
+     */
+    @GetMapping("/queryDepartsByIds")
+    List<JSONObject> queryDepartsByIds(@RequestParam("ids") String ids){
+        return this.sysBaseApi.queryDepartsByIds(ids);
+    }
+
+    /**
+     * 40发送邮件消息
+     * @param email
+     * @param title
+     * @param content
+     */
+    @GetMapping("/sendEmailMsg")
+    public void sendEmailMsg(@RequestParam("email")String email,@RequestParam("title")String title,@RequestParam("content")String content){
+         this.sysBaseApi.sendEmailMsg(email,title,content);
+    };
+    /**
+     * 41 获取公司下级部门和公司下所有用户信息
+     * @param orgCode
+     */
+    @GetMapping("/getDeptUserByOrgCode")
+    List<Map> getDeptUserByOrgCode(@RequestParam("orgCode")String orgCode){
+       return this.sysBaseApi.getDeptUserByOrgCode(orgCode);
+    }
+
+    /**
+     * 查询分类字典翻译
+     *
+     * @param ids 分类字典表id
+     * @return
+     */
+    @GetMapping("/loadCategoryDictItem")
+    public List<String> loadCategoryDictItem(@RequestParam("ids") String ids) {
+        return sysBaseApi.loadCategoryDictItem(ids);
+    }
+
+    /**
+     * 根据字典code加载字典text
+     *
+     * @param dictCode 顺序:tableName,text,code
+     * @param keys     要查询的key
+     * @return
+     */
+    @GetMapping("/loadDictItem")
+    public List<String> loadDictItem(@RequestParam("dictCode") String dictCode, @RequestParam("keys") String keys) {
+        return sysBaseApi.loadDictItem(dictCode, keys);
+    }
+
+    /**
+     * 根据字典code查询字典项
+     *
+     * @param dictCode 顺序:tableName,text,code
+     * @param dictCode 要查询的key
+     * @return
+     */
+    @GetMapping("/getDictItems")
+    public List<DictModel> getDictItems(@RequestParam("dictCode") String dictCode) {
+        return sysBaseApi.getDictItems(dictCode);
+    }
+
+    /**
+     * 根据多个字典code查询多个字典项
+     *
+     * @param dictCodeList
+     * @return key = dictCode ; value=对应的字典项
+     */
+    @RequestMapping("/getManyDictItems")
+    public Map<String, List<DictModel>> getManyDictItems(@RequestParam("dictCodeList") List<String> dictCodeList) {
+        return sysBaseApi.getManyDictItems(dictCodeList);
+    }
+
+    /**
+     * 【下拉搜索】
+     * 大数据量的字典表 走异步加载,即前端输入内容过滤数据
+     *
+     * @param dictCode 字典code格式:table,text,code
+     * @param keyword  过滤关键字
+     * @return
+     */
+    @GetMapping("/loadDictItemByKeyword")
+    public List<DictModel> loadDictItemByKeyword(@RequestParam("dictCode") String dictCode, @RequestParam("keyword") String keyword, @RequestParam(value = "pageSize", required = false) Integer pageSize) {
+        return sysBaseApi.loadDictItemByKeyword(dictCode, keyword, pageSize);
+    }
+
+    /**
+     * 48 普通字典的翻译,根据多个dictCode和多条数据,多个以逗号分割
+     * @param dictCodes
+     * @param keys
+     * @return
+     */
+    @GetMapping("/translateManyDict")
+    public Map<String, List<DictModel>> translateManyDict(@RequestParam("dictCodes") String dictCodes, @RequestParam("keys") String keys){
+        return this.sysBaseApi.translateManyDict(dictCodes, keys);
+    }
+
+
+    /**
+     * 获取表数据字典 【接口签名验证】
+     * @param table
+     * @param text
+     * @param code
+     * @return
+     */
+    @GetMapping("/queryTableDictItemsByCode")
+    List<DictModel> queryTableDictItemsByCode(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code){
+        return sysBaseApi.queryTableDictItemsByCode(table, text, code);
+    }
+
+    /**
+     * 查询表字典 支持过滤数据 【接口签名验证】
+     * @param table
+     * @param text
+     * @param code
+     * @param filterSql
+     * @return
+     */
+    @GetMapping("/queryFilterTableDictInfo")
+    List<DictModel> queryFilterTableDictInfo(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("filterSql") String filterSql){
+        return sysBaseApi.queryFilterTableDictInfo(table, text, code, filterSql);
+    }
+
+    /**
+     * 【接口签名验证】
+     * 查询指定table的 text code 获取字典,包含text和value
+     * @param table
+     * @param text
+     * @param code
+     * @param keyArray
+     * @return
+     */
+    @Deprecated
+    @GetMapping("/queryTableDictByKeys")
+    public List<String> queryTableDictByKeys(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("keyArray") String[] keyArray){
+        return sysBaseApi.queryTableDictByKeys(table, text, code, keyArray);
+    }
+
+
+    /**
+     * 字典表的 翻译【接口签名验证】
+     * @param table
+     * @param text
+     * @param code
+     * @param key
+     * @return
+     */
+    @GetMapping("/translateDictFromTable")
+    public String translateDictFromTable(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("key") String key){
+        return sysBaseApi.translateDictFromTable(table, text, code, key);
+    }
+
+
+    /**
+     * 【接口签名验证】
+     * 49 字典表的 翻译,可批量
+     *
+     * @param table
+     * @param text
+     * @param code
+     * @param keys  多个用逗号分割
+     * @return
+     */
+    @GetMapping("/translateDictFromTableByKeys")
+    public List<DictModel> translateDictFromTableByKeys(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("keys") String keys) {
+        return this.sysBaseApi.translateDictFromTableByKeys(table, text, code, keys);
+    }
+
+    /**
+     * 发送模板信息
+     * @param message
+     */
+    @PostMapping("/sendTemplateMessage")
+    public void sendTemplateMessage(@RequestBody MessageDTO message){
+        sysBaseApi.sendTemplateMessage(message);
+    }
+
+    /**
+     * 获取消息模板内容
+     * @param code
+     * @return
+     */
+    @GetMapping("/getTemplateContent")
+    public String getTemplateContent(@RequestParam("code") String code){
+        return this.sysBaseApi.getTemplateContent(code);
+    }
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/controller/CasClientController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/controller/CasClientController.java
index 4da744a..4b271a6 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/controller/CasClientController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/controller/CasClientController.java
@@ -5,21 +5,17 @@ import java.util.List;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import cn.hutool.crypto.SecureUtil;
 import org.apache.commons.lang.StringUtils;
 import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.constant.CacheConstant;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.util.JwtUtil;
-import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.RedisUtil;
-import org.jeecg.modules.cas.util.CASServiceUtil;
+import org.jeecg.modules.cas.util.CasServiceUtil;
 import org.jeecg.modules.cas.util.XmlUtils;
 import org.jeecg.modules.system.entity.SysDepart;
 import org.jeecg.modules.system.entity.SysUser;
 import org.jeecg.modules.system.service.ISysDepartService;
 import org.jeecg.modules.system.service.ISysUserService;
-import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.HttpEntity;
@@ -65,7 +61,7 @@ public class CasClientController {
 		log.info("Rest api login.");
 		try {
 			String validateUrl = prefixUrl+"/p3/serviceValidate";
-			String res = CASServiceUtil.getSTValidate(validateUrl, ticket, service);
+			String res = CasServiceUtil.getStValidate(validateUrl, ticket, service);
 			log.info("res."+res);
 			final String error = XmlUtils.getTextForElement(res, "authenticationFailure");
 			if(StringUtils.isNotEmpty(error)) {
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/CasServiceUtil.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/CasServiceUtil.java
new file mode 100644
index 0000000..12fcec1
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/CasServiceUtil.java
@@ -0,0 +1,107 @@
+package org.jeecg.modules.cas.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
+/**
+ * @Description: CasServiceUtil
+ * @author: jeecg-boot
+ */
+public class CasServiceUtil {
+	
+	public static void main(String[] args) {
+		String serviceUrl = "https://cas.8f8.com.cn:8443/cas/p3/serviceValidate";
+		String service = "http://localhost:3003/user/login";
+		String ticket = "ST-5-1g-9cNES6KXNRwq-GuRET103sm0-DESKTOP-VKLS8B3";
+		String res = getStValidate(serviceUrl,ticket, service);
+		
+		System.out.println("---------res-----"+res);
+	}
+	
+	
+	/**
+     * 验证ST
+     */
+    public static String getStValidate(String url, String st, String service){
+		try {
+			url = url+"?service="+service+"&ticket="+st;
+			CloseableHttpClient httpclient = createHttpClientWithNoSsl();
+			HttpGet httpget = new HttpGet(url);
+			HttpResponse response = httpclient.execute(httpget);
+	        String res = readResponse(response);
+	        return res == null ? null : (res == "" ? null : res);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return "";
+	}
+
+    
+    /**
+     * 读取 response body 内容为字符串
+     *
+     * @param response
+     * @return
+     * @throws IOException
+     */
+    private static String readResponse(HttpResponse response) throws IOException {
+        BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+        String result = new String();
+        String line;
+        while ((line = in.readLine()) != null) {
+            result += line;
+        }
+        return result;
+    }
+    
+    
+    /**
+     * 创建模拟客户端(针对 https 客户端禁用 SSL 验证)
+     *
+     * @param cookieStore 缓存的 Cookies 信息
+     * @return
+     * @throws Exception
+     */
+    private static CloseableHttpClient createHttpClientWithNoSsl() throws Exception {
+        // Create a trust manager that does not validate certificate chains
+        TrustManager[] trustAllCerts = new TrustManager[]{
+                new X509TrustManager() {
+                    @Override
+                    public X509Certificate[] getAcceptedIssuers() {
+                        return null;
+                    }
+
+                    @Override
+                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
+                        // don't check
+                    }
+
+                    @Override
+                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
+                        // don't check
+                    }
+                }
+        };
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        ctx.init(null, trustAllCerts, null);
+        LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(ctx);
+        return HttpClients.custom()
+                .setSSLSocketFactory(sslSocketFactory)
+                .build();
+    }
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/XmlUtils.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/XmlUtils.java
index bcd7d64..408a100 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/XmlUtils.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/cas/util/XmlUtils.java
@@ -14,6 +14,7 @@ import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
+import org.jeecg.common.constant.CommonConstant;
 import org.w3c.dom.Document;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -31,6 +32,11 @@ import lombok.extern.slf4j.Slf4j;
 public final class XmlUtils {
 
     /**
+     * attributes
+     */
+    private static final String ATTRIBUTES = "attributes";
+
+    /**
      * Creates a new namespace-aware DOM document object by parsing the given XML.
      *
      * @param xml XML content.
@@ -218,9 +224,9 @@ public final class XmlUtils {
         }
 
         @Override
-        public void startElement(final String namespaceURI, final String localName, final String qName,
-                final Attributes attributes) throws SAXException {
-            if ("attributes".equals(localName)) {
+        public void startElement(final String nameSpaceUri, final String localName, final String qName,
+                                 final Attributes attributes) throws SAXException {
+            if (ATTRIBUTES.equals(localName)) {
                 this.foundAttributes = true;
             } else if (this.foundAttributes) {
                 this.value = new StringBuilder();
@@ -236,9 +242,9 @@ public final class XmlUtils {
         }
 
         @Override
-        public void endElement(final String namespaceURI, final String localName, final String qName)
+        public void endElement(final String nameSpaceUri, final String localName, final String qName)
                 throws SAXException {
-            if ("attributes".equals(localName)) {
+            if (ATTRIBUTES.equals(localName)) {
                 this.foundAttributes = false;
                 this.currentAttribute = null;
             } else if (this.foundAttributes) {
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/controller/SysMessageTemplateController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/controller/SysMessageTemplateController.java
index ec1ce07..3325b88 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/controller/SysMessageTemplateController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/controller/SysMessageTemplateController.java
@@ -6,9 +6,12 @@ import java.util.Map;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.jeecg.common.api.dto.message.MessageDTO;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.api.ISysBaseAPI;
 import org.jeecg.common.system.base.controller.JeecgController;
 import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.message.entity.MsgParams;
 import org.jeecg.modules.message.entity.SysMessageTemplate;
 import org.jeecg.modules.message.service.ISysMessageTemplateService;
@@ -46,6 +49,9 @@ public class SysMessageTemplateController extends JeecgController<SysMessageTemp
 	@Autowired
 	private PushMsgUtil pushMsgUtil;
 
+	@Autowired
+	private ISysBaseAPI sysBaseApi;
+
 	/**
 	 * 分页列表查询
 	 * 
@@ -152,19 +158,23 @@ public class SysMessageTemplateController extends JeecgController<SysMessageTemp
 	@PostMapping(value = "/sendMsg")
 	public Result<SysMessageTemplate> sendMessage(@RequestBody MsgParams msgParams) {
 		Result<SysMessageTemplate> result = new Result<SysMessageTemplate>();
-		Map<String, String> map = null;
 		try {
-			map = (Map<String, String>) JSON.parse(msgParams.getTestData());
+			MessageDTO md = new MessageDTO();
+			md.setToAll(false);
+			md.setTitle("消息发送测试");
+			md.setTemplateCode(msgParams.getTemplateCode());
+			md.setToUser(msgParams.getReceiver());
+			md.setType(msgParams.getMsgType());
+			String testData = msgParams.getTestData();
+			if(oConvertUtils.isNotEmpty(testData)){
+				Map<String, Object> data = JSON.parseObject(testData, Map.class);
+				md.setData(data);
+			}
+			sysBaseApi.sendTemplateMessage(md);
+			return result.success("消息发送成功!");
 		} catch (Exception e) {
-			result.error500("解析Json出错!");
-			return result;
-		}
-		boolean is_sendSuccess = pushMsgUtil.sendMessage(msgParams.getMsgType(), msgParams.getTemplateCode(), map, msgParams.getReceiver());
-		if (is_sendSuccess) {
-			result.success("发送消息任务添加成功!");
-		} else {
-			result.error500("发送消息任务添加失败!");
+			log.error("发送消息出错", e.getMessage());
+			return result.error500("发送消息出错!");
 		}
-		return result;
 	}
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/entity/SysMessage.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/entity/SysMessage.java
index 9faa53e..f3555e3 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/entity/SysMessage.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/entity/SysMessage.java
@@ -50,9 +50,11 @@ public class SysMessage extends JeecgEntity {
 	/**消息标题*/
 	@Excel(name = "消息标题", width = 15)
 	private java.lang.String esTitle;
-	/**推送方式:1短信 2邮件 3微信*/
-	@Excel(name = "推送方式:1短信 2邮件 3微信", width = 15)
-	@Dict(dicCode = "msgType")
+	/**
+	 * 推送方式:参考枚举类MessageTypeEnum
+	 */
+	@Excel(name = "推送方式", width = 15)
+	@Dict(dicCode = "messageType")
 	private java.lang.String esType;
 	/**备注*/
 	@Excel(name = "备注", width = 15)
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/entity/SysMessageTemplate.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/entity/SysMessageTemplate.java
index 929937a..1ea966e 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/entity/SysMessageTemplate.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/entity/SysMessageTemplate.java
@@ -35,4 +35,9 @@ public class SysMessageTemplate extends JeecgEntity{
 	/**模板类型*/
 	@Excel(name = "模板类型", width = 15)
 	private java.lang.String templateType;
+
+	/**已经应用/未应用  1是0否*/
+	@Excel(name = "应用状态", width = 15)
+	private String useStatus;
+
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/ISendMsgHandle.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/ISendMsgHandle.java
index 1be8274..a58300c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/ISendMsgHandle.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/ISendMsgHandle.java
@@ -1,5 +1,7 @@
 package org.jeecg.modules.message.handle;
 
+import org.jeecg.common.api.dto.message.MessageDTO;
+
 /**
  * @Description: 发送信息接口
  * @author: jeecg-boot
@@ -8,9 +10,17 @@ public interface ISendMsgHandle {
 
     /**
      * 发送信息
-     * @param es_receiver 发送人
-     * @param es_title 标题
-     * @param es_content 内容
+     * @param esReceiver 发送人
+     * @param esTitle 标题
+     * @param esContent 内容
+     */
+	void sendMsg(String esReceiver, String esTitle, String esContent);
+
+    /**
+     * 发送信息
+     * @param messageDTO
      */
-	void SendMsg(String es_receiver, String es_title, String es_content);
+	default void sendMessage(MessageDTO messageDTO){
+
+    }
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/DdSendMsgHandle.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/DdSendMsgHandle.java
new file mode 100644
index 0000000..e6741de
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/DdSendMsgHandle.java
@@ -0,0 +1,37 @@
+package org.jeecg.modules.message.handle.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.dto.message.MessageDTO;
+import org.jeecg.modules.message.handle.ISendMsgHandle;
+import org.jeecg.modules.system.service.impl.ThirdAppDingtalkServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Description: 发钉钉消息模板
+ * @author: jeecg-boot
+ */
+@Slf4j
+@Component("ddSendMsgHandle")
+public class DdSendMsgHandle implements ISendMsgHandle {
+
+	@Autowired
+	private ThirdAppDingtalkServiceImpl dingtalkService;
+
+	@Override
+	public void sendMsg(String esReceiver, String esTitle, String esContent) {
+		log.info("发微信消息模板");
+		MessageDTO messageDTO = new MessageDTO();
+		messageDTO.setToUser(esReceiver);
+		messageDTO.setTitle(esTitle);
+		messageDTO.setContent(esContent);
+		messageDTO.setToAll(false);
+		sendMessage(messageDTO);
+	}
+
+	@Override
+	public void sendMessage(MessageDTO messageDTO) {
+		dingtalkService.sendMessage(messageDTO, true);
+	}
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/EmailSendMsgHandle.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/EmailSendMsgHandle.java
index 92addb1..828d878 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/EmailSendMsgHandle.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/EmailSendMsgHandle.java
@@ -1,20 +1,34 @@
 package org.jeecg.modules.message.handle.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.dto.message.MessageDTO;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.util.RedisUtil;
 import org.jeecg.common.util.SpringContextUtils;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.config.StaticConfig;
 import org.jeecg.modules.message.handle.ISendMsgHandle;
-import org.springframework.mail.SimpleMailMessage;
+import org.jeecg.modules.system.entity.SysUser;
+import org.jeecg.modules.system.mapper.SysUserMapper;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.stereotype.Component;
 
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.List;
 
 /**
  * @Description: 邮箱发送信息
  * @author: jeecg-boot
  */
+@Slf4j
+@Component("emailSendMsgHandle")
 public class EmailSendMsgHandle implements ISendMsgHandle {
     static String emailFrom;
 
@@ -22,8 +36,16 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
         EmailSendMsgHandle.emailFrom = emailFrom;
     }
 
+    @Autowired
+    SysUserMapper sysUserMapper;
+
+    @Autowired
+    private RedisUtil redisUtil;
+
+
+
     @Override
-    public void SendMsg(String es_receiver, String es_title, String es_content) {
+    public void sendMsg(String esReceiver, String esTitle, String esContent) {
         JavaMailSender mailSender = (JavaMailSender) SpringContextUtils.getBean("mailSender");
         MimeMessage message = mailSender.createMimeMessage();
         MimeMessageHelper helper = null;
@@ -37,13 +59,53 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
             helper = new MimeMessageHelper(message, true);
             // 设置发送方邮箱地址
             helper.setFrom(emailFrom);
-            helper.setTo(es_receiver);
-            helper.setSubject(es_title);
-            helper.setText(es_content, true);
+            helper.setTo(esReceiver);
+            helper.setSubject(esTitle);
+            helper.setText(esContent, true);
             mailSender.send(message);
         } catch (MessagingException e) {
             e.printStackTrace();
         }
 
     }
+
+    @Override
+    public void sendMessage(MessageDTO messageDTO) {
+        String[] arr = messageDTO.getToUser().split(",");
+        LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<SysUser>().in(SysUser::getUsername, arr);
+        List<SysUser> list = sysUserMapper.selectList(query);
+        String content = messageDTO.getContent();
+        String title = messageDTO.getTitle();
+        for(SysUser user: list){
+            String email = user.getEmail();
+            if(email==null || "".equals(email)){
+                continue;
+            }
+
+            if(content.indexOf(CommonConstant.LOGIN_TOKEN)>0){
+                String token = getToken(user);
+                try {
+                    content = content.replace(CommonConstant.LOGIN_TOKEN, URLEncoder.encode(token, "UTF-8"));
+                } catch (UnsupportedEncodingException e) {
+                    log.error("邮件消息token编码失败", e.getMessage());
+                }
+            }
+            log.info("邮件内容:"+ content);
+            sendMsg(email, title, content);
+        }
+    }
+
+    /**
+     * 获取token
+     * @param user
+     * @return
+     */
+    private String getToken(SysUser user) {
+        // 生成token
+        String token = JwtUtil.sign(user.getUsername(), user.getPassword());
+        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
+        // 设置超时时间 1个小时
+        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 1 / 1000);
+        return token;
+    }
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/QywxSendMsgHandle.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/QywxSendMsgHandle.java
new file mode 100644
index 0000000..46afeb6
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/QywxSendMsgHandle.java
@@ -0,0 +1,37 @@
+package org.jeecg.modules.message.handle.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.dto.message.MessageDTO;
+import org.jeecg.modules.message.handle.ISendMsgHandle;
+import org.jeecg.modules.system.service.impl.ThirdAppWechatEnterpriseServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Description: 发企业微信消息模板
+ * @author: jeecg-boot
+ */
+@Slf4j
+@Component("qywxSendMsgHandle")
+public class QywxSendMsgHandle implements ISendMsgHandle {
+
+	@Autowired
+	private ThirdAppWechatEnterpriseServiceImpl wechatEnterpriseService;
+
+	@Override
+	public void sendMsg(String esReceiver, String esTitle, String esContent) {
+		log.info("发微信消息模板");
+		MessageDTO messageDTO = new MessageDTO();
+		messageDTO.setToUser(esReceiver);
+		messageDTO.setTitle(esTitle);
+		messageDTO.setContent(esContent);
+		messageDTO.setToAll(false);
+		sendMessage(messageDTO);
+	}
+
+	@Override
+	public void sendMessage(MessageDTO messageDTO) {
+		wechatEnterpriseService.sendMessage(messageDTO, true);
+	}
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/SmsSendMsgHandle.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/SmsSendMsgHandle.java
index c08ac2d..5063ddf 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/SmsSendMsgHandle.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/SmsSendMsgHandle.java
@@ -11,7 +11,7 @@ import org.jeecg.modules.message.handle.ISendMsgHandle;
 public class SmsSendMsgHandle implements ISendMsgHandle {
 
 	@Override
-	public void SendMsg(String es_receiver, String es_title, String es_content) {
+	public void sendMsg(String esReceiver, String esTitle, String esContent) {
 		// TODO Auto-generated method stub
 		log.info("发短信");
 	}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/SystemSendMsgHandle.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/SystemSendMsgHandle.java
index 0ad5007..7a2d2ef 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/SystemSendMsgHandle.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/SystemSendMsgHandle.java
@@ -1,28 +1,129 @@
 package org.jeecg.modules.message.handle.impl;
 
+import com.alibaba.fastjson.JSONObject;
 import org.jeecg.common.api.dto.message.MessageDTO;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.WebsocketConst;
 import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.system.api.ISysBaseAPI;
 import org.jeecg.common.util.SpringContextUtils;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.message.handle.ISendMsgHandle;
+import org.jeecg.modules.message.websocket.WebSocket;
+import org.jeecg.modules.system.entity.SysAnnouncement;
+import org.jeecg.modules.system.entity.SysAnnouncementSend;
+import org.jeecg.modules.system.entity.SysUser;
+import org.jeecg.modules.system.mapper.SysAnnouncementMapper;
+import org.jeecg.modules.system.mapper.SysAnnouncementSendMapper;
+import org.jeecg.modules.system.mapper.SysUserMapper;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.Map;
 
 /**
 * @Description: 发送系统消息
 * @Author: wangshuai
 * @Date: 2022年3月22日 18:48:20
 */
+@Component("systemSendMsgHandle")
 public class SystemSendMsgHandle implements ISendMsgHandle {
 
     public static final String FROM_USER="system";
 
+    @Resource
+    private SysAnnouncementMapper sysAnnouncementMapper;
+
+    @Resource
+    private SysUserMapper userMapper;
+
+    @Resource
+    private SysAnnouncementSendMapper sysAnnouncementSendMapper;
+
+    @Resource
+    private WebSocket webSocket;
+
+    /**
+     * 该方法会发送3种消息:系统消息、企业微信 钉钉
+     * @param esReceiver 发送人
+     * @param esTitle 标题
+     * @param esContent 内容
+     */
     @Override
-    public void SendMsg(String es_receiver, String es_title, String es_content) {
-        if(oConvertUtils.isEmpty(es_receiver)){
+    public void sendMsg(String esReceiver, String esTitle, String esContent) {
+        if(oConvertUtils.isEmpty(esReceiver)){
             throw  new JeecgBootException("被发送人不能为空");
         }
-        ISysBaseAPI sysBaseAPI = SpringContextUtils.getBean(ISysBaseAPI.class);
-        MessageDTO messageDTO = new MessageDTO(FROM_USER,es_receiver,es_title,es_content);
-        sysBaseAPI.sendSysAnnouncement(messageDTO);
+        ISysBaseAPI sysBaseApi = SpringContextUtils.getBean(ISysBaseAPI.class);
+        MessageDTO messageDTO = new MessageDTO(FROM_USER,esReceiver,esTitle,esContent);
+        sysBaseApi.sendSysAnnouncement(messageDTO);
+    }
+
+    /**
+     * 仅发送系统消息
+     * @param messageDTO
+     */
+    @Override
+    public void sendMessage(MessageDTO messageDTO) {
+        //原方法不支持 sysBaseApi.sendSysAnnouncement(messageDTO);  有企业微信消息逻辑,
+        String title = messageDTO.getTitle();
+        String content = messageDTO.getContent();
+        String fromUser = messageDTO.getFromUser();
+        Map<String,Object> data = messageDTO.getData();
+        String[] arr = messageDTO.getToUser().split(",");
+        for(String username: arr){
+            doSend(title, content, fromUser, username, data);
+        }
+    }
+
+    private void doSend(String title, String msgContent, String fromUser, String toUser, Map<String, Object> data){
+        SysAnnouncement announcement = new SysAnnouncement();
+        if(data!=null){
+            //摘要信息
+            Object msgAbstract = data.get(CommonConstant.NOTICE_MSG_SUMMARY);
+            if(msgAbstract!=null){
+                announcement.setMsgAbstract(msgAbstract.toString());
+            }
+            // 任务节点ID
+            Object taskId = data.get(CommonConstant.NOTICE_MSG_BUS_ID);
+            if(taskId!=null){
+                announcement.setBusId(taskId.toString());
+            }
+        }
+        announcement.setTitile(title);
+        announcement.setMsgContent(msgContent);
+        announcement.setSender(fromUser);
+        announcement.setPriority(CommonConstant.PRIORITY_M);
+        announcement.setMsgType(CommonConstant.MSG_TYPE_UESR);
+        announcement.setSendStatus(CommonConstant.HAS_SEND);
+        announcement.setSendTime(new Date());
+        //系统消息
+        announcement.setMsgCategory("2");
+        announcement.setDelFlag(String.valueOf(CommonConstant.DEL_FLAG_0));
+        sysAnnouncementMapper.insert(announcement);
+        // 2.插入用户通告阅读标记表记录
+        String userId = toUser;
+        String[] userIds = userId.split(",");
+        String anntId = announcement.getId();
+        for(int i=0;i<userIds.length;i++) {
+            if(oConvertUtils.isNotEmpty(userIds[i])) {
+                SysUser sysUser = userMapper.getUserByName(userIds[i]);
+                if(sysUser==null) {
+                    continue;
+                }
+                SysAnnouncementSend announcementSend = new SysAnnouncementSend();
+                announcementSend.setAnntId(anntId);
+                announcementSend.setUserId(sysUser.getId());
+                announcementSend.setReadFlag(CommonConstant.NO_READ_FLAG);
+                sysAnnouncementSendMapper.insert(announcementSend);
+                JSONObject obj = new JSONObject();
+                obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_USER);
+                obj.put(WebsocketConst.MSG_USER_ID, sysUser.getId());
+                obj.put(WebsocketConst.MSG_ID, announcement.getId());
+                obj.put(WebsocketConst.MSG_TXT, announcement.getTitile());
+                webSocket.sendMessage(sysUser.getId(), obj.toJSONString());
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/WxSendMsgHandle.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/WxSendMsgHandle.java
index a1d76f7..8181cfa 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/WxSendMsgHandle.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/handle/impl/WxSendMsgHandle.java
@@ -11,7 +11,7 @@ import org.jeecg.modules.message.handle.ISendMsgHandle;
 public class WxSendMsgHandle implements ISendMsgHandle {
 
 	@Override
-	public void SendMsg(String es_receiver, String es_title, String es_content) {
+	public void sendMsg(String esReceiver, String esTitle, String esContent) {
 		// TODO Auto-generated method stub
 		log.info("发微信消息模板");
 	}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/job/SendMsgJob.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/job/SendMsgJob.java
index 6230074..7be7085 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/job/SendMsgJob.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/message/job/SendMsgJob.java
@@ -1,21 +1,19 @@
 package org.jeecg.modules.message.job;
 
-import java.util.List;
-
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.dto.message.MessageDTO;
+import org.jeecg.common.system.api.ISysBaseAPI;
 import org.jeecg.common.util.DateUtils;
 import org.jeecg.modules.message.entity.SysMessage;
-import org.jeecg.modules.message.handle.ISendMsgHandle;
 import org.jeecg.modules.message.handle.enums.SendMsgStatusEnum;
-import org.jeecg.modules.message.handle.enums.SendMsgTypeEnum;
 import org.jeecg.modules.message.service.ISysMessageService;
 import org.quartz.Job;
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
 import org.springframework.beans.factory.annotation.Autowired;
 
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-
-import lombok.extern.slf4j.Slf4j;
+import java.util.List;
 
 /**
  * 发送消息任务
@@ -28,6 +26,9 @@ public class SendMsgJob implements Job {
 	@Autowired
 	private ISysMessageService sysMessageService;
 
+	@Autowired
+	private ISysBaseAPI sysBaseAPI;
+
 	@Override
 	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
 
@@ -41,32 +42,19 @@ public class SendMsgJob implements Job {
 		System.out.println(sysMessages);
 		// 2.根据不同的类型走不通的发送实现类
 		for (SysMessage sysMessage : sysMessages) {
-			ISendMsgHandle sendMsgHandle = null;
-			try {
-				if (sysMessage.getEsType().equals(SendMsgTypeEnum.EMAIL.getType())) {
-					sendMsgHandle = (ISendMsgHandle) Class.forName(SendMsgTypeEnum.EMAIL.getImplClass()).newInstance();
-				} else if (sysMessage.getEsType().equals(SendMsgTypeEnum.SMS.getType())) {
-					sendMsgHandle = (ISendMsgHandle) Class.forName(SendMsgTypeEnum.SMS.getImplClass()).newInstance();
-				} else if (sysMessage.getEsType().equals(SendMsgTypeEnum.WX.getType())) {
-					sendMsgHandle = (ISendMsgHandle) Class.forName(SendMsgTypeEnum.WX.getImplClass()).newInstance();
-				} else if(sysMessage.getEsType().equals(SendMsgTypeEnum.SYSTEM_MESSAGE.getType())){
-                    //update-begin---author:wangshuai ---date:20220323  for:[issues/I4X698]根据模板发送系统消息,发送失败------------
-				    sendMsgHandle = (ISendMsgHandle) Class.forName(SendMsgTypeEnum.SYSTEM_MESSAGE.getImplClass()).newInstance();
-                    //update-end---author:wangshuai ---date:20220323  for:[issues/I4X698]根据模板发送系统消息,发送失败------------
-				}
-			} catch (Exception e) {
-				log.error(e.getMessage(),e);
-			}
+			//update-begin-author:taoyan date:2022-7-8 for: 模板消息发送测试调用方法修改
 			Integer sendNum = sysMessage.getEsSendNum();
 			try {
-                //update-begin---author:wangshuai ---date:20220323  for:[issues/I4X698]模板管理发送消息出现NullPointerException 錯誤------------
-                if(null != sendMsgHandle){
-                    sendMsgHandle.SendMsg(sysMessage.getEsReceiver(), sysMessage.getEsTitle(),
-                            sysMessage.getEsContent().toString());
-                    //发送消息成功
-                    sysMessage.setEsSendStatus(SendMsgStatusEnum.SUCCESS.getCode());
-                }
-                //update-end---author:wangshuai ---date:20220323  for:[issues/I4X698]模板管理发送消息出现NullPointerException 錯誤------------
+				MessageDTO md = new MessageDTO();
+				md.setTitle(sysMessage.getEsTitle());
+				md.setContent(sysMessage.getEsContent());
+				md.setToUser(sysMessage.getEsReceiver());
+				md.setType(sysMessage.getEsType());
+				md.setToAll(false);
+				sysBaseAPI.sendTemplateMessage(md);
+				//发送消息成功
+				sysMessage.setEsSendStatus(SendMsgStatusEnum.SUCCESS.getCode());
+				//update-end-author:taoyan date:2022-7-8 for: 模板消息发送测试调用方法修改
 			} catch (Exception e) {
 				e.printStackTrace();
 				// 发送消息出现异常
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java
index 5ab7213..5bdcb45 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java
@@ -12,6 +12,7 @@ import cn.hutool.core.date.DateUtil;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.google.common.collect.Maps;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.monitor.domain.RedisInfo;
 import org.jeecg.modules.monitor.exception.RedisConnectException;
@@ -34,6 +35,11 @@ public class RedisServiceImpl implements RedisService {
 	@Resource
 	private RedisConnectionFactory redisConnectionFactory;
 
+    /**
+     * redis信息
+     */
+    private static final String REDIS_MESSAGE = "3";
+
 	/**
 	 * Redis详细信息
 	 */
@@ -88,7 +94,7 @@ public class RedisServiceImpl implements RedisService {
 	public Map<String, JSONArray> getMapForReport(String type)  throws RedisConnectException {
 		Map<String,JSONArray> mapJson=new HashMap(5);
 		JSONArray json = new JSONArray();
-		if("3".equals(type)){
+		if(REDIS_MESSAGE.equals(type)){
 			List<RedisInfo> redisInfo = getRedisInfo();
 			for(RedisInfo info:redisInfo){
 				Map<String, Object> map= Maps.newHashMap();
@@ -101,7 +107,8 @@ public class RedisServiceImpl implements RedisService {
 			mapJson.put("data",json);
 			return mapJson;
 		}
-		for(int i = 0; i < 5; i++){
+		int length = 5;
+		for(int i = 0; i < length; i++){
 			JSONObject jo = new JSONObject();
 			Map<String, Object> map;
 			if("1".equals(type)){
@@ -109,11 +116,11 @@ public class RedisServiceImpl implements RedisService {
 				jo.put("value",map.get("dbSize"));
 			}else{
 				map = getMemoryInfo();
-				Integer used_memory = Integer.valueOf(map.get("used_memory").toString());
-				jo.put("value",used_memory/1000);
+				Integer usedMemory = Integer.valueOf(map.get("used_memory").toString());
+				jo.put("value",usedMemory/1000);
 			}
-			String create_time = DateUtil.formatTime(DateUtil.date((Long) map.get("create_time")-(4-i)*1000));
-			jo.put("name",create_time);
+			String createTime = DateUtil.formatTime(DateUtil.date((Long) map.get("create_time")-(4-i)*1000));
+			jo.put("name",createTime);
 			json.add(jo);
 		}
 		mapJson.put("data",json);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/service/impl/NgAlainServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/service/impl/NgAlainServiceImpl.java
index 6e93496..bcad44a 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/service/impl/NgAlainServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/service/impl/NgAlainServiceImpl.java
@@ -2,6 +2,8 @@ package org.jeecg.modules.ngalain.service.impl;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.ngalain.service.NgAlainService;
 import org.jeecg.modules.system.entity.SysPermission;
@@ -123,12 +125,13 @@ public class NgAlainServiceImpl implements NgAlainService {
     private JSONObject getPermissionJsonObject(SysPermission permission) {
         JSONObject json = new JSONObject();
         //类型(0:一级菜单 1:子菜单  2:按钮)
-        if(permission.getMenuType()==2) {
+        if(CommonConstant.MENU_TYPE_2.equals(permission.getMenuType())) {
             json.put("action", permission.getPerms());
             json.put("describe", permission.getName());
-        }else if(permission.getMenuType()==0||permission.getMenuType()==1) {
+        }else if(CommonConstant.MENU_TYPE_0.equals(permission.getMenuType()) || CommonConstant.MENU_TYPE_1.equals(permission.getMenuType())) {
             json.put("id", permission.getId());
-            if(permission.getUrl()!=null&&(permission.getUrl().startsWith("http://")||permission.getUrl().startsWith("https://"))) {
+            boolean flag = permission.getUrl()!=null&&(permission.getUrl().startsWith(CommonConstant.HTTP_PROTOCOL)||permission.getUrl().startsWith(CommonConstant.HTTPS_PROTOCOL));
+            if(flag) {
                 String url= new String(Base64.getUrlEncoder().encode(permission.getUrl().getBytes()));
                 json.put("path", "/sys/link/" +url.replaceAll("=",""));
             }else {
@@ -156,7 +159,7 @@ public class NgAlainServiceImpl implements NgAlainService {
             }else {
                 meta.put("icon", oConvertUtils.getString(permission.getIcon(), ""));
             }
-            if(permission.getUrl()!=null&&(permission.getUrl().startsWith("http://")||permission.getUrl().startsWith("https://"))) {
+            if(flag) {
                 meta.put("url", permission.getUrl());
             }
             json.put("meta", meta);
@@ -172,7 +175,7 @@ public class NgAlainServiceImpl implements NgAlainService {
      */
     private String urlToRouteName(String url) {
         if(oConvertUtils.isNotEmpty(url)) {
-            if(url.startsWith("/")) {
+            if(url.startsWith(SymbolConstant.SINGLE_SLASH)) {
                 url = url.substring(1);
             }
             url = url.replace("/", "-");
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/controller/OssFileController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/controller/OssFileController.java
new file mode 100644
index 0000000..7939759
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/controller/OssFileController.java
@@ -0,0 +1,95 @@
+package org.jeecg.modules.oss.controller;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.shiro.authz.annotation.RequiresRoles;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.oss.entity.OssFile;
+import org.jeecg.modules.oss.service.IOssFileService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 云存储示例 DEMO
+ * @author: jeecg-boot
+ */
+@Slf4j
+@Controller
+@RequestMapping("/sys/oss/file")
+public class OssFileController {
+
+	@Autowired
+	private IOssFileService ossFileService;
+
+	@ResponseBody
+	@GetMapping("/list")
+	public Result<IPage<OssFile>> queryPageList(OssFile file,
+                                                @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
+		Result<IPage<OssFile>> result = new Result<>();
+		QueryWrapper<OssFile> queryWrapper = QueryGenerator.initQueryWrapper(file, req.getParameterMap());
+		Page<OssFile> page = new Page<>(pageNo, pageSize);
+		IPage<OssFile> pageList = ossFileService.page(page, queryWrapper);
+		result.setSuccess(true);
+		result.setResult(pageList);
+		return result;
+	}
+
+	@ResponseBody
+	@PostMapping("/upload")
+	//@RequiresRoles("admin")
+	public Result upload(@RequestParam("file") MultipartFile multipartFile) {
+		Result result = new Result();
+		try {
+			ossFileService.upload(multipartFile);
+			result.success("上传成功!");
+		}
+		catch (Exception ex) {
+			log.info(ex.getMessage(), ex);
+			result.error500("上传失败");
+		}
+		return result;
+	}
+
+	@ResponseBody
+	@DeleteMapping("/delete")
+	public Result delete(@RequestParam(name = "id") String id) {
+		Result result = new Result();
+		OssFile file = ossFileService.getById(id);
+		if (file == null) {
+			result.error500("未找到对应实体");
+		}else {
+			boolean ok = ossFileService.delete(file);
+			result.success("删除成功!");
+		}
+		return result;
+	}
+
+	/**
+	 * 通过id查询.
+	 */
+	@ResponseBody
+	@GetMapping("/queryById")
+	public Result<OssFile> queryById(@RequestParam(name = "id") String id) {
+		Result<OssFile> result = new Result<>();
+		OssFile file = ossFileService.getById(id);
+		if (file == null) {
+			result.error500("未找到对应实体");
+		}
+		else {
+			result.setResult(file);
+			result.setSuccess(true);
+		}
+		return result;
+	}
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/entity/OssFile.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/entity/OssFile.java
new file mode 100644
index 0000000..ba4e073
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/entity/OssFile.java
@@ -0,0 +1,28 @@
+package org.jeecg.modules.oss.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.system.base.entity.JeecgEntity;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+/**
+ * @Description: oss云存储实体类
+ * @author: jeecg-boot
+ */
+@Data
+@TableName("oss_file")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class OssFile extends JeecgEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Excel(name = "文件名称")
+	private String fileName;
+
+	@Excel(name = "文件地址")
+	private String url;
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/mapper/OssFileMapper.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/mapper/OssFileMapper.java
new file mode 100644
index 0000000..36a9955
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/mapper/OssFileMapper.java
@@ -0,0 +1,12 @@
+package org.jeecg.modules.oss.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.oss.entity.OssFile;
+
+/**
+ * @Description: oss云存储Mapper
+ * @author: jeecg-boot
+ */
+public interface OssFileMapper extends BaseMapper<OssFile> {
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/service/IOssFileService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/service/IOssFileService.java
new file mode 100644
index 0000000..8a82a48
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/service/IOssFileService.java
@@ -0,0 +1,29 @@
+package org.jeecg.modules.oss.service;
+
+import java.io.IOException;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.oss.entity.OssFile;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * @Description: OOS云存储service接口
+ * @author: jeecg-boot
+ */
+public interface IOssFileService extends IService<OssFile> {
+
+    /**
+     * oss文件上传
+     * @param multipartFile
+     * @throws IOException
+     */
+	void upload(MultipartFile multipartFile) throws IOException;
+
+    /**
+     * oss文件删除
+     * @param ossFile OSSFile对象
+     * @return
+     */
+	boolean delete(OssFile ossFile);
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/service/impl/OssFileServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/service/impl/OssFileServiceImpl.java
new file mode 100644
index 0000000..539d90f
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/oss/service/impl/OssFileServiceImpl.java
@@ -0,0 +1,48 @@
+package org.jeecg.modules.oss.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.common.util.CommonUtils;
+import org.jeecg.common.util.oss.OssBootUtil;
+import org.jeecg.modules.oss.entity.OssFile;
+import org.jeecg.modules.oss.mapper.OssFileMapper;
+import org.jeecg.modules.oss.service.IOssFileService;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+/**
+ * @Description: OSS云存储实现类
+ * @author: jeecg-boot
+ */
+@Service("ossFileService")
+public class OssFileServiceImpl extends ServiceImpl<OssFileMapper, OssFile> implements IOssFileService {
+
+	@Override
+	public void upload(MultipartFile multipartFile) throws IOException {
+		String fileName = multipartFile.getOriginalFilename();
+		fileName = CommonUtils.getFileName(fileName);
+		OssFile ossFile = new OssFile();
+		ossFile.setFileName(fileName);
+		String url = OssBootUtil.upload(multipartFile,"upload/test");
+		//update-begin--Author:scott  Date:20201227 for:JT-361【文件预览】阿里云原生域名可以文件预览,自己映射域名kkfileview提示文件下载失败-------------------
+		// 返回阿里云原生域名前缀URL
+		ossFile.setUrl(OssBootUtil.getOriginalUrl(url));
+		//update-end--Author:scott  Date:20201227 for:JT-361【文件预览】阿里云原生域名可以文件预览,自己映射域名kkfileview提示文件下载失败-------------------
+		this.save(ossFile);
+	}
+
+	@Override
+	public boolean delete(OssFile ossFile) {
+		try {
+			this.removeById(ossFile.getId());
+			OssBootUtil.deleteUrl(ossFile.getUrl());
+		}
+		catch (Exception ex) {
+			log.error(ex.getMessage(),ex);
+			return false;
+		}
+		return true;
+	}
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java
index 881e8ae..d61c720 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java
@@ -10,6 +10,7 @@ import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authz.annotation.RequiresRoles;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.ImportExcelUtil;
@@ -132,7 +133,7 @@ public class QuartzJobController {
 		if (ids == null || "".equals(ids.trim())) {
 			return Result.error("参数不识别!");
 		}
-		for (String id : Arrays.asList(ids.split(","))) {
+		for (String id : Arrays.asList(ids.split(SymbolConstant.COMMA))) {
 			QuartzJob job = quartzJobService.getById(id);
 			quartzJobService.deleteAndStopJob(job);
 		}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/CommonController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/CommonController.java
index 760efa2..24c4a77 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/CommonController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/CommonController.java
@@ -5,8 +5,8 @@ import com.alibaba.fastjson.JSONObject;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.exception.JeecgBootException;
-import org.jeecg.common.system.api.ISysBaseAPI;
 import org.jeecg.common.util.CommonUtils;
 import org.jeecg.common.util.RestUtil;
 import org.jeecg.common.util.TokenUtils;
@@ -72,8 +72,10 @@ public class CommonController {
         String bizPath = request.getParameter("biz");
 
         //LOWCOD-2580 sys/common/upload接口存在任意文件上传漏洞
-        if (oConvertUtils.isNotEmpty(bizPath) && (bizPath.contains("../") || bizPath.contains("..\\"))) {
-            throw new JeecgBootException("上传目录bizPath,格式非法!");
+        if (oConvertUtils.isNotEmpty(bizPath)) {
+            if(bizPath.contains(SymbolConstant.SPOT_SINGLE_SLASH) || bizPath.contains(SymbolConstant.SPOT_DOUBLE_BACKSLASH)){
+                throw new JeecgBootException("上传目录bizPath,格式非法!");
+            }
         }
 
         MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
@@ -138,7 +140,7 @@ public class CommonController {
             // 获取文件名
             String orgName = mf.getOriginalFilename();
             orgName = CommonUtils.getFileName(orgName);
-            if(orgName.indexOf(".")!=-1){
+            if(orgName.indexOf(SymbolConstant.SPOT)!=-1){
                 fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."));
             }else{
                 fileName = orgName+ "_" + System.currentTimeMillis();
@@ -152,8 +154,8 @@ public class CommonController {
             }else{
                 dbpath = fileName;
             }
-            if (dbpath.contains("\\")) {
-                dbpath = dbpath.replace("\\", "/");
+            if (dbpath.contains(SymbolConstant.DOUBLE_BACKSLASH)) {
+                dbpath = dbpath.replace(SymbolConstant.DOUBLE_BACKSLASH, SymbolConstant.SINGLE_SLASH);
             }
             return dbpath;
         } catch (IOException e) {
@@ -210,7 +212,7 @@ public class CommonController {
     public void view(HttpServletRequest request, HttpServletResponse response) {
         // ISO-8859-1 ==> UTF-8 进行编码转换
         String imgPath = extractPathFromPattern(request);
-        if(oConvertUtils.isEmpty(imgPath) || imgPath=="null"){
+        if(oConvertUtils.isEmpty(imgPath) || CommonConstant.STRING_NULL.equals(imgPath)){
             return;
         }
         // 其余处理略
@@ -218,7 +220,7 @@ public class CommonController {
         OutputStream outputStream = null;
         try {
             imgPath = imgPath.replace("..", "").replace("../","");
-            if (imgPath.endsWith(",")) {
+            if (imgPath.endsWith(SymbolConstant.COMMA)) {
                 imgPath = imgPath.substring(0, imgPath.length() - 1);
             }
             String filePath = uploadpath + File.separator + imgPath;
@@ -349,7 +351,7 @@ public class CommonController {
      * @return
      */
     @RequestMapping("/transitRESTful")
-    public Result transitRESTful(@RequestParam("url") String url, HttpServletRequest request) {
+    public Result transitRestful(@RequestParam("url") String url, HttpServletRequest request) {
         try {
             ServletServerHttpRequest httpRequest = new ServletServerHttpRequest(request);
             // 中转请求method、body
@@ -368,8 +370,8 @@ public class CommonController {
             HttpHeaders headers = new HttpHeaders();
             headers.set("X-Access-Token", token);
             // 发送请求
-            String httpURL = URLDecoder.decode(url, "UTF-8");
-            ResponseEntity<String> response = RestUtil.request(httpURL, method, headers , variables, params, String.class);
+            String httpUrl = URLDecoder.decode(url, "UTF-8");
+            ResponseEntity<String> response = RestUtil.request(httpUrl, method, headers , variables, params, String.class);
             // 封装返回结果
             Result<Object> result = new Result<>();
             int statusCode = response.getStatusCodeValue();
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java
index b8490ec..18341cf 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java
@@ -12,12 +12,14 @@ import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CacheConstant;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.system.util.JwtUtil;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.*;
 import org.jeecg.common.util.encryption.EncryptedString;
 import org.jeecg.modules.base.service.BaseCommonService;
 import org.jeecg.modules.system.entity.SysDepart;
+import org.jeecg.modules.system.entity.SysRoleIndex;
 import org.jeecg.modules.system.entity.SysTenant;
 import org.jeecg.modules.system.entity.SysUser;
 import org.jeecg.modules.system.model.SysLoginModel;
@@ -26,6 +28,7 @@ import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
 import org.jeecg.modules.system.util.RandImageUtil;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
@@ -59,6 +62,8 @@ public class LoginController {
 	@Resource
 	private BaseCommonService baseCommonService;
 
+	private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
+
 	@ApiOperation("登录接口")
 	@RequestMapping(value = "/login", method = RequestMethod.POST)
 	public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel){
@@ -83,6 +88,8 @@ public class LoginController {
 		if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
             log.warn("验证码错误,key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
 			result.error500("验证码错误");
+			// 改成特殊的code 便于前端判断
+			result.setCode(HttpStatus.PRECONDITION_FAILED.value());
 			return result;
 		}
 		//update-end-author:taoyan date:20190828 for:校验验证码
@@ -97,7 +104,7 @@ public class LoginController {
 		if(!result.isSuccess()) {
 			return result;
 		}
-		
+
 		//2. 校验用户名或密码是否正确
 		String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
 		String syspassword = sysUser.getPassword();
@@ -130,6 +137,21 @@ public class LoginController {
 			// 根据用户名查询用户信息
 			SysUser sysUser = sysUserService.getUserByName(username);
 			JSONObject obj=new JSONObject();
+
+			//update-begin---author:scott ---date:2022-06-20  for:vue3前端,支持自定义首页-----------
+			String version = request.getHeader(CommonConstant.VERSION);
+			//update-begin---author:liusq ---date:2022-06-29  for:接口返回值修改,同步修改这里的判断逻辑-----------
+			SysRoleIndex roleIndex = sysUserService.getDynamicIndexByUserRole(username, version);
+			if (oConvertUtils.isNotEmpty(version) && roleIndex != null && oConvertUtils.isNotEmpty(roleIndex.getUrl())) {
+				String homePath = roleIndex.getUrl();
+				if (!homePath.startsWith(SymbolConstant.SINGLE_SLASH)) {
+					homePath = SymbolConstant.SINGLE_SLASH + homePath;
+				}
+				sysUser.setHomePath(homePath);
+			}
+			//update-begin---author:liusq ---date:2022-06-29  for:接口返回值修改,同步修改这里的判断逻辑-----------
+			//update-end---author:scott ---date::2022-06-20  for:vue3前端,支持自定义首页--------------
+			
 			obj.put("userInfo",sysUser);
 			obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
 			result.setResult(obj);
@@ -294,7 +316,8 @@ public class LoginController {
 				result = sysUserService.checkUserIsEffective(sysUser);
 				if(!result.isSuccess()) {
 					String message = result.getMessage();
-					if("该用户不存在,请注册".equals(message)){
+					String userNotExist="该用户不存在,请注册";
+					if(userNotExist.equals(message)){
 						result.error500("该用户不存在或未绑定手机号");
 					}
 					return result;
@@ -400,7 +423,7 @@ public class LoginController {
 		String tenantIds = sysUser.getRelTenantIds();
 		if (oConvertUtils.isNotEmpty(tenantIds)) {
 			List<Integer> tenantIdList = new ArrayList<>();
-			for(String id: tenantIds.split(",")){
+			for(String id: tenantIds.split(SymbolConstant.COMMA)){
 				tenantIdList.add(Integer.valueOf(id));
 			}
 			// 该方法仅查询有效的租户,如果返回0个就说明所有的租户均无效。
@@ -451,7 +474,6 @@ public class LoginController {
 		Result<String> res = new Result<String>();
 		try {
 			//生成验证码
-			final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
 			String code = RandomUtil.randomString(BASE_CHECK_CODES,4);
 
 			//存到redis中
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java
index e3f78e1..e57e4a0 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java
@@ -27,7 +27,7 @@ import org.jeecg.modules.system.service.ISysAnnouncementService;
 import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
 import org.jeecg.modules.system.service.impl.ThirdAppDingtalkServiceImpl;
 import org.jeecg.modules.system.service.impl.ThirdAppWechatEnterpriseServiceImpl;
-import org.jeecg.modules.system.util.XSSUtils;
+import org.jeecg.modules.system.util.XssUtils;
 import org.jeecgframework.poi.excel.ExcelImportUtil;
 import org.jeecgframework.poi.excel.def.NormalExcelConstants;
 import org.jeecgframework.poi.excel.entity.ExportParams;
@@ -125,7 +125,7 @@ public class SysAnnouncementController {
 		Result<SysAnnouncement> result = new Result<SysAnnouncement>();
 		try {
 			// update-begin-author:liusq date:20210804 for:标题处理xss攻击的问题
-			String title = XSSUtils.striptXSS(sysAnnouncement.getTitile());
+			String title = XssUtils.scriptXss(sysAnnouncement.getTitile());
 			sysAnnouncement.setTitile(title);
 			// update-end-author:liusq date:20210804 for:标题处理xss攻击的问题
 			sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_0.toString());
@@ -153,7 +153,7 @@ public class SysAnnouncementController {
 			result.error500("未找到对应实体");
 		}else {
 			// update-begin-author:liusq date:20210804 for:标题处理xss攻击的问题
-			String title = XSSUtils.striptXSS(sysAnnouncement.getTitile());
+			String title = XssUtils.scriptXss(sysAnnouncement.getTitile());
 			sysAnnouncement.setTitile(title);
 			// update-end-author:liusq date:20210804 for:标题处理xss攻击的问题
 			boolean ok = sysAnnouncementService.upDateAnnouncement(sysAnnouncement);
@@ -488,15 +488,15 @@ public class SysAnnouncementController {
     public ModelAndView showContent(ModelAndView modelAndView, @PathVariable("id") String id, HttpServletRequest request) {
         SysAnnouncement announcement = sysAnnouncementService.getById(id);
         if (announcement != null) {
-            boolean tokenOK = false;
+            boolean tokenOk = false;
             try {
                 // 验证Token有效性
-                tokenOK = TokenUtils.verifyToken(request, sysBaseApi, redisUtil);
+                tokenOk = TokenUtils.verifyToken(request, sysBaseApi, redisUtil);
             } catch (Exception ignored) {
             }
             // 判断是否传递了Token,并且Token有效,如果传了就不做查看限制,直接返回
             // 如果Token无效,就做查看限制:只能查看已发布的
-            if (tokenOK || ANNOUNCEMENT_SEND_STATUS_1.equals(announcement.getSendStatus())) {
+            if (tokenOk || ANNOUNCEMENT_SEND_STATUS_1.equals(announcement.getSendStatus())) {
                 modelAndView.addObject("data", announcement);
                 modelAndView.setViewName("announcement/showContent");
                 return modelAndView;
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementSendController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementSendController.java
index ac2087c..67464e3 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementSendController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementSendController.java
@@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletRequest;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.DataBaseConstant;
 import org.jeecg.common.constant.WebsocketConst;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.SqlInjectionUtil;
@@ -76,7 +77,7 @@ public class SysAnnouncementSendController {
 		SqlInjectionUtil.filterContent(order);
 
 		if(oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) {
-			if("asc".equals(order)) {
+			if(DataBaseConstant.SQL_ASC.equals(order)) {
 				queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column));
 			}else {
 				queryWrapper.orderByDesc(oConvertUtils.camelToUnderline(column));
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java
index 719adcc..9ab89a7 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java
@@ -14,6 +14,7 @@ import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.vo.DictModel;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.ImportExcelUtil;
+import org.jeecg.common.util.SqlInjectionUtil;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.system.entity.SysCategory;
 import org.jeecg.modules.system.model.TreeSelectModel;
@@ -47,7 +48,12 @@ import java.util.stream.Collectors;
 public class SysCategoryController {
 	@Autowired
 	private ISysCategoryService sysCategoryService;
-	
+
+     /**
+      * 分类编码0
+      */
+     private static final String CATEGORY_ROOT_CODE = "0";
+
 	/**
 	  * 分页列表查询
 	 * @param sysCategory
@@ -294,7 +300,12 @@ public class SysCategoryController {
  	public Result<SysCategory> loadOne(@RequestParam(name="field") String field,@RequestParam(name="val") String val) {
  		Result<SysCategory> result = new Result<SysCategory>();
  		try {
- 			
+			//update-begin-author:taoyan date:2022-5-6 for: issues/3663 sql注入问题
+			boolean isClassField = SqlInjectionUtil.isClassField(field, SysCategory.class);
+			if (!isClassField) {
+				return Result.error("字段无效,请检查!");
+			}
+			//update-end-author:taoyan date:2022-5-6 for: issues/3663 sql注入问题
  			QueryWrapper<SysCategory> query = new QueryWrapper<SysCategory>();
  			query.eq(field, val);
  			List<SysCategory> ls = this.sysCategoryService.list(query);
@@ -463,7 +474,7 @@ public class SysCategoryController {
 	 public Result<List<DictModel>> loadAllData(@RequestParam(name="code",required = true) String code) {
 		 Result<List<DictModel>> result = new Result<List<DictModel>>();
 		 LambdaQueryWrapper<SysCategory> query = new LambdaQueryWrapper<SysCategory>();
-		 if(oConvertUtils.isNotEmpty(code) && !"0".equals(code)){
+		 if(oConvertUtils.isNotEmpty(code) && !CATEGORY_ROOT_CODE.equals(code)){
 			 query.likeRight(SysCategory::getCode,code);
 		 }
 		 List<SysCategory> list = this.sysCategoryService.list(query);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java
index 98417c1..a39a630 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java
@@ -1,12 +1,11 @@
 package org.jeecg.modules.system.controller;
 
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.HexUtil;
-import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
-import cn.hutool.crypto.symmetric.SymmetricCrypto;
+
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import com.baomidou.dynamic.datasource.creator.DruidDataSourceCreator;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -29,6 +28,7 @@ import org.springframework.web.servlet.ModelAndView;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
 import java.util.Arrays;
 import java.util.List;
 
@@ -69,18 +69,6 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
         QueryWrapper<SysDataSource> queryWrapper = QueryGenerator.initQueryWrapper(sysDataSource, req.getParameterMap());
         Page<SysDataSource> page = new Page<>(pageNo, pageSize);
         IPage<SysDataSource> pageList = sysDataSourceService.page(page, queryWrapper);
-        try {
-            List<SysDataSource> records = pageList.getRecords();
-            records.forEach(item->{
-                String dbPassword = item.getDbPassword();
-                if(StringUtils.isNotBlank(dbPassword)){
-                    String decodedStr = SecurityUtil.jiemi(dbPassword);
-                    item.setDbPassword(decodedStr);
-                }
-            });
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
         return Result.ok(pageList);
     }
 
@@ -109,17 +97,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
     @ApiOperation(value = "多数据源管理-添加", notes = "多数据源管理-添加")
     @PostMapping(value = "/add")
     public Result<?> add(@RequestBody SysDataSource sysDataSource) {
-        try {
-            String dbPassword = sysDataSource.getDbPassword();
-            if(StringUtils.isNotBlank(dbPassword)){
-                String encrypt = SecurityUtil.jiami(dbPassword);
-                sysDataSource.setDbPassword(encrypt);
-            }
-            sysDataSourceService.save(sysDataSource);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return Result.ok("添加成功!");
+        return sysDataSourceService.saveDataSource(sysDataSource);
     }
 
     /**
@@ -132,19 +110,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
     @ApiOperation(value = "多数据源管理-编辑", notes = "多数据源管理-编辑")
     @RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
     public Result<?> edit(@RequestBody SysDataSource sysDataSource) {
-        try {
-            SysDataSource d = sysDataSourceService.getById(sysDataSource.getId());
-            DataSourceCachePool.removeCache(d.getCode());
-            String dbPassword = sysDataSource.getDbPassword();
-            if(StringUtils.isNotBlank(dbPassword)){
-                String encrypt = SecurityUtil.jiami(dbPassword);
-                sysDataSource.setDbPassword(encrypt);
-            }
-            sysDataSourceService.updateById(sysDataSource);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return Result.ok("编辑成功!");
+        return sysDataSourceService.editDataSource(sysDataSource);
     }
 
     /**
@@ -157,10 +123,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
     @ApiOperation(value = "多数据源管理-通过id删除", notes = "多数据源管理-通过id删除")
     @DeleteMapping(value = "/delete")
     public Result<?> delete(@RequestParam(name = "id") String id) {
-        SysDataSource sysDataSource = sysDataSourceService.getById(id);
-        DataSourceCachePool.removeCache(sysDataSource.getCode());
-        sysDataSourceService.removeById(id);
-        return Result.ok("删除成功!");
+        return sysDataSourceService.deleteDataSource(id);
     }
 
     /**
@@ -191,8 +154,14 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
     @AutoLog(value = "多数据源管理-通过id查询")
     @ApiOperation(value = "多数据源管理-通过id查询", notes = "多数据源管理-通过id查询")
     @GetMapping(value = "/queryById")
-    public Result<?> queryById(@RequestParam(name = "id") String id) {
+    public Result<?> queryById(@RequestParam(name = "id") String id) throws InterruptedException {
         SysDataSource sysDataSource = sysDataSourceService.getById(id);
+        //密码解密
+        String dbPassword = sysDataSource.getDbPassword();
+        if(StringUtils.isNotBlank(dbPassword)){
+            String decodedStr = SecurityUtil.jiemi(dbPassword);
+            sysDataSource.setDbPassword(decodedStr);
+        }
         return Result.ok(sysDataSource);
     }
 
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java
index 378ae6d..fcfd21a 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java
@@ -123,13 +123,14 @@ public class SysDepartController {
 	 * 异步查询部门list
 	 * @param parentId 父节点 异步加载时传递
 	 * @param ids 前端回显是传递
+	 * @param primaryKey 主键字段(id或者orgCode)
 	 * @return
 	 */
 	@RequestMapping(value = "/queryDepartTreeSync", method = RequestMethod.GET)
-	public Result<List<SysDepartTreeModel>> queryDepartTreeSync(@RequestParam(name = "pid", required = false) String parentId,@RequestParam(name = "ids", required = false) String ids) {
+	public Result<List<SysDepartTreeModel>> queryDepartTreeSync(@RequestParam(name = "pid", required = false) String parentId,@RequestParam(name = "ids", required = false) String ids, @RequestParam(name = "primaryKey", required = false) String primaryKey) {
 		Result<List<SysDepartTreeModel>> result = new Result<>();
 		try {
-			List<SysDepartTreeModel> list = sysDepartService.queryTreeListByPid(parentId,ids);
+			List<SysDepartTreeModel> list = sysDepartService.queryTreeListByPid(parentId,ids, primaryKey);
 			result.setResult(list);
 			result.setSuccess(true);
 		} catch (Exception e) {
@@ -460,7 +461,7 @@ public class SysDepartController {
 		LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>();
 		query.orderByAsc(SysDepart::getOrgCode);
 		if(oConvertUtils.isNotEmpty(id)){
-			String arr[] = id.split(",");
+			String[] arr = id.split(",");
 			query.in(SysDepart::getId,arr);
 		}
 		List<SysDepart> ls = this.sysDepartService.list(query);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java
index 74a765a..8edb12b 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java
@@ -237,7 +237,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
 		 Result<List<String>> result = new Result<>();
 		 try {
 			 List<SysDepartRolePermission> list = sysDepartRolePermissionService.list(new QueryWrapper<SysDepartRolePermission>().lambda().eq(SysDepartRolePermission::getRoleId, roleId));
-			 result.setResult(list.stream().map(SysDepartRolePermission -> String.valueOf(SysDepartRolePermission.getPermissionId())).collect(Collectors.toList()));
+			 result.setResult(list.stream().map(sysDepartRolePermission -> String.valueOf(sysDepartRolePermission.getPermissionId())).collect(Collectors.toList()));
 			 result.setSuccess(true);
 		 } catch (Exception e) {
 			 log.error(e.getMessage(), e);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
index 121bf32..172cdc7 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
@@ -12,6 +12,7 @@ import org.apache.shiro.authz.annotation.RequiresRoles;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CacheConstant;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.vo.DictModel;
 import org.jeecg.common.system.vo.DictQuery;
@@ -277,8 +278,8 @@ public class SysDictController {
 		}
 		//update-end-author:taoyan date:20220317 for: VUEN-222【安全机制】字典接口、online报表、online图表等接口,加一些安全机制
 		try {
-			if(dictCode.indexOf(",")!=-1) {
-				String[] params = dictCode.split(",");
+			if(dictCode.indexOf(SymbolConstant.COMMA)!=-1) {
+				String[] params = dictCode.split(SymbolConstant.COMMA);
 				if(params.length!=3) {
 					result.error500("字典Code格式不正确!");
 					return result;
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysLogController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysLogController.java
index 9409845..1853a7f 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysLogController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysLogController.java
@@ -6,6 +6,7 @@ import java.util.Arrays;
 import javax.servlet.http.HttpServletRequest;
 
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.system.entity.SysLog;
@@ -38,7 +39,12 @@ public class SysLogController {
 	
 	@Autowired
 	private ISysLogService sysLogService;
-	
+
+    /**
+     * 全部清除
+     */
+	private static final String ALL_ClEAR = "allclear";
+
 	/**
 	 * @功能:查询日志记录
 	 * @param syslog
@@ -103,7 +109,7 @@ public class SysLogController {
 		if(ids==null || "".equals(ids.trim())) {
 			result.error500("参数不识别!");
 		}else {
-			if("allclear".equals(ids)) {
+			if(ALL_ClEAR.equals(ids)) {
 				this.sysLogService.removeAll();
 				result.success("清除成功!");
 			}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java
index 8471b6b..0e8217a 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java
@@ -1,5 +1,6 @@
 package org.jeecg.modules.system.controller;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -10,11 +11,12 @@ import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authz.annotation.RequiresRoles;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.constant.enums.RoleIndexConfigEnum;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.Md5Util;
 import org.jeecg.common.util.oConvertUtils;
-import org.jeecg.config.JeeccgBaseConfig;
+import org.jeecg.config.JeecgBaseConfig;
 import org.jeecg.modules.base.service.BaseCommonService;
 import org.jeecg.modules.system.entity.*;
 import org.jeecg.modules.system.model.SysPermissionTree;
@@ -57,7 +59,7 @@ public class SysPermissionController {
 	private ISysUserService sysUserService;
 
 	@Autowired
-	private JeeccgBaseConfig jeeccgBaseConfig;
+	private JeecgBaseConfig jeecgBaseConfig;
 
 	@Autowired
     private BaseCommonService baseCommonService;
@@ -65,6 +67,11 @@ public class SysPermissionController {
 	@Autowired
 	private ISysRoleIndexService sysRoleIndexService;
 
+    /**
+     * 子菜单
+     */
+	private static final String CHILDREN = "children";
+
 	/**
 	 * 加载数据节点
 	 *
@@ -212,6 +219,7 @@ public class SysPermissionController {
 	 * @return
 	 */
 	@RequestMapping(value = "/getUserPermissionByToken", method = RequestMethod.GET)
+	//@DynamicTable(value = DynamicTableConstant.SYS_ROLE_INDEX)
 	public Result<?> getUserPermissionByToken(HttpServletRequest request) {
 		Result<JSONObject> result = new Result<JSONObject>();
 		try {
@@ -229,14 +237,29 @@ public class SysPermissionController {
 			}
 			//update-end-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存
 
-			//update-begin--Author:liusq  Date:20210624  for:自定义首页地址LOWCOD-1578
-			List<String> roles = sysUserService.getRole(loginUser.getUsername());
-            String compUrl = RoleIndexConfigEnum.getIndexByRoles(roles);
-			if(StringUtils.isNotBlank(compUrl)){
+			//update-begin--Author:zyf Date:20220425  for:自定义首页地址 LOWCOD-1578
+			String version = request.getHeader(CommonConstant.VERSION);
+			//update-begin---author:liusq ---date:2022-06-29  for:接口返回值修改,同步修改这里的判断逻辑-----------
+			SysRoleIndex roleIndex= sysUserService.getDynamicIndexByUserRole(loginUser.getUsername(),version);
+			//update-end---author:liusq ---date:2022-06-29  for:接口返回值修改,同步修改这里的判断逻辑-----------
+			//update-end--Author:zyf  Date:20220425  for:自定义首页地址 LOWCOD-1578
+
+			if(roleIndex!=null){
 				List<SysPermission> menus = metaList.stream().filter(sysPermission -> "首页".equals(sysPermission.getName())).collect(Collectors.toList());
-				menus.get(0).setComponent(compUrl);
+				//update-begin---author:liusq ---date:2022-06-29  for:设置自定义首页地址和组件----------
+				String component = roleIndex.getComponent();
+				String routeUrl = roleIndex.getUrl();
+				boolean route = roleIndex.isRoute();
+				if(oConvertUtils.isNotEmpty(routeUrl)){
+					menus.get(0).setComponent(component);
+					menus.get(0).setRoute(route);
+					menus.get(0).setUrl(routeUrl);
+				}else{
+					menus.get(0).setComponent(component);
+				}
+				//update-end---author:liusq ---date:2022-06-29  for:设置自定义首页地址和组件-----------
 			}
-			//update-end--Author:liusq  Date:20210624  for:自定义首页地址LOWCOD-1578
+			
 			JSONObject json = new JSONObject();
 			JSONArray menujsonArray = new JSONArray();
 			this.getPermissionJsonArray(menujsonArray, metaList, null);
@@ -259,7 +282,7 @@ public class SysPermissionController {
 			json.put("auth", authjsonArray);
 			//全部权限配置集合(按钮权限,访问权限)
 			json.put("allAuth", allauthjsonArray);
-			json.put("sysSafeMode", jeeccgBaseConfig.getSafeMode());
+			json.put("sysSafeMode", jeecgBaseConfig.getSafeMode());
 			result.setResult(json);
 		} catch (Exception e) {
 			result.error500("查询失败:" + e.getMessage());  
@@ -306,7 +329,7 @@ public class SysPermissionController {
 			//全部权限配置集合(按钮权限,访问权限)
 			result.put("allAuth", allAuthArray);
             // 系统安全模式
-			result.put("sysSafeMode", jeeccgBaseConfig.getSafeMode());
+			result.put("sysSafeMode", jeecgBaseConfig.getSafeMode());
             return Result.OK(result);
 		} catch (Exception e) {
 			log.error(e.getMessage(), e);
@@ -418,7 +441,7 @@ public class SysPermissionController {
 			List<TreeModel> treeList = new ArrayList<>();
 			getTreeModelList(treeList, list, null);
 
-			Map<String, Object> resMap = new HashMap<String, Object>();
+			Map<String, Object> resMap = new HashMap<String, Object>(5);
             // 全部树节点数据
 			resMap.put("treeList", treeList);
             // 全部树ids
@@ -464,7 +487,7 @@ public class SysPermissionController {
 		Result<List<String>> result = new Result<>();
 		try {
 			List<SysRolePermission> list = sysRolePermissionService.list(new QueryWrapper<SysRolePermission>().lambda().eq(SysRolePermission::getRoleId, roleId));
-			result.setResult(list.stream().map(SysRolePermission -> String.valueOf(SysRolePermission.getPermissionId())).collect(Collectors.toList()));
+			result.setResult(list.stream().map(sysRolePermission -> String.valueOf(sysRolePermission.getPermissionId())).collect(Collectors.toList()));
 			result.setSuccess(true);
 		} catch (Exception e) {
 			log.error(e.getMessage(), e);
@@ -546,8 +569,8 @@ public class SysPermissionController {
 		jsonArray = jsonArray.stream().map(obj -> {
 			JSONObject returnObj = new JSONObject();
 			JSONObject jsonObj = (JSONObject)obj;
-			if(jsonObj.containsKey("children")){
-				JSONArray childrens = jsonObj.getJSONArray("children");
+			if(jsonObj.containsKey(CHILDREN)){
+				JSONArray childrens = jsonObj.getJSONArray(CHILDREN);
                 childrens = childrens.stream().filter(arrObj -> !"true".equals(((JSONObject) arrObj).getString("hidden"))).collect(Collectors.toCollection(JSONArray::new));
                 if(childrens==null || childrens.size()==0){
                     jsonObj.put("hidden",true);
@@ -675,7 +698,7 @@ public class SysPermissionController {
 				json.put("route", "0");
 			}
 
-			if (isWWWHttpUrl(permission.getUrl())) {
+			if (isWwwHttpUrl(permission.getUrl())) {
 				json.put("path", Md5Util.md5Encode(permission.getUrl(), "utf-8"));
 			} else {
 				json.put("path", permission.getUrl());
@@ -736,7 +759,7 @@ public class SysPermissionController {
 					meta.put("icon", permission.getIcon());
 				}
 			}
-			if (isWWWHttpUrl(permission.getUrl())) {
+			if (isWwwHttpUrl(permission.getUrl())) {
 				meta.put("url", permission.getUrl());
 			}
 			// update-begin--Author:sunjianlei  Date:20210918 for:新增适配vue3项目的隐藏tab功能
@@ -756,8 +779,9 @@ public class SysPermissionController {
 	 *
 	 * @return
 	 */
-	private boolean isWWWHttpUrl(String url) {
-		if (url != null && (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("{{"))) {
+	private boolean isWwwHttpUrl(String url) {
+        boolean flag = url != null && (url.startsWith(CommonConstant.HTTP_PROTOCOL) || url.startsWith(CommonConstant.HTTPS_PROTOCOL) || url.startsWith(SymbolConstant.DOUBLE_LEFT_CURLY_BRACKET));
+        if (flag) {
 			return true;
 		}
 		return false;
@@ -771,7 +795,7 @@ public class SysPermissionController {
 	 */
 	private String urlToRouteName(String url) {
 		if (oConvertUtils.isNotEmpty(url)) {
-			if (url.startsWith("/")) {
+			if (url.startsWith(SymbolConstant.SINGLE_SLASH)) {
 				url = url.substring(1);
 			}
 			url = url.replace("/", "-");
@@ -883,7 +907,7 @@ public class SysPermissionController {
 		Result<List<String>> result = new Result<>();
 		try {
 			List<SysDepartPermission> list = sysDepartPermissionService.list(new QueryWrapper<SysDepartPermission>().lambda().eq(SysDepartPermission::getDepartId, departId));
-			result.setResult(list.stream().map(SysDepartPermission -> String.valueOf(SysDepartPermission.getPermissionId())).collect(Collectors.toList()));
+			result.setResult(list.stream().map(sysDepartPermission -> String.valueOf(sysDepartPermission.getPermissionId())).collect(Collectors.toList()));
 			result.setSuccess(true);
 		} catch (Exception e) {
 			log.error(e.getMessage(), e);
@@ -914,4 +938,5 @@ public class SysPermissionController {
 		}
 		return result;
 	}
+
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysRoleIndexController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysRoleIndexController.java
index fb15615..8f48814 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysRoleIndexController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysRoleIndexController.java
@@ -68,7 +68,8 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
     @AutoLog(value = "角色首页配置-添加")
     @ApiOperation(value = "角色首页配置-添加", notes = "角色首页配置-添加")
     @PostMapping(value = "/add")
-    public Result<?> add(@RequestBody SysRoleIndex sysRoleIndex) {
+    //@DynamicTable(value = DynamicTableConstant.SYS_ROLE_INDEX)
+    public Result<?> add(@RequestBody SysRoleIndex sysRoleIndex,HttpServletRequest request) {
         sysRoleIndexService.save(sysRoleIndex);
         return Result.OK("添加成功!");
     }
@@ -82,7 +83,8 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
     @AutoLog(value = "角色首页配置-编辑")
     @ApiOperation(value = "角色首页配置-编辑", notes = "角色首页配置-编辑")
     @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
-    public Result<?> edit(@RequestBody SysRoleIndex sysRoleIndex) {
+    //@DynamicTable(value = DynamicTableConstant.SYS_ROLE_INDEX)
+    public Result<?> edit(@RequestBody SysRoleIndex sysRoleIndex,HttpServletRequest request) {
         sysRoleIndexService.updateById(sysRoleIndex);
         return Result.OK("编辑成功!");
     }
@@ -161,7 +163,8 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
     @AutoLog(value = "角色首页配置-通过code查询")
     @ApiOperation(value = "角色首页配置-通过code查询", notes = "角色首页配置-通过code查询")
     @GetMapping(value = "/queryByCode")
-    public Result<?> queryByCode(@RequestParam(name = "roleCode", required = true) String roleCode) {
+    //@DynamicTable(value = DynamicTableConstant.SYS_ROLE_INDEX)
+    public Result<?> queryByCode(@RequestParam(name = "roleCode", required = true) String roleCode,HttpServletRequest request) {
         SysRoleIndex sysRoleIndex = sysRoleIndexService.getOne(new LambdaQueryWrapper<SysRoleIndex>().eq(SysRoleIndex::getRoleCode, roleCode));
         return Result.OK(sysRoleIndex);
     }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java
index 6001b94..7897bdc 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java
@@ -9,6 +9,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.aspect.annotation.PermissionData;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.oConvertUtils;
@@ -204,7 +205,7 @@ public class SysTenantController {
             Map<String,Object> map = new HashMap(5);
             if (oConvertUtils.isNotEmpty(tenantIds)) {
                 List<Integer> tenantIdList = new ArrayList<>();
-                for(String id: tenantIds.split(",")){
+                for(String id: tenantIds.split(SymbolConstant.COMMA)){
                     tenantIdList.add(Integer.valueOf(id));
                 }
                 // 该方法仅查询有效的租户,如果返回0个就说明所有的租户均无效。
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUploadController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUploadController.java
index 45d6934..ad0bf40 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUploadController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUploadController.java
@@ -6,8 +6,8 @@ import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.util.CommonUtils;
 import org.jeecg.common.util.MinioUtil;
 import org.jeecg.common.util.oConvertUtils;
-import org.jeecg.modules.oss.entity.OSSFile;
-import org.jeecg.modules.oss.service.IOSSFileService;
+import org.jeecg.modules.oss.entity.OssFile;
+import org.jeecg.modules.oss.service.IOssFileService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -26,7 +26,7 @@ import javax.servlet.http.HttpServletRequest;
 @RequestMapping("/sys/upload")
 public class SysUploadController {
     @Autowired
-    private IOSSFileService ossFileService;
+    private IOssFileService ossFileService;
 
     /**
      * 上传
@@ -38,7 +38,8 @@ public class SysUploadController {
         String bizPath = request.getParameter("biz");
 
         //LOWCOD-2580 sys/common/upload接口存在任意文件上传漏洞
-        if (oConvertUtils.isNotEmpty(bizPath) && (bizPath.contains("../") || bizPath.contains("..\\"))) {
+        boolean flag = oConvertUtils.isNotEmpty(bizPath) && (bizPath.contains("../") || bizPath.contains("..\\"));
+        if (flag) {
             throw new JeecgBootException("上传目录bizPath,格式非法!");
         }
 
@@ -51,16 +52,16 @@ public class SysUploadController {
         // 获取文件名
         String orgName = file.getOriginalFilename();
         orgName = CommonUtils.getFileName(orgName);
-        String file_url =  MinioUtil.upload(file,bizPath);
-        if(oConvertUtils.isEmpty(file_url)){
+        String fileUrl =  MinioUtil.upload(file,bizPath);
+        if(oConvertUtils.isEmpty(fileUrl)){
             return Result.error("上传失败,请检查配置信息是否正确!");
         }
         //保存文件信息
-        OSSFile minioFile = new OSSFile();
+        OssFile minioFile = new OssFile();
         minioFile.setFileName(orgName);
-        minioFile.setUrl(file_url);
+        minioFile.setUrl(fileUrl);
         ossFileService.save(minioFile);
-        result.setMessage(file_url);
+        result.setMessage(fileUrl);
         result.setSuccess(true);
         return result;
     }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
index 1b2e2d3..9a5d5c8 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
@@ -18,6 +18,7 @@ import org.apache.shiro.authz.annotation.RequiresRoles;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.aspect.annotation.PermissionData;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.system.api.ISysBaseAPI;
 import org.jeecg.modules.base.service.BaseCommonService;
 import org.jeecg.common.system.query.QueryGenerator;
@@ -159,7 +160,7 @@ public class SysUserController {
 	}
 
     //@RequiresRoles({"admin"})
-    //@RequiresPermissions("user:add")
+    //Permissions("system:user:add")
 	@RequestMapping(value = "/add", method = RequestMethod.POST)
 	public Result<SysUser> add(@RequestBody JSONObject jsonObject) {
 		Result<SysUser> result = new Result<SysUser>();
@@ -174,6 +175,8 @@ public class SysUserController {
 			user.setPassword(passwordEncode);
 			user.setStatus(1);
 			user.setDelFlag(CommonConstant.DEL_FLAG_0);
+			//用户表字段org_code不能在这里设置他的值
+            user.setOrgCode(null);
 			// 保存用户走一个service 保证事务
 			sysUserService.saveUser(user, selectedRoles, selectedDeparts);
             baseCommonService.addLog("添加用户,username: " +user.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
@@ -186,7 +189,7 @@ public class SysUserController {
 	}
 
     //@RequiresRoles({"admin"})
-    //@RequiresPermissions("user:edit")
+    //Permissions("system:user:edit")
 	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<SysUser> edit(@RequestBody JSONObject jsonObject) {
 		Result<SysUser> result = new Result<SysUser>();
@@ -206,6 +209,8 @@ public class SysUserController {
                     //vue3.0前端只传递了departIds
                     departs=user.getDepartIds();
                 }
+                //用户表字段org_code不能在这里设置他的值
+                user.setOrgCode(null);
                 // 修改用户走一个service 保证事务
 				sysUserService.editUser(user, roles, departs);
 				result.success("修改成功!");
@@ -439,8 +444,13 @@ public class SysUserController {
             @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
             @RequestParam(name = "departId", required = false) String departId,
             @RequestParam(name="realname",required=false) String realname,
-            @RequestParam(name="username",required=false) String username) {
-        IPage<SysUser> pageList = sysUserDepartService.queryDepartUserPageList(departId, username, realname, pageSize, pageNo);
+            @RequestParam(name="username",required=false) String username,
+            @RequestParam(name="id",required = false) String id) {
+        //update-begin-author:taoyan date:2022-7-14 for: VUEN-1702【禁止问题】sql注入漏洞
+        String[] arr = new String[]{departId, realname, username, id};
+        SqlInjectionUtil.filterContent(arr, SymbolConstant.SINGLE_QUOTATION_MARK);
+        //update-end-author:taoyan date:2022-7-14 for: VUEN-1702【禁止问题】sql注入漏洞
+        IPage<SysUser> pageList = sysUserDepartService.queryDepartUserPageList(departId, username, realname, pageSize, pageNo,id);
         return Result.OK(pageList);
     }
 
@@ -450,6 +460,8 @@ public class SysUserController {
      * @param request
      * @param sysUser
      */
+    //@RequiresRoles({"admin"})
+    //@RequiresPermissions("system:user:export")
     @RequestMapping(value = "/exportXls")
     public ModelAndView exportXls(SysUser sysUser,HttpServletRequest request) {
         // Step.1 组装查询条件
@@ -483,7 +495,7 @@ public class SysUserController {
      * @return
      */
     //@RequiresRoles({"admin"})
-    //@RequiresPermissions("user:import")
+    //Permissions("system:user:import")
     @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
     public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response)throws IOException {
         MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
@@ -1267,6 +1279,15 @@ public class SysUserController {
                     sysUser.setPhone(phone);
                 }
                 if(StringUtils.isNotBlank(email)){
+                    //update-begin---author:wangshuai ---date:20220708  for:[VUEN-1528]积木官网邮箱重复,应该提示准确------------
+                    LambdaQueryWrapper<SysUser> emailQuery = new LambdaQueryWrapper<>();
+                    emailQuery.eq(SysUser::getEmail,email);
+                    long count = sysUserService.count(emailQuery);
+                    if (!email.equals(sysUser.getEmail()) && count!=0) {
+                        result.error500("保存失败,邮箱已存在!");
+                        return result;
+                    }
+                    //update-end---author:wangshuai ---date:20220708  for:[VUEN-1528]积木官网邮箱重复,应该提示准确--------------
                     sysUser.setEmail(email);
                 }
                 if(null != birthday){
@@ -1277,7 +1298,7 @@ public class SysUserController {
             }
         } catch (Exception e) {
             log.error(e.getMessage(), e);
-            result.error500("操作失败!");
+            result.error500("保存失败!");
         }
         return result;
     }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java
index 4c93b1e..2082875 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java
@@ -246,7 +246,7 @@ public class ThirdAppController {
         // 第三方app的类型
         String app = params.getString("app");
         // 消息id
-        String msg_task_id = params.getString("msg_task_id");
+        String msgTaskId = params.getString("msg_task_id");
 
         if (ThirdAppConfig.WECHAT_ENTERPRISE.equals(app)) {
             if (thirdAppConfig.isWechatEnterpriseEnabled()) {
@@ -255,7 +255,7 @@ public class ThirdAppController {
             return Result.error("企业微信已被禁用");
         } else if (ThirdAppConfig.DINGTALK.equals(app)) {
             if (thirdAppConfig.isDingtalkEnabled()) {
-                Response<JSONObject> response = dingtalkService.recallMessageResponse(msg_task_id);
+                Response<JSONObject> response = dingtalkService.recallMessageResponse(msgTaskId);
                 if (response.isSuccess()) {
                     return Result.OK("撤回成功", response);
                 } else {
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java
index d7e7c06..56686a4 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java
@@ -332,7 +332,10 @@ public class ThirdLoginController {
 			builder.append("&scope=openid");
 			// 跟随authCode原样返回。
 			builder.append("&state=").append(state);
-			url = builder.toString();
+            //update-begin---author:wangshuai ---date:20220613  for:[issues/I5BOUF]oauth2 钉钉无法登录------------
+            builder.append("&prompt=").append("consent");
+            //update-end---author:wangshuai ---date:20220613  for:[issues/I5BOUF]oauth2 钉钉无法登录--------------
+            url = builder.toString();
 		} else {
 			return "不支持的source";
 		}
@@ -377,9 +380,28 @@ public class ThirdLoginController {
             return "不支持的source";
         }
         try {
-            String token = saveToken(loginUser);
+
+			//update-begin-author:taoyan date:2022-6-30 for: 工作流发送消息 点击消息链接跳转办理页面
+			String redirect = "";
+			if (state.indexOf("?") > 0) {
+				String[] arr = state.split("\\?");
+				state = arr[0];
+				if(arr.length>1){
+					redirect = arr[1];
+				}
+			}
+
+			String token = saveToken(loginUser);
 			state += "/oauth2-app/login?oauth2LoginToken=" + URLEncoder.encode(token, "UTF-8");
-			state += "&thirdType=" + "wechat_enterprise";
+			//update-begin---author:wangshuai ---date:20220613  for:[issues/I5BOUF]oauth2 钉钉无法登录------------
+			state += "&thirdType=" + source;
+			//state += "&thirdType=" + "wechat_enterprise";
+			if (redirect != null && redirect.length() > 0) {
+				state += "&" + redirect;
+			}
+			//update-end-author:taoyan date:2022-6-30 for: 工作流发送消息 点击消息链接跳转办理页面
+
+            //update-end---author:wangshuai ---date:20220613  for:[issues/I5BOUF]oauth2 钉钉无法登录------------
 			log.info("OAuth2登录重定向地址: " + state);
             try {
                 response.sendRedirect(state);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysRoleIndex.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysRoleIndex.java
index 1c744bf..d270fc5 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysRoleIndex.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysRoleIndex.java
@@ -40,6 +40,17 @@ public class SysRoleIndex {
 	@Excel(name = "路由地址", width = 15)
     @ApiModelProperty(value = "路由地址")
 	private java.lang.String url;
+	/**路由地址*/
+	@Excel(name = "路由地址", width = 15)
+    @ApiModelProperty(value = "组件")
+	private java.lang.String component;
+	/**
+	 * 是否路由菜单: 0:不是  1:是(默认值1)
+	 */
+	@Excel(name = "是否路由菜单", width = 15)
+	@ApiModelProperty(value = "是否路由菜单")
+	@TableField(value="is_route")
+	private boolean route;
 	/**优先级*/
 	@Excel(name = "优先级", width = 15)
     @ApiModelProperty(value = "优先级")
@@ -72,4 +83,12 @@ public class SysRoleIndex {
 	@Excel(name = "所属部门", width = 15)
     @ApiModelProperty(value = "所属部门")
 	private java.lang.String sysOrgCode;
+
+
+	public SysRoleIndex() {
+
+	}
+	public SysRoleIndex(String componentUrl){
+		this.component = componentUrl;
+	}
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysUser.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysUser.java
index 74f7fc5..837852e 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysUser.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysUser.java
@@ -2,6 +2,7 @@ package org.jeecg.modules.system.entity;
 
 import java.util.Date;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -182,4 +183,10 @@ public class SysUser implements Serializable {
 
     /**设备id uniapp推送用*/
     private String clientId;
+
+    /**
+     * 登录首页地址
+     */
+    @TableField(exist = false)
+    private String homePath;
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java
index 135b0bf..17c2cdd 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java
@@ -124,28 +124,28 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
 	@Deprecated
 	public String queryTableDictTextByKey(@Param("table") String table,@Param("text") String text,@Param("code") String code,@Param("key") String key);
 
-	/**
-	 * 通过查询指定table的 text code key 获取字典值,可批量查询
-	 *
-	 * @param table
-	 * @param text
-	 * @param code
-	 * @param keys
-	 * @return
-	 */
-	@Deprecated
-	List<DictModel> queryTableDictTextByKeys(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keys") List<String> keys);
+//	/**
+//	 * 通过查询指定table的 text code key 获取字典值,可批量查询
+//	 *
+//	 * @param table
+//	 * @param text
+//	 * @param code
+//	 * @param keys
+//	 * @return
+//	 */
+//	@Deprecated
+//	List<DictModel> queryTableDictTextByKeys(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keys") List<String> keys);
 
-    /**
-     * 通过查询指定table的 text code key 获取字典值,包含value
-     * @param table
-     * @param text
-     * @param code
-     * @param keyArray
-     * @return List<DictModel>
-     */
-	@Deprecated
-	public List<DictModel> queryTableDictByKeys(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keyArray") String[] keyArray);
+//  D  /**
+////     * 通过查询指定table的 text code key 获取字典值,包含value
+////     * @param table
+////     * @param text
+////     * @param code
+////     * @param keyArray
+////     * @return List<DictModel>
+////     */
+////	@Deprecated
+////	public List<DictModel> queryTableictByKeys(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keyArray") String[] keyArray);
 
 	/**
 	 * 查询所有部门 作为字典信息 id -->value,departName -->text
@@ -159,28 +159,28 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
 	 */
 	public List<DictModel> queryAllUserBackDictModel();
 	
-	/**
-	 * 通过关键字查询出字典表
-	 * @param table
-	 * @param text
-	 * @param code
-	 * @param keyword
-	 * @return
-	 */
-	@Deprecated
-	public List<DictModel> queryTableDictItems(@Param("table") String table,@Param("text") String text,@Param("code") String code,@Param("keyword") String keyword);
+//	/**
+//	 * 通过关键字查询出字典表
+//	 * @param table
+//	 * @param text
+//	 * @param code
+//	 * @param keyword
+//	 * @return
+//	 */
+//	@Deprecated
+//	public List<DictModel> queryTableDictItems(@Param("table") String table,@Param("text") String text,@Param("code") String code,@Param("keyword") String keyword);
 
 
-	/**
-	 * 通过关键字查询出字典表
-	 * @param page
-	 * @param table
-	 * @param text
-	 * @param code
-	 * @param keyword
-	 * @return
-	 */
-	IPage<DictModel> queryTableDictItems(Page<DictModel> page, @Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keyword") String keyword);
+//	/**
+//	 * 通过关键字查询出字典表
+//	 * @param page
+//	 * @param table
+//	 * @param text
+//	 * @param code
+//	 * @param keyword
+//	 * @return
+//	 */
+//	//IPage<DictModel> queryTableDictItems(Page<DictModel> page, @Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keyword") String keyword);
 
 	/**
 	  * 根据表名、显示字段名、存储字段名 查询树
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java
index 83d5a44..00c9607 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java
@@ -18,16 +18,17 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 public interface SysRoleMapper extends BaseMapper<SysRole> {
 
     /**
-     * @Description: 删除角色与用户关系
+     * 删除角色与用户关系
      * @Author scott
      * @Date 2019/12/13 16:12
+     * @param roleId
      */
     @Delete("delete from sys_user_role where role_id = #{roleId}")
     void deleteRoleUserRelation(@Param("roleId") String roleId);
 
 
     /**
-     * @Description: 删除角色与权限关系
+     * 删除角色与权限关系
      * @Author scott
      * @param roleId
      * @Date 2019/12/13 16:12
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysCategoryMapper.xml b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysCategoryMapper.xml
index 71a5e8b..741670c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysCategoryMapper.xml
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysCategoryMapper.xml
@@ -11,9 +11,25 @@
 			   from sys_category
 			where pid = #{pid}
 			<if test="query!= null">
-				<foreach collection="query.entrySet()" item="value"  index="key" >
-					and ${key} = #{value}
-				</foreach>
+				<if test="query.code !=null and query.code != ''">
+					and code = #{query.code}
+				</if>
+
+				<if test="query.name !=null and query.name != ''">
+					and name = #{query.name}
+				</if>
+
+				<if test="query.id !=null and query.id != ''">
+					and id = #{query.id}
+				</if>
+
+				<if test="query.createBy !=null and query.createBy != ''">
+					and create_by = #{query.createBy}
+				</if>
+
+				<if test="query.sysOrgCode !=null and query.sysOrgCode != ''">
+					and sys_org_code = #{query.sysOrgCode}
+				</if>
 			</if>
 	</select>
 
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml
index 34f3ebe..24d49a2 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml
@@ -80,22 +80,22 @@
 		   select ${text} as "text" from ${table} where ${code}= #{key}
 	</select>
 
-	<!--通过查询指定table的 text code key 获取字典值,可批量查询-->
+	<!--通过查询指定table的 text code key 获取字典值,可批量查询
 	<select id="queryTableDictTextByKeys" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
 		select ${text} as "text", ${code} as "value" from ${table} where ${code} IN (
 			<foreach item="key" collection="keys" separator=",">
 				#{key}
 			</foreach>
 		)
-	</select>
+	</select>-->
 
-	<!--通过查询指定table的 text code key 获取字典值,包含value-->
+	<!--通过查询指定table的 text code key 获取字典值,包含value
 	<select id="queryTableDictByKeys" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
 		select ${text} as "text", ${code} as "value" from ${table} where ${code} in
 		<foreach item="key" collection="keyArray" open="(" separator="," close=")">
 			#{key}
 		</foreach>
-	</select>
+	</select>-->
 
 	<!-- 重复校验 sql语句 -->
 	<select id="duplicateCheckCountSql" resultType="Long" parameterType="org.jeecg.modules.system.model.DuplicateCheckVo">
@@ -117,10 +117,10 @@
 		select username as "value",realname as "text" from sys_user where del_flag = '0'
 	</select>
 	
-	<!--通过查询指定table的 text code 获取字典数据,且支持关键字查询 -->
+	<!--通过查询指定table的 text code 获取字典数据,且支持关键字查询
 	<select id="queryTableDictItems" parameterType="String"  resultType="org.jeecg.common.system.vo.DictModel">
 		select ${text} as "text",${code} as "value" from ${table} where ${text} like #{keyword}
-	</select>
+	</select> -->
 	
 	<!-- 根据表名、显示字段名、存储字段名、父ID查询树 -->
 	<select id="queryTreeList" parameterType="Object" resultType="org.jeecg.modules.system.model.TreeSelectModel">
@@ -150,6 +150,16 @@
 				   <foreach collection="query.entrySet()" item="value"  index="key" >
 				   	and ${key} LIKE #{value}
 				   </foreach>
+					 <!-- udapte-end-author:sunjianlei date:20220615 for: 【issues/3709】自定义树查询条件没有处理父ID,没有树状结构了 -->
+					 <choose>
+						 <when test="pid != null and pid != ''">
+							 and ${pidField} = #{pid}
+						 </when>
+						 <otherwise>
+							 and (${pidField} = '' OR ${pidField} IS NULL)
+						 </otherwise>
+					 </choose>
+			   	 <!-- udapte-end-author:sunjianlei date:20220615 for: 【issues/3709】自定义树查询条件没有处理父ID,没有树状结构了 -->
 			   </if>
 			   <!-- udapte-end-author:sunjianlei date:20220110 for: 【JTC-597】自定义树查询条件查不出数据 -->
 	</select>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/model/SysPermissionTree.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/model/SysPermissionTree.java
index 3b6ee09..be9b16b 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/model/SysPermissionTree.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/model/SysPermissionTree.java
@@ -52,6 +52,11 @@ public class SysPermissionTree implements Serializable {
 	private String component;
 
 	/**
+	 * 组件名字
+	 */
+	private String componentName;
+
+	/**
 	 * 跳转网页链接
 	 */
 	private String url;
@@ -141,6 +146,7 @@ public class SysPermissionTree implements Serializable {
 		this.perms = permission.getPerms();
 		this.permsType = permission.getPermsType();
 		this.component = permission.getComponent();
+		this.componentName = permission.getComponentName();
 		this.createBy = permission.getCreateBy();
 		this.createTime = permission.getCreateTime();
 		this.delFlag = permission.getDelFlag();
@@ -266,6 +272,14 @@ public class SysPermissionTree implements Serializable {
 		this.component = component;
 	}
 
+	public String getComponentName() {
+		return componentName;
+	}
+
+	public void setComponentName(String componentName) {
+		this.componentName = componentName;
+	}
+
 	public String getUrl() {
 		return url;
 	}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/security/DictQueryBlackListHandler.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/security/DictQueryBlackListHandler.java
index 279c72a..53f2e7c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/security/DictQueryBlackListHandler.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/security/DictQueryBlackListHandler.java
@@ -1,5 +1,6 @@
 package org.jeecg.modules.system.security;
 
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.common.util.security.AbstractQueryBlackListHandler;
@@ -32,8 +33,9 @@ public class DictQueryBlackListHandler extends AbstractQueryBlackListHandler {
             QueryTable table = new QueryTable(tableName, "");
             // 无论什么场景 第二、三个元素一定是表的字段,直接add
             table.addField(arr[1].trim());
-            if (oConvertUtils.isNotEmpty(arr[2].trim())) {
-                table.addField(arr[2].trim());
+            String filed = arr[2].trim();
+            if (oConvertUtils.isNotEmpty(filed)) {
+                table.addField(filed);
             }
             List<QueryTable> list = new ArrayList<>();
             list.add(table);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysCategoryService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysCategoryService.java
index 908dfda..6c8b301 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysCategoryService.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysCategoryService.java
@@ -20,6 +20,11 @@ public interface ISysCategoryService extends IService<SysCategory> {
 	public static final String ROOT_PID_VALUE = "0";
 
     /**
+     * 存在子节点
+     */
+    public static final String HAS_CHILD = "1";
+
+    /**
      * 添加分类字典
      * @param sysCategory
      */
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDataSourceService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDataSourceService.java
index c8f3e04..eab243c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDataSourceService.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDataSourceService.java
@@ -1,6 +1,7 @@
 package org.jeecg.modules.system.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.common.api.vo.Result;
 import org.jeecg.modules.system.entity.SysDataSource;
 
 /**
@@ -11,4 +12,25 @@ import org.jeecg.modules.system.entity.SysDataSource;
  */
 public interface ISysDataSourceService extends IService<SysDataSource> {
 
+    /**
+     * 添加数据源
+     * @param sysDataSource
+     * @return
+     */
+    Result saveDataSource(SysDataSource sysDataSource);
+
+    /**
+     * 修改数据源
+     * @param sysDataSource
+     * @return
+     */
+    Result editDataSource(SysDataSource sysDataSource);
+
+
+    /**
+     * 删除数据源
+     * @param id
+     * @return
+     */
+    Result deleteDataSource(String id);
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java
index 5e52ef2..7cff1ce 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java
@@ -127,9 +127,10 @@ public interface ISysDepartService extends IService<SysDepart>{
      * 获取我的部门下级所有部门
      * @param parentId 父id
      * @param ids 多个部门id
+     * @param primaryKey 主键字段(id或者orgCode)
      * @return
      */
-    List<SysDepartTreeModel> queryTreeListByPid(String parentId,String ids);
+    List<SysDepartTreeModel> queryTreeListByPid(String parentId,String ids, String primaryKey);
 
     /**
      * 获取某个部门的所有父级部门的ID
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDictService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDictService.java
index b08a9d3..7f9bc9e 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDictService.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDictService.java
@@ -158,16 +158,16 @@ public interface ISysDictService extends IService<SysDict> {
 	 */
 	public List<DictModel> queryAllUserBackDictModel();
 
-	/**
-	 * 通过关键字查询字典表
-	 * @param table
-	 * @param text
-	 * @param code
-	 * @param keyword
-	 * @return
-	 */
-	@Deprecated
-	public List<DictModel> queryTableDictItems(String table, String text, String code,String keyword);
+//	/**
+//	 * 通过关键字查询字典表
+//	 * @param table
+//	 * @param text
+//	 * @param code
+//	 * @param keyword
+//	 * @return
+//	 */
+//	@Deprecated
+//	public List<DictModel> queryTableDictItems(String table, String text, String code,String keyword);
 
 	/**
 	 * 查询字典表数据 只查询前10条
@@ -179,6 +179,7 @@ public interface ISysDictService extends IService<SysDict> {
      * @param pageSize 每页条数
 	 * @return
 	 */
+	@Deprecated
 	public List<DictModel> queryLittleTableDictItems(String table, String text, String code, String condition, String keyword, int pageSize);
 
 	/**
@@ -190,6 +191,7 @@ public interface ISysDictService extends IService<SysDict> {
 	 * @param keyword
 	 * @return
 	 */
+	@Deprecated
 	public List<DictModel> queryAllTableDictItems(String table, String text, String code, String condition, String keyword);
 	/**
 	  * 根据表名、显示字段名、存储字段名 查询树
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysUserDepartService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysUserDepartService.java
index e368942..72eaaa5 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysUserDepartService.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysUserDepartService.java
@@ -49,8 +49,10 @@ public interface ISysUserDepartService extends IService<SysUserDepart> {
 	 * @param username
 	 * @param pageSize
 	 * @param pageNo
+     * @param realname
+     * @param id
 	 * @return
 	 */
-	IPage<SysUser> queryDepartUserPageList(String departId, String username, String realname, int pageSize, int pageNo);
+	IPage<SysUser> queryDepartUserPageList(String departId, String username, String realname, int pageSize, int pageNo,String id);
 
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysUserService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysUserService.java
index 70c880a..3ef056f 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysUserService.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysUserService.java
@@ -6,7 +6,9 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.system.vo.SysUserCacheInfo;
+import org.jeecg.modules.system.entity.SysRoleIndex;
 import org.jeecg.modules.system.entity.SysUser;
 import org.jeecg.modules.system.model.SysUserSysDepartModel;
 import org.springframework.transaction.annotation.Transactional;
@@ -87,12 +89,22 @@ public interface ISysUserService extends IService<SysUser> {
 	 * @return
 	 */
 	public List<String> getRole(String username);
+
+	/**
+	 * 获取根据登录用户的角色获取动态首页
+	 *
+	 * @param username
+	 * @param version 前端UI版本
+	 * @return
+	 */
+	public SysRoleIndex getDynamicIndexByUserRole(String username,String version);
 	
 	/**
 	  * 查询用户信息包括 部门信息
 	 * @param username
 	 * @return
 	 */
+	@Deprecated
 	public SysUserCacheInfo getCacheUser(String username);
 
 	/**
@@ -175,6 +187,7 @@ public interface ISysUserService extends IService<SysUser> {
 	/**
 	 * 根据手机号获取用户名和密码
      * @param phone 手机号
+     * @return SysUser
 	 */
 	public SysUser getUserByPhone(String phone);
 
@@ -280,4 +293,12 @@ public interface ISysUserService extends IService<SysUser> {
      */
 	List<String> userIdToUsername(Collection<String> userIdList);
 
+
+	/**
+	 * 获取用户信息 字段信息是加密后的 【加密用户信息】
+	 * @param username
+	 * @return
+	 */
+	LoginUser getEncodeUserInfo(String username);
+
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java
index 7e34096..9223a91 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java
@@ -1,4 +1,5 @@
 package org.jeecg.modules.system.service.impl;
+
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -14,19 +15,22 @@ import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.dto.OnlineAuthDTO;
 import org.jeecg.common.api.dto.message.*;
 import org.jeecg.common.aspect.UrlMatchEnum;
-import org.jeecg.common.constant.CacheConstant;
-import org.jeecg.common.constant.CommonConstant;
-import org.jeecg.common.constant.DataBaseConstant;
-import org.jeecg.common.constant.WebsocketConst;
+import org.jeecg.common.constant.*;
+import org.jeecg.common.constant.enums.MessageTypeEnum;
+import org.jeecg.common.desensitization.util.SensitiveInfoUtil;
 import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.system.api.ISysBaseAPI;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.vo.*;
 import org.jeecg.common.util.SysAnnmentTypeEnum;
 import org.jeecg.common.util.YouBianCodeUtil;
+import org.jeecg.common.util.dynamic.db.FreemarkerParseFactory;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.message.entity.SysMessageTemplate;
+import org.jeecg.modules.message.handle.impl.DdSendMsgHandle;
 import org.jeecg.modules.message.handle.impl.EmailSendMsgHandle;
+import org.jeecg.modules.message.handle.impl.QywxSendMsgHandle;
+import org.jeecg.modules.message.handle.impl.SystemSendMsgHandle;
 import org.jeecg.modules.message.service.ISysMessageTemplateService;
 import org.jeecg.modules.message.websocket.WebSocket;
 import org.jeecg.modules.system.entity.*;
@@ -58,11 +62,10 @@ import java.util.*;
 public class SysBaseApiImpl implements ISysBaseAPI {
 	/** 当前系统数据库类型 */
 	private static String DB_TYPE = "";
+
 	@Autowired
 	private ISysMessageTemplateService sysMessageTemplateService;
 	@Resource
-	private SysLogMapper sysLogMapper;
-	@Resource
 	private SysUserMapper userMapper;
 	@Resource
 	private SysUserRoleMapper sysUserRoleMapper;
@@ -82,7 +85,6 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 	private SysDepartMapper departMapper;
 	@Resource
 	private SysCategoryMapper categoryMapper;
-
 	@Autowired
 	private ISysDataSourceService dataSourceService;
 	@Autowired
@@ -91,28 +93,33 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 	private SysPermissionMapper sysPermissionMapper;
 	@Autowired
 	private ISysPermissionDataRuleService sysPermissionDataRuleService;
-
 	@Autowired
 	private ThirdAppWechatEnterpriseServiceImpl wechatEnterpriseService;
 	@Autowired
 	private ThirdAppDingtalkServiceImpl dingtalkService;
-
 	@Autowired
 	ISysCategoryService sysCategoryService;
+	@Autowired
+	private ISysUserService sysUserService;
 
 	@Override
-	@Cacheable(cacheNames=CacheConstant.SYS_USERS_CACHE, key="#username")
+	//@SensitiveDecode
 	public LoginUser getUserByName(String username) {
-		if(oConvertUtils.isEmpty(username)) {
+		//update-begin-author:taoyan date:2022-6-6 for: VUEN-1276 【v3流程图】测试bug 1、通过我发起的流程或者流程实例,查看历史,流程图预览问题
+		if (oConvertUtils.isEmpty(username)) {
 			return null;
 		}
-		LoginUser loginUser = new LoginUser();
-		SysUser sysUser = userMapper.getUserByName(username);
-		if(sysUser==null) {
-			return null;
+		//update-end-author:taoyan date:2022-6-6 for: VUEN-1276 【v3流程图】测试bug 1、通过我发起的流程或者流程实例,查看历史,流程图预览问题
+		LoginUser user = sysUserService.getEncodeUserInfo(username);
+
+		//相同类中方法间调用时脱敏解密 Aop会失效,获取用户信息太重要,此处采用原生解密方法,不采用@SensitiveDecodeAble注解方式
+		try {
+			SensitiveInfoUtil.handlerObject(user, false);
+		} catch (IllegalAccessException e) {
+			e.printStackTrace();
 		}
-		BeanUtils.copyProperties(sysUser, loginUser);
-		return loginUser;
+
+		return user;
 	}
 
 	@Override
@@ -204,6 +211,14 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 		SysUserCacheInfo info = new SysUserCacheInfo();
 		info.setOneDepart(true);
 		LoginUser user = this.getUserByName(username);
+
+//		try {
+//			//相同类中方法间调用时脱敏@SensitiveDecodeAble解密 Aop失效处理
+//			SensitiveInfoUtil.handlerObject(user, false);
+//		} catch (IllegalAccessException e) {
+//			e.printStackTrace();
+//		}
+
 		if(user!=null) {
 			info.setSysUserCode(user.getUsername());
 			info.setSysUserName(user.getRealname());
@@ -290,7 +305,7 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 	@Override
 	public List<DictModel> queryTableDictItemsByCode(String table, String text, String code) {
 		//update-begin-author:taoyan date:20200820 for:【Online+系统】字典表加权限控制机制逻辑,想法不错 LOWCOD-799
-		if(table.indexOf("#{")>=0){
+		if(table.indexOf(SymbolConstant.SYS_VAR_PREFIX)>=0){
 			table = QueryGenerator.getSqlRuleValue(table);
 		}
 		//update-end-author:taoyan date:20200820 for:【Online+系统】字典表加权限控制机制逻辑,想法不错 LOWCOD-799
@@ -528,15 +543,15 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 			try {
 				DatabaseMetaData md = connection.getMetaData();
 				String dbType = md.getDatabaseProductName().toLowerCase();
-				if(dbType.indexOf("mysql")>=0) {
+				if(dbType.indexOf(DataBaseConstant.DB_TYPE_MYSQL.toLowerCase())>=0) {
 					DB_TYPE = DataBaseConstant.DB_TYPE_MYSQL;
-				}else if(dbType.indexOf("oracle")>=0) {
+				}else if(dbType.indexOf(DataBaseConstant.DB_TYPE_ORACLE.toLowerCase())>=0) {
 					DB_TYPE = DataBaseConstant.DB_TYPE_ORACLE;
-				}else if(dbType.indexOf("sqlserver")>=0||dbType.indexOf("sql server")>=0) {
+				}else if(dbType.indexOf(DataBaseConstant.DB_TYPE_SQLSERVER.toLowerCase())>=0||dbType.indexOf(DataBaseConstant.DB_TYPE_SQL_SERVER_BLANK)>=0) {
 					DB_TYPE = DataBaseConstant.DB_TYPE_SQLSERVER;
-				}else if(dbType.indexOf("postgresql")>=0) {
+				}else if(dbType.indexOf(DataBaseConstant.DB_TYPE_POSTGRESQL.toLowerCase())>=0) {
 					DB_TYPE = DataBaseConstant.DB_TYPE_POSTGRESQL;
-				}else if(dbType.indexOf("mariadb")>=0) {
+				}else if(dbType.indexOf(DataBaseConstant.DB_TYPE_MARIADB.toLowerCase())>=0) {
 					DB_TYPE = DataBaseConstant.DB_TYPE_MARIADB;
 				}else {
 					log.error("数据库类型:[" + dbType + "]不识别!");
@@ -777,6 +792,8 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 		if(userDepartList != null){
 			//查找所属公司
 			String orgCodes = "";
+			StringBuilder orgCodesBuilder = new StringBuilder();
+            orgCodesBuilder.append(orgCodes);
 			for(SysUserDepart userDepart : userDepartList){
 				//查询所属公司编码
 				SysDepart depart = sysDepartService.getById(userDepart.getDepId());
@@ -785,10 +802,11 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 				if(depart != null && depart.getOrgCode() != null){
 					compyOrgCode = depart.getOrgCode().substring(0,length);
 					if(orgCodes.indexOf(compyOrgCode) == -1){
-						orgCodes = orgCodes + "," + compyOrgCode;
+                        orgCodesBuilder.append(SymbolConstant.COMMA).append(compyOrgCode);
 					}
 				}
 			}
+            orgCodes = orgCodesBuilder.toString();
 			if(oConvertUtils.isNotEmpty(orgCodes)){
 				orgCodes = orgCodes.substring(1);
 				List<String> listIds = departMapper.getSubDepIdsByOrgCodes(orgCodes.split(","));
@@ -1037,7 +1055,7 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 	@Override
 	public void sendEmailMsg(String email, String title, String content) {
 			EmailSendMsgHandle emailHandle=new EmailSendMsgHandle();
-			emailHandle.SendMsg(email, title, content);
+			emailHandle.sendMsg(email, title, content);
 	}
 
 	/**
@@ -1154,4 +1172,54 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 		return sysDictService.queryTableDictTextByKeys(table, text, code, Arrays.asList(keys.split(",")));
 	}
 
+	//-------------------------------------流程节点发送模板消息-----------------------------------------------
+	@Autowired
+	private QywxSendMsgHandle qywxSendMsgHandle;
+
+	@Autowired
+	private SystemSendMsgHandle systemSendMsgHandle;
+
+	@Autowired
+	private EmailSendMsgHandle emailSendMsgHandle;
+
+	@Autowired
+	private DdSendMsgHandle ddSendMsgHandle;
+
+	@Override
+	public void sendTemplateMessage(MessageDTO message) {
+		String messageType = message.getType();
+		//update-begin-author:taoyan date:2022-7-9 for: 将模板解析代码移至消息发送, 而不是调用的地方
+		String templateCode = message.getTemplateCode();
+		if(oConvertUtils.isNotEmpty(templateCode)){
+			String content = getTemplateContent(templateCode);
+			if(oConvertUtils.isNotEmpty(content) && null!=message.getData()){
+				content = FreemarkerParseFactory.parseTemplateContent(content, message.getData());
+			}
+			message.setContent(content);
+		}
+		if(oConvertUtils.isEmpty(message.getContent())){
+			throw new JeecgBootException("发送消息失败,消息内容为空!");
+		}
+		//update-end-author:taoyan date:2022-7-9 for: 将模板解析代码移至消息发送, 而不是调用的地方
+		if(MessageTypeEnum.XT.getType().equals(messageType)){
+			systemSendMsgHandle.sendMessage(message);
+		}else if(MessageTypeEnum.YJ.getType().equals(messageType)){
+			emailSendMsgHandle.sendMessage(message);
+		}else if(MessageTypeEnum.DD.getType().equals(messageType)){
+			ddSendMsgHandle.sendMessage(message);
+		}else if(MessageTypeEnum.QYWX.getType().equals(messageType)){
+			qywxSendMsgHandle.sendMessage(message);
+		}
+	}
+
+	@Override
+	public String getTemplateContent(String code) {
+		List<SysMessageTemplate> list = sysMessageTemplateService.selectByCode(code);
+		if(list==null || list.size()==0){
+			return null;
+		}
+		return list.get(0).getTemplateContent();
+	}
+	//-------------------------------------流程节点发送模板消息-----------------------------------------------
+
 }
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java
index 1c0401c..437be4e 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java
@@ -5,7 +5,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.FillRuleConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.util.FillRuleUtil;
 import org.jeecg.common.util.oConvertUtils;
@@ -43,8 +45,8 @@ public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCa
 			if(!ISysCategoryService.ROOT_PID_VALUE.equals(categoryPid)){
 				SysCategory parent = baseMapper.selectById(categoryPid);
 				parentCode = parent.getCode();
-				if(parent!=null && !"1".equals(parent.getHasChild())){
-					parent.setHasChild("1");
+				if(parent!=null && !ISysCategoryService.HAS_CHILD.equals(parent.getHasChild())){
+					parent.setHasChild(ISysCategoryService.HAS_CHILD);
 					baseMapper.updateById(parent);
 				}
 			}
@@ -66,8 +68,8 @@ public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCa
 		}else{
 			//如果当前节点父ID不为空 则设置父节点的hasChild 为1
 			SysCategory parent = baseMapper.selectById(sysCategory.getPid());
-			if(parent!=null && !"1".equals(parent.getHasChild())){
-				parent.setHasChild("1");
+			if(parent!=null && !ISysCategoryService.HAS_CHILD.equals(parent.getHasChild())){
+				parent.setHasChild(ISysCategoryService.HAS_CHILD);
 				baseMapper.updateById(parent);
 			}
 		}
@@ -170,14 +172,15 @@ public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCa
 				queryWrapper.eq(SysCategory::getPid,metaPid);
 				queryWrapper.notIn(SysCategory::getId,Arrays.asList(idArr));
 				List<SysCategory> dataList = this.baseMapper.selectList(queryWrapper);
-				if((dataList == null || dataList.size()==0) && !Arrays.asList(idArr).contains(metaPid)
-						&& !sb.toString().contains(metaPid)){
+                boolean flag = (dataList == null || dataList.size()==0) && !Arrays.asList(idArr).contains(metaPid)
+                        && !sb.toString().contains(metaPid);
+                if(flag){
 					//如果当前节点原本有子节点 现在木有了,更新状态
 					sb.append(metaPid).append(",");
 				}
 			}
 		}
-		if(sb.toString().endsWith(",")){
+		if(sb.toString().endsWith(SymbolConstant.COMMA)){
 			sb = sb.deleteCharAt(sb.length() - 1);
 		}
 		return sb.toString();
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDataSourceServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDataSourceServiceImpl.java
index 048e63e..f3052ec 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDataSourceServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDataSourceServiceImpl.java
@@ -1,11 +1,22 @@
 package org.jeecg.modules.system.service.impl;
 
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import com.baomidou.dynamic.datasource.creator.DruidDataSourceCreator;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.commons.lang.StringUtils;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.util.dynamic.db.DataSourceCachePool;
 import org.jeecg.modules.system.entity.SysDataSource;
 import org.jeecg.modules.system.mapper.SysDataSourceMapper;
 import org.jeecg.modules.system.service.ISysDataSourceService;
+import org.jeecg.modules.system.util.SecurityUtil;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import javax.sql.DataSource;
+
 /**
  * @Description: 多数据源管理
  * @Author: jeecg-boot
@@ -15,4 +26,106 @@ import org.springframework.stereotype.Service;
 @Service
 public class SysDataSourceServiceImpl extends ServiceImpl<SysDataSourceMapper, SysDataSource> implements ISysDataSourceService {
 
+    @Autowired
+    private DruidDataSourceCreator dataSourceCreator;
+
+    @Autowired
+    private DataSource dataSource;
+
+    @Override
+    public Result saveDataSource(SysDataSource sysDataSource) {
+        try {
+            long count = checkDbCode(sysDataSource.getCode());
+            if (count > 0) {
+                return Result.error("数据源编码已存在");
+            }
+            String dbPassword = sysDataSource.getDbPassword();
+            if (StringUtils.isNotBlank(dbPassword)) {
+                String encrypt = SecurityUtil.jiami(dbPassword);
+                sysDataSource.setDbPassword(encrypt);
+            }
+            boolean result = save(sysDataSource);
+            if (result) {
+                //动态创建数据源
+                //addDynamicDataSource(sysDataSource, dbPassword);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return Result.OK("添加成功!");
+    }
+
+    @Override
+    public Result editDataSource(SysDataSource sysDataSource) {
+        try {
+            SysDataSource d = getById(sysDataSource.getId());
+            DataSourceCachePool.removeCache(d.getCode());
+            String dbPassword = sysDataSource.getDbPassword();
+            if (StringUtils.isNotBlank(dbPassword)) {
+                String encrypt = SecurityUtil.jiami(dbPassword);
+                sysDataSource.setDbPassword(encrypt);
+            }
+            Boolean result=updateById(sysDataSource);
+            if(result){
+                //先删除老的数据源
+               // removeDynamicDataSource(d.getCode());
+                //添加新的数据源
+                //addDynamicDataSource(sysDataSource,dbPassword);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return Result.OK("编辑成功!");
+    }
+
+    @Override
+    public Result deleteDataSource(String id) {
+        SysDataSource sysDataSource = getById(id);
+        DataSourceCachePool.removeCache(sysDataSource.getCode());
+        removeById(id);
+        return Result.OK("删除成功!");
+    }
+
+    /**
+     * 动态添加数据源 【注册mybatis动态数据源】
+     *
+     * @param sysDataSource 添加数据源数据对象
+     * @param dbPassword    未加密的密码
+     */
+    private void addDynamicDataSource(SysDataSource sysDataSource, String dbPassword) {
+        DataSourceProperty dataSourceProperty = new DataSourceProperty();
+        dataSourceProperty.setUrl(sysDataSource.getDbUrl());
+        dataSourceProperty.setPassword(dbPassword);
+        dataSourceProperty.setDriverClassName(sysDataSource.getDbDriver());
+        dataSourceProperty.setUsername(sysDataSource.getDbUsername());
+        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
+        DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
+        try {
+            ds.addDataSource(sysDataSource.getCode(), dataSource);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 删除数据源
+     * @param code
+     */
+    private void removeDynamicDataSource(String code) {
+        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
+        ds.removeDataSource(code);
+    }
+
+    /**
+     * 检查数据源编码是否存在
+     *
+     * @param dbCode
+     * @return
+     */
+    private long checkDbCode(String dbCode) {
+        QueryWrapper<SysDataSource> qw = new QueryWrapper();
+        qw.lambda().eq(true, SysDataSource::getCode, dbCode);
+        return count(qw);
+    }
+
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
index 5de598d..3b3aa21 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
@@ -10,6 +10,7 @@ import org.apache.commons.lang.StringUtils;
 import org.jeecg.common.constant.CacheConstant;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.FillRuleConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.util.FillRuleUtil;
 import org.jeecg.common.util.YouBianCodeUtil;
 import org.jeecg.common.util.oConvertUtils;
@@ -469,14 +470,14 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
 	 */
 	private String getMinLengthNode(String[] str){
 		int min =str[0].length();
-		String orgCode = str[0];
+		StringBuilder orgCodeBuilder = new StringBuilder(str[0]);
 		for(int i =1;i<str.length;i++){
 			if(str[i].length()<=min){
 				min = str[i].length();
-				orgCode = orgCode+","+str[i];
+                orgCodeBuilder.append(SymbolConstant.COMMA).append(str[i]);
 			}
 		}
-		return orgCode;
+		return orgCodeBuilder.toString();
 	}
     /**
      * 获取部门树信息根据关键字
@@ -504,13 +505,18 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
 	 * 根据parentId查询部门树
 	 * @param parentId
 	 * @param ids 前端回显传递
+	 * @param primaryKey 主键字段(id或者orgCode)
 	 * @return
 	 */
 	@Override
-	public List<SysDepartTreeModel> queryTreeListByPid(String parentId,String ids) {
+	public List<SysDepartTreeModel> queryTreeListByPid(String parentId,String ids, String primaryKey) {
 		Consumer<LambdaQueryWrapper<SysDepart>> square = i -> {
 			if (oConvertUtils.isNotEmpty(ids)) {
-				i.in(SysDepart::getId, ids.split(","));
+				if (CommonConstant.DEPART_KEY_ORG_CODE.equals(primaryKey)) {
+					i.in(SysDepart::getOrgCode, ids.split(SymbolConstant.COMMA));
+				} else {
+					i.in(SysDepart::getId, ids.split(SymbolConstant.COMMA));
+				}
 			} else {
 				if(oConvertUtils.isEmpty(parentId)){
 					i.and(q->q.isNull(true,SysDepart::getParentId).or().eq(true,SysDepart::getParentId,""));
@@ -519,10 +525,12 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
 				}
 			}
 		};
-		LambdaQueryWrapper<SysDepart> lqw=new LambdaQueryWrapper();
+		LambdaQueryWrapper<SysDepart> lqw=new LambdaQueryWrapper<>();
 		lqw.eq(true,SysDepart::getDelFlag,CommonConstant.DEL_FLAG_0.toString());
 		lqw.func(square);
-		lqw.orderByDesc(SysDepart::getDepartOrder);
+        //update-begin---author:wangshuai ---date:20220527  for:[VUEN-1143]排序不对,vue3和2应该都有问题,应该按照升序排------------
+		lqw.orderByAsc(SysDepart::getDepartOrder);
+        //update-end---author:wangshuai ---date:20220527  for:[VUEN-1143]排序不对,vue3和2应该都有问题,应该按照升序排--------------
 		List<SysDepart> list = list(lqw);
         //update-begin---author:wangshuai ---date:20220316  for:[JTC-119]在部门管理菜单下设置部门负责人 创建用户的时候不需要处理
         //设置用户id,让前台显示
@@ -549,7 +557,7 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
 	@Override
 	public JSONObject queryAllParentIdByDepartId(String departId) {
 		JSONObject result = new JSONObject();
-		for (String id : departId.split(",")) {
+		for (String id : departId.split(SymbolConstant.COMMA)) {
 			JSONObject all = this.queryAllParentId("id", id);
 			result.put(id, all);
 		}
@@ -559,7 +567,7 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
 	@Override
 	public JSONObject queryAllParentIdByOrgCode(String orgCode) {
 		JSONObject result = new JSONObject();
-		for (String code : orgCode.split(",")) {
+		for (String code : orgCode.split(SymbolConstant.COMMA)) {
 			JSONObject all = this.queryAllParentId("org_code", code);
 			result.put(code, all);
 		}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java
index 6662166..c1fe226 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java
@@ -7,8 +7,11 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.constant.CacheConstant;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.DataBaseConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.system.util.ResourceUtil;
 import org.jeecg.common.system.vo.DictModel;
 import org.jeecg.common.system.vo.DictModelMany;
 import org.jeecg.common.system.vo.DictQuery;
@@ -25,10 +28,7 @@ import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -97,6 +97,10 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 			}).collect(Collectors.toList());
 			res.put(d.getDictCode(), dictModelList);
 		}
+		//update-begin-author:taoyan date:2022-7-8 for: 系统字典数据应该包括自定义的java类-枚举
+		Map<String, List<DictModel>> enumRes = ResourceUtil.getEnumDictData();
+		res.putAll(enumRes);
+		//update-end-author:taoyan date:2022-7-8 for: 系统字典数据应该包括自定义的java类-枚举
 		log.debug("-------登录加载系统字典-----" + res.toString());
 		return res;
 	}
@@ -123,6 +127,10 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 			List<DictModel> dictItemList = dictMap.computeIfAbsent(dict.getDictCode(), i -> new ArrayList<>());
 			dictItemList.add(new DictModel(dict.getValue(), dict.getText()));
 		}
+		//update-begin-author:taoyan date:2022-7-8 for: 系统字典数据应该包括自定义的java类-枚举
+		Map<String, List<DictModel>> enumRes = ResourceUtil.queryManyDictByKeys(dictCodeList, keys);
+		dictMap.putAll(enumRes);
+		//update-end-author:taoyan date:2022-7-8 for: 系统字典数据应该包括自定义的java类-枚举
 		return dictMap;
 	}
 
@@ -167,7 +175,7 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 	public List<DictModel> queryTableDictTextByKeys(String table, String text, String code, List<String> keys) {
 		//update-begin-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件
 		String filterSql = null;
-		if(table.toLowerCase().indexOf("where")>0){
+		if(table.toLowerCase().indexOf(DataBaseConstant.SQL_WHERE)>0){
 			String[] arr = table.split(" (?i)where ");
 			table = arr[0];
 			filterSql = arr[1];
@@ -200,7 +208,16 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 			return null;
 		}
 		String[] keyArray = keys.split(",");
-		List<DictModel> dicts = sysDictMapper.queryTableDictByKeys(table, text, code, keyArray);
+
+		//update-begin-author:taoyan date:2022-4-24 for: 下拉搜索组件,表单编辑页面回显下拉搜索的文本的时候,因为表名后配置了条件,导致sql执行失败,
+		String filterSql = null;
+		if(table.toLowerCase().indexOf("where")!=-1){
+			String[] arr = table.split(" (?i)where ");
+			table = arr[0];
+			filterSql = arr[1];
+		}
+		List<DictModel> dicts = sysDictMapper.queryTableDictByKeysAndFilterSql(table, text, code, filterSql, Arrays.asList(keyArray));
+		//update-end-author:taoyan date:2022-4-24 for: 下拉搜索组件,表单编辑页面回显下拉搜索的文本的时候,因为表名后配置了条件,导致sql执行失败,
 		List<String> texts = new ArrayList<>(dicts.size());
 
 		// update-begin--author:sunjianlei--date:20210514--for:新增delNotExist参数,设为false不删除数据库里不存在的key ----
@@ -261,15 +278,19 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 		return baseMapper.queryAllUserBackDictModel();
 	}
 	
-	@Override
-	public List<DictModel> queryTableDictItems(String table, String text, String code, String keyword) {
-		return baseMapper.queryTableDictItems(table, text, code, "%"+keyword+"%");
-	}
+//	@Override
+//	public List<DictModel> queryTableDictItems(String table, String text, String code, String keyword) {
+//		return baseMapper.queryTableDictItems(table, text, code, "%"+keyword+"%");
+//	}
 
 	@Override
 	public List<DictModel> queryLittleTableDictItems(String table, String text, String code, String condition, String keyword, int pageSize) {
     	Page<DictModel> page = new Page<DictModel>(1, pageSize);
 		page.setSearchCount(false);
+
+		//【issues/3713】字典接口存在SQL注入风险
+		SqlInjectionUtil.specialFilterContentForDictSql(code);
+
 		String filterSql = getFilterSql(table, text, code, condition, keyword);
 		IPage<DictModel> pageList = baseMapper.queryTableDictWithFilter(page, table, text, code, filterSql);
 		return pageList.getRecords();
@@ -284,15 +305,15 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 	 * @return
 	 */
 	private String getFilterSql(String table, String text, String code, String condition, String keyword){
-		String keywordSql = null, filterSql = "", sql_where = " where ";
+		String keywordSql = null, filterSql = "", sqlWhere = " where ";
 		// update-begin-author:sunjianlei date:20220112 for: 【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错
-		if (table.toLowerCase().contains(" where ")) {
-			sql_where = " and ";
+        if (table.toLowerCase().contains(sqlWhere)) {
+            sqlWhere = " and ";
 		}
 		// update-end-author:sunjianlei date:20220112 for: 【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错
 		if(oConvertUtils.isNotEmpty(keyword)){
 			// 判断是否是多选
-			if (keyword.contains(",")) {
+			if (keyword.contains(SymbolConstant.COMMA)) {
                 //update-begin--author:scott--date:20220105--for:JTC-529【表单设计器】 编辑页面报错,in参数采用双引号导致 ----
 				String inKeywords = "'" + String.join("','", keyword.split(",")) + "'";
                 //update-end--author:scott--date:20220105--for:JTC-529【表单设计器】 编辑页面报错,in参数采用双引号导致----
@@ -302,11 +323,11 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 			}
 		}
 		if(oConvertUtils.isNotEmpty(condition) && oConvertUtils.isNotEmpty(keywordSql)){
-			filterSql+= sql_where + condition + " and " + keywordSql;
+			filterSql+= sqlWhere + condition + " and " + keywordSql;
 		}else if(oConvertUtils.isNotEmpty(condition)){
-			filterSql+= sql_where + condition;
+			filterSql+= sqlWhere + condition;
 		}else if(oConvertUtils.isNotEmpty(keywordSql)){
-			filterSql+= sql_where + keywordSql;
+			filterSql+= sqlWhere + keywordSql;
 		}
 		return filterSql;
 	}
@@ -319,13 +340,7 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 
 	@Override
 	public List<TreeSelectModel> queryTreeList(Map<String, String> query,String table, String text, String code, String pidField,String pid,String hasChildField) {
-		List<TreeSelectModel> result = baseMapper.queryTreeList(query, table, text, code, pidField, pid, hasChildField);
-		// udapte-begin-author:sunjianlei date:20220110 for: 【JTC-597】如果 query 有值,就不允许展开子节点
-		if (query != null) {
-			result.forEach(r -> r.setLeaf(true));
-		}
-		return result;
-		// udapte-end-author:sunjianlei date:20220110 for: 【JTC-597】如果 query 有值,就不允许展开子节点
+		return baseMapper.queryTreeList(query, table, text, code, pidField, pid, hasChildField);
 	}
 
 	@Override
@@ -354,7 +369,7 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 	@Override
 	public List<DictModel> getDictItems(String dictCode) {
 		List<DictModel> ls;
-		if (dictCode.contains(",")) {
+		if (dictCode.contains(SymbolConstant.COMMA)) {
 			//关联表字典(举例:sys_user,realname,id)
 			String[] params = dictCode.split(",");
 			if (params.length < 3) {
@@ -362,11 +377,16 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 				return null;
 			}
 			//SQL注入校验(只限制非法串改数据库)
-			final String[] sqlInjCheck = {params[0], params[1], params[2]};
+			//update-begin-author:taoyan date:2022-7-4 for: issues/I5BNY9 指定带过滤条件的字典table在生成代码后失效
+			// 表名后也有可能带条件and语句 不能走filterContent方法
+			SqlInjectionUtil.specialFilterContentForDictSql(params[0]);
+			final String[] sqlInjCheck = {params[1], params[2]};
+			//update-end-author:taoyan date:2022-7-4 for: issues/I5BNY9 指定带过滤条件的字典table在生成代码后失效
+			//【issues/3713】字典接口存在SQL注入风险
 			SqlInjectionUtil.filterContent(sqlInjCheck);
 			if (params.length == 4) {
 				// SQL注入校验(查询条件SQL 特殊check,此方法仅供此处使用)
-				SqlInjectionUtil.specialFilterContent(params[3]);
+				SqlInjectionUtil.specialFilterContentForDictSql(params[3]);
 				ls = this.queryTableDictItemsByCodeAndFilter(params[0], params[1], params[2], params[3]);
 			} else if (params.length == 3) {
 				ls = this.queryTableDictItemsByCode(params[0], params[1], params[2]);
@@ -383,7 +403,10 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 
 	@Override
 	public List<DictModel> loadDict(String dictCode, String keyword, Integer pageSize) {
-		if (dictCode.contains(",")) {
+		//【issues/3713】字典接口存在SQL注入风险
+		SqlInjectionUtil.specialFilterContentForDictSql(dictCode);
+
+		if (dictCode.contains(SymbolConstant.COMMA)) {
 			//update-begin-author:taoyan date:20210329 for: 下拉搜索不支持表名后加查询条件
 			String[] params = dictCode.split(",");
 			String condition = null;
@@ -393,11 +416,16 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 			} else if (params.length == 4) {
 				condition = params[3];
 				// update-begin-author:taoyan date:20220314 for: online表单下拉搜索框表字典配置#{sys_org_code}报错 #3500
-				if(condition.indexOf("#{")>=0){
+				if(condition.indexOf(SymbolConstant.SYS_VAR_PREFIX)>=0){
 					condition =  QueryGenerator.getSqlRuleValue(condition);
 				}
 				// update-end-author:taoyan date:20220314 for: online表单下拉搜索框表字典配置#{sys_org_code}报错 #3500
 			}
+
+			// 字典Code格式不正确 [表名为空]
+			if(oConvertUtils.isEmpty(params[0])){
+				return null;
+			}
 			List<DictModel> ls;
 			if (pageSize != null) {
 				ls = this.queryLittleTableDictItems(params[0], params[1], params[2], condition, keyword, pageSize);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysGatewayRouteServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysGatewayRouteServiceImpl.java
index 18c3649..1853103 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysGatewayRouteServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysGatewayRouteServiceImpl.java
@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.base.BaseMap;
 import org.jeecg.common.constant.CacheConstant;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.GlobalConstants;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.system.entity.SysGatewayRoute;
@@ -35,6 +36,7 @@ public class SysGatewayRouteServiceImpl extends ServiceImpl<SysGatewayRouteMappe
     @Autowired
     private RedisTemplate<String, Object> redisTemplate;
 
+    private static final String STRING_STATUS = "status";
 
     @Override
     public void addRoute2Redis(String key) {
@@ -75,10 +77,10 @@ public class SysGatewayRouteServiceImpl extends ServiceImpl<SysGatewayRouteMappe
             }
             route.setFilters(filters);
             route.setUri(json.getString("uri"));
-            if (json.get("status") == null) {
+            if (json.get(STRING_STATUS) == null) {
                 route.setStatus(1);
             } else {
-                route.setStatus(json.getInteger("status"));
+                route.setStatus(json.getInteger(STRING_STATUS));
             }
             this.saveOrUpdate(route);
             resreshRouter(null);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysLogServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysLogServiceImpl.java
index e9b561d..e226c3c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysLogServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysLogServiceImpl.java
@@ -31,8 +31,6 @@ public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> impleme
 
 	@Resource
 	private SysLogMapper sysLogMapper;
-	@Autowired
-	private SysBaseApiImpl sysBaseAPI;
 	
 	/**
 	 * @功能:清空所有日志记录
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionDataRuleImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionDataRuleImpl.java
index 69b7c12..be7c3f7 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionDataRuleImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionDataRuleImpl.java
@@ -88,7 +88,8 @@ public class SysPermissionDataRuleImpl extends ServiceImpl<SysPermissionDataRule
 	public void savePermissionDataRule(SysPermissionDataRule sysPermissionDataRule) {
 		this.save(sysPermissionDataRule);
 		SysPermission permission = sysPermissionMapper.selectById(sysPermissionDataRule.getPermissionId());
-		if(permission!=null && (permission.getRuleFlag()==null || permission.getRuleFlag().equals(CommonConstant.RULE_FLAG_0))) {
+        boolean flag = permission != null && (permission.getRuleFlag() == null || permission.getRuleFlag().equals(CommonConstant.RULE_FLAG_0));
+        if(flag) {
 			permission.setRuleFlag(CommonConstant.RULE_FLAG_1);
 			sysPermissionMapper.updateById(permission);
 		}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java
index 88b93ff..f40c163 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java
@@ -200,7 +200,8 @@ public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, S
 			
 			//如果当前菜单的父菜单变了,则需要修改新父菜单和老父菜单的,叶子节点状态
 			String pid = sysPermission.getParentId();
-			if((oConvertUtils.isNotEmpty(pid) && !pid.equals(p.getParentId())) || oConvertUtils.isEmpty(pid)&&oConvertUtils.isNotEmpty(p.getParentId())) {
+            boolean flag = (oConvertUtils.isNotEmpty(pid) && !pid.equals(p.getParentId())) || oConvertUtils.isEmpty(pid)&&oConvertUtils.isNotEmpty(p.getParentId());
+            if (flag) {
 				//a.设置新的父菜单不为叶子节点
 				this.sysPermissionMapper.setMenuLeaf(pid, 0);
 				//b.判断老的菜单下是否还有其他子菜单,没有的话则设置为叶子节点
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java
index 4089360..4749c2e 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java
@@ -44,13 +44,13 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
 	 */
 	@Override
 	public List<DepartIdModel> queryDepartIdsOfUser(String userId) {
-		LambdaQueryWrapper<SysUserDepart> queryUDep = new LambdaQueryWrapper<SysUserDepart>();
+		LambdaQueryWrapper<SysUserDepart> queryUserDep = new LambdaQueryWrapper<SysUserDepart>();
 		LambdaQueryWrapper<SysDepart> queryDep = new LambdaQueryWrapper<SysDepart>();
 		try {
-			queryUDep.eq(SysUserDepart::getUserId, userId);
+            queryUserDep.eq(SysUserDepart::getUserId, userId);
 			List<String> depIdList = new ArrayList<>();
 			List<DepartIdModel> depIdModelList = new ArrayList<>();
-			List<SysUserDepart> userDepList = this.list(queryUDep);
+			List<SysUserDepart> userDepList = this.list(queryUserDep);
 			if(userDepList != null && userDepList.size() > 0) {
 			for(SysUserDepart userDepart : userDepList) {
 					depIdList.add(userDepart.getDepId());
@@ -78,10 +78,10 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
 	 */
 	@Override
 	public List<SysUser> queryUserByDepId(String depId) {
-		LambdaQueryWrapper<SysUserDepart> queryUDep = new LambdaQueryWrapper<SysUserDepart>();
-		queryUDep.eq(SysUserDepart::getDepId, depId);
+		LambdaQueryWrapper<SysUserDepart> queryUserDep = new LambdaQueryWrapper<SysUserDepart>();
+		queryUserDep.eq(SysUserDepart::getDepId, depId);
 		List<String> userIdList = new ArrayList<>();
-		List<SysUserDepart> uDepList = this.list(queryUDep);
+		List<SysUserDepart> uDepList = this.list(queryUserDep);
 		if(uDepList != null && uDepList.size() > 0) {
 			for(SysUserDepart uDep : uDepList) {
 				userIdList.add(uDep.getUserId());
@@ -121,7 +121,7 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
 	}
 
 	@Override
-	public IPage<SysUser> queryDepartUserPageList(String departId, String username, String realname, int pageSize, int pageNo) {
+	public IPage<SysUser> queryDepartUserPageList(String departId, String username, String realname, int pageSize, int pageNo,String id) {
 		IPage<SysUser> pageList = null;
 		// 部门ID不存在 直接查询用户表即可
 		Page<SysUser> page = new Page<SysUser>(pageNo, pageSize);
@@ -133,6 +133,11 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
 			if(oConvertUtils.isNotEmpty(username)){
 				query.like(SysUser::getUsername, username);
 			}
+            //update-begin---author:wangshuai ---date:20220608  for:[VUEN-1238]邮箱回复时,发送到显示的为用户id------------
+            if(oConvertUtils.isNotEmpty(id)){
+                query.eq(SysUser::getId, id);
+            }
+            //update-end---author:wangshuai ---date:20220608  for:[VUEN-1238]邮箱回复时,发送到显示的为用户id------------
 			pageList = sysUserMapper.selectPage(page, query);
 		}else{
 			// 有部门ID 需要走自定义sql
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java
index 3316a9f..71dea40 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java
@@ -9,6 +9,9 @@ import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CacheConstant;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.enums.RoleIndexConfigEnum;
+import org.jeecg.common.desensitization.annotation.SensitiveEncode;
+import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.system.vo.SysUserCacheInfo;
 import org.jeecg.common.util.PasswordUtil;
 import org.jeecg.common.util.UUIDGenerator;
@@ -19,6 +22,7 @@ import org.jeecg.modules.system.mapper.*;
 import org.jeecg.modules.system.model.SysUserSysDepartModel;
 import org.jeecg.modules.system.service.ISysUserService;
 import org.jeecg.modules.system.vo.SysUserDepVo;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.Cacheable;
@@ -65,6 +69,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 	ThirdAppWechatEnterpriseServiceImpl wechatEnterpriseService;
 	@Autowired
 	ThirdAppDingtalkServiceImpl dingtalkService;
+	@Autowired
+	SysRoleIndexMapper sysRoleIndexMapper;
 
     @Override
     @CacheEvict(value = {CacheConstant.SYS_USERS_CACHE}, allEntries = true)
@@ -155,7 +161,40 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 	public List<String> getRole(String username) {
 		return sysUserRoleMapper.getRoleByUserName(username);
 	}
-	
+
+	/**
+	 * 获取动态首页路由配置
+	 * @param username
+	 * @param version
+	 * @return
+	 */
+	@Override
+	public SysRoleIndex getDynamicIndexByUserRole(String username,String version) {
+		List<String> roles = sysUserRoleMapper.getRoleByUserName(username);
+		String componentUrl = RoleIndexConfigEnum.getIndexByRoles(roles);
+		SysRoleIndex roleIndex = new SysRoleIndex(componentUrl);
+		//只有 X-Version=v3 的时候,才读取sys_role_index表获取角色首页配置
+		if (oConvertUtils.isNotEmpty(version) && roles!=null && roles.size()>0) {
+			LambdaQueryWrapper<SysRoleIndex> routeIndexQuery = new LambdaQueryWrapper();
+			//用户所有角色
+			routeIndexQuery.in(SysRoleIndex::getRoleCode, roles);
+			//角色首页状态0:未开启  1:开启
+			routeIndexQuery.eq(SysRoleIndex::getStatus, CommonConstant.STATUS_1);
+			//优先级正序排序
+			routeIndexQuery.orderByAsc(SysRoleIndex::getPriority);
+			List<SysRoleIndex> list = sysRoleIndexMapper.selectList(routeIndexQuery);
+			if (null != list && list.size() > 0) {
+				roleIndex = list.get(0);
+			}
+		}
+		
+		//如果componentUrl为空,则返回空
+		if(oConvertUtils.isEmpty(roleIndex.getComponent())){
+			return null;
+		}
+		return roleIndex;
+	}
+
 	/**
 	 * 通过用户名获取用户角色集合
 	 * @param username 用户名
@@ -200,7 +239,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 	 * @return
 	 */
 	@Override
-	@Cacheable(cacheNames=CacheConstant.SYS_USERS_CACHE, key="#username")
 	public SysUserCacheInfo getCacheUser(String username) {
 		SysUserCacheInfo info = new SysUserCacheInfo();
 		info.setOneDepart(true);
@@ -558,4 +596,19 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 		return userList.stream().map(SysUser::getUsername).collect(Collectors.toList());
 	}
 
+	@Override
+	@Cacheable(cacheNames=CacheConstant.SYS_USERS_CACHE, key="#username")
+	@SensitiveEncode
+	public LoginUser getEncodeUserInfo(String username){
+		if(oConvertUtils.isEmpty(username)) {
+			return null;
+		}
+		LoginUser loginUser = new LoginUser();
+		SysUser sysUser = userMapper.getUserByName(username);
+		if(sysUser==null) {
+			return null;
+		}
+		BeanUtils.copyProperties(sysUser, loginUser);
+		return loginUser;
+	}
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java
index 02a54b0..f7391a0 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java
@@ -67,15 +67,20 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
     private SysAnnouncementSendMapper sysAnnouncementSendMapper;
 
     /**
+     * errcode
+     */
+    private static final String ERR_CODE = "errcode";
+
+    /**
      * 第三方APP类型,当前固定为 wechat_enterprise
      */
     public final String THIRD_TYPE = ThirdAppConfig.WECHAT_ENTERPRISE.toLowerCase();
 
     @Override
     public String getAccessToken() {
-        String CORP_ID = thirdAppConfig.getWechatEnterprise().getClientId();
-        String SECRET = thirdAppConfig.getWechatEnterprise().getClientSecret();
-        AccessToken accessToken = JwAccessTokenAPI.getAccessToken(CORP_ID, SECRET);
+        String corpId = thirdAppConfig.getWechatEnterprise().getClientId();
+        String secret = thirdAppConfig.getWechatEnterprise().getClientSecret();
+        AccessToken accessToken = JwAccessTokenAPI.getAccessToken(corpId, secret);
         if (accessToken != null) {
             return accessToken.getAccesstoken();
         }
@@ -85,14 +90,14 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
 
     /** 获取APPToken,新版企业微信的秘钥是分开的 */
     public String getAppAccessToken() {
-        String CORP_ID = thirdAppConfig.getWechatEnterprise().getClientId();
-        String SECRET = thirdAppConfig.getWechatEnterprise().getAgentAppSecret();
+        String corpId = thirdAppConfig.getWechatEnterprise().getClientId();
+        String secret = thirdAppConfig.getWechatEnterprise().getAgentAppSecret();
         // 如果没有配置APP秘钥,就说明是老企业,可以通用秘钥
-        if (oConvertUtils.isEmpty(SECRET)) {
-            SECRET = thirdAppConfig.getWechatEnterprise().getClientSecret();
+        if (oConvertUtils.isEmpty(secret)) {
+            secret = thirdAppConfig.getWechatEnterprise().getClientSecret();
         }
 
-        AccessToken accessToken = JwAccessTokenAPI.getAccessToken(CORP_ID, SECRET);
+        AccessToken accessToken = JwAccessTokenAPI.getAccessToken(corpId, secret);
         if (accessToken != null) {
             return accessToken.getAccesstoken();
         }
@@ -464,6 +469,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
                 case 60104:
                     msg = "手机号码已存在";
                     break;
+                default:
             }
             String str = String.format("用户 %s(%s) 同步失败!错误码:%s——%s", sysUser.getUsername(), sysUser.getRealname(), errCode, msg);
             syncInfo.addFailInfo(str);
@@ -567,7 +573,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
         // 企业微信规则:1表示启用成员,0表示禁用成员
         // JEECG规则:1正常,2冻结
         if (sysUser.getStatus() != null) {
-            if (sysUser.getStatus() == 1 || sysUser.getStatus() == 2) {
+            if (CommonConstant.USER_UNFREEZE.equals(sysUser.getStatus()) || CommonConstant.USER_FREEZE.equals(sysUser.getStatus())) {
                 user.setEnable(sysUser.getStatus() == 1 ? 1 : 0);
             } else {
                 user.setEnable(1);
@@ -837,7 +843,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
         JSONObject response = JwUserAPI.getUserInfoByCode(code, accessToken);
         if (response != null) {
             log.info("response: " + response.toJSONString());
-            if (response.getIntValue("errcode") == 0) {
+            if (response.getIntValue(ERR_CODE) == 0) {
                 return response.getString("UserId");
             }
         }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/PermissionDataUtil.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/PermissionDataUtil.java
index 2438fcc..211740a 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/PermissionDataUtil.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/PermissionDataUtil.java
@@ -2,6 +2,8 @@ package org.jeecg.modules.system.util;
 
 import java.util.List;
 
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.system.entity.SysPermission;
 
@@ -11,6 +13,21 @@ import org.jeecg.modules.system.entity.SysPermission;
  */
 public class PermissionDataUtil {
 
+    /**
+     * 路径:views/
+     */
+    private static final String PATH_VIEWS = "views/";
+
+    /**
+     * 路径:src/views/
+     */
+    private static final String PATH_SRC_VIEWS = "src/views/";
+
+    /**
+     * .vue后缀
+     */
+    private static final String VUE_SUFFIX = ".vue";
+
 	/**
 	 * 智能处理错误数据,简化用户失误操作
 	 * 
@@ -24,17 +41,17 @@ public class PermissionDataUtil {
 		// 组件
 		if (oConvertUtils.isNotEmpty(permission.getComponent())) {
 			String component = permission.getComponent();
-			if (component.startsWith("/")) {
+			if (component.startsWith(SymbolConstant.SINGLE_SLASH)) {
 				component = component.substring(1);
 			}
-			if (component.startsWith("views/")) {
-				component = component.replaceFirst("views/", "");
+			if (component.startsWith(PATH_VIEWS)) {
+				component = component.replaceFirst(PATH_VIEWS, "");
 			}
-			if (component.startsWith("src/views/")) {
-				component = component.replaceFirst("src/views/", "");
+			if (component.startsWith(PATH_SRC_VIEWS)) {
+				component = component.replaceFirst(PATH_SRC_VIEWS, "");
 			}
-			if (component.endsWith(".vue")) {
-				component = component.replace(".vue", "");
+			if (component.endsWith(VUE_SUFFIX)) {
+				component = component.replace(VUE_SUFFIX, "");
 			}
 			permission.setComponent(component);
 		}
@@ -42,11 +59,11 @@ public class PermissionDataUtil {
 		// 请求URL
 		if (oConvertUtils.isNotEmpty(permission.getUrl())) {
 			String url = permission.getUrl();
-			if (url.endsWith(".vue")) {
-				url = url.replace(".vue", "");
+			if (url.endsWith(VUE_SUFFIX)) {
+				url = url.replace(VUE_SUFFIX, "");
 			}
-			if (!url.startsWith("http") && !url.startsWith("/")&&!url.trim().startsWith("{{")) {
-				url = "/" + url;
+			if (!url.startsWith(CommonConstant.STR_HTTP) && !url.startsWith(SymbolConstant.SINGLE_SLASH)&&!url.trim().startsWith(SymbolConstant.DOUBLE_LEFT_CURLY_BRACKET)) {
+				url = SymbolConstant.SINGLE_SLASH + url;
 			}
 			permission.setUrl(url);
 		}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/RandImageUtil.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/RandImageUtil.java
index d9e7fe4..3311d68 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/RandImageUtil.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/RandImageUtil.java
@@ -15,26 +15,26 @@ import java.util.Random;
  */
 public class RandImageUtil {
 
-    public static final String key = "JEECG_LOGIN_KEY";
+    public static final String KEY = "JEECG_LOGIN_KEY";
 
     /**
      * 定义图形大小
      */
-    private static final int width = 105;
+    private static final int WIDTH = 105;
     /**
      * 定义图形大小
      */
-    private static final int height = 35;
+    private static final int HEIGHT = 35;
 
     /**
      * 定义干扰线数量
      */
-    private static final int count = 200;
+    private static final int COUNT = 200;
 
     /**
      * 干扰线的长度=1.414*lineWidth
      */
-    private static final int lineWidth = 2;
+    private static final int LINE_WIDTH = 2;
 
     /**
      * 图片格式
@@ -85,28 +85,28 @@ public class RandImageUtil {
 
     private static BufferedImage getImageBuffer(String resultCode){
         // 在内存中创建图象
-        final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        final BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
         // 获取图形上下文
         final Graphics2D graphics = (Graphics2D) image.getGraphics();
         // 设定背景颜色
         // ---1
         graphics.setColor(Color.WHITE);
-        graphics.fillRect(0, 0, width, height);
+        graphics.fillRect(0, 0, WIDTH, HEIGHT);
         // 设定边框颜色
 //		graphics.setColor(getRandColor(100, 200)); // ---2
-        graphics.drawRect(0, 0, width - 1, height - 1);
+        graphics.drawRect(0, 0, WIDTH - 1, HEIGHT - 1);
 
         final Random random = new Random();
         // 随机产生干扰线,使图象中的认证码不易被其它程序探测到
-        for (int i = 0; i < count; i++) {
+        for (int i = 0; i < COUNT; i++) {
             // ---3
             graphics.setColor(getRandColor(150, 200));
 
             // 保证画在边框之内
-            final int x = random.nextInt(width - lineWidth - 1) + 1;
-            final int y = random.nextInt(height - lineWidth - 1) + 1;
-            final int xl = random.nextInt(lineWidth);
-            final int yl = random.nextInt(lineWidth);
+            final int x = random.nextInt(WIDTH - LINE_WIDTH - 1) + 1;
+            final int y = random.nextInt(HEIGHT - LINE_WIDTH - 1) + 1;
+            final int xl = random.nextInt(LINE_WIDTH);
+            final int yl = random.nextInt(LINE_WIDTH);
             graphics.drawLine(x, y, x + xl, y + yl);
         }
         // 取随机产生的认证码
@@ -129,11 +129,12 @@ public class RandImageUtil {
 
     private static Color getRandColor(int fc, int bc) { // 取得给定范围随机颜色
         final Random random = new Random();
-        if (fc > 255) {
-            fc = 255;
+        int length = 255;
+        if (fc > length) {
+            fc = length;
         }
-        if (bc > 255) {
-            bc = 255;
+        if (bc > length) {
+            bc = length;
         }
 
         final int r = fc + random.nextInt(bc - fc);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/XssUtils.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/XssUtils.java
new file mode 100644
index 0000000..1fbb380
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/XssUtils.java
@@ -0,0 +1,49 @@
+package org.jeecg.modules.system.util;
+
+import org.springframework.web.util.HtmlUtils;
+
+import java.util.regex.Pattern;
+
+/**
+ * @Description: 工具类XSSUtils,现在的做法是替换成空字符,CSDN的是进行转义,比如文字开头的"<"转成&lt;
+ * @author: lsq
+ * @date: 2021年07月26日 19:13
+ */
+public class XssUtils {
+
+    private static Pattern[] patterns = new Pattern[]{
+        //Script fragments
+        Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
+        //src='...'
+        Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
+        Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
+        //script tags
+        Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
+        Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
+        //eval(...)
+        Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
+        //expression(...)
+        Pattern.compile("e­xpression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
+        //javascript:...
+        Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
+        //vbscript:...
+        Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
+        //onload(...)=...
+        Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
+    };
+
+    public static String scriptXss(String value) {
+        if (value != null) {
+            value = value.replaceAll(" ", "");
+            for(Pattern scriptPattern: patterns){
+                value = scriptPattern.matcher(value).replaceAll("");
+            }
+        }
+        return HtmlUtils.htmlEscape(value);
+    }
+
+    public static void main(String[] args) {
+        String s = scriptXss("<img  src=x onload=alert(111).*?><script></script>javascript:eval()\\\\.");
+        System.err.println("s======>" + s);
+    }
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-dev.yml b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-dev.yml
index d8057f0..3c76532 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-dev.yml
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-dev.yml
@@ -184,7 +184,11 @@ jeecg:
   # 签名密钥串(前后端要一致,正式发布请自行修改)
   signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a
   # 本地:local\Minio:minio\阿里云:alioss
-  uploadType: local
+  uploadType: minio
+  # 前端访问地址
+  domainUrl:
+    pc: http://localhost:3100
+    app: http://localhost:8051
   path:
     #文件上传根目录 设置
     upload: /opt/upFiles
@@ -328,4 +332,4 @@ third-app:
       client-id: ??
       # appSecret
       client-secret: ??
-      agent-id: ??
\ No newline at end of file
+      agent-id: ??
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml
index 2db8fb0..773ad14 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml
@@ -39,10 +39,10 @@ spring:
   quartz:
     job-store-type: jdbc
     initialize-schema: embedded
-    #延迟1秒启动定时任务
-    startup-delay: 1s
     #定时任务启动开关,true-开  false-关
     auto-startup: true
+    #延迟1秒启动定时任务
+    startup-delay: 1s
     #启动时更新己存在的Job
     overwrite-existing-jobs: true
     properties:
@@ -185,6 +185,10 @@ jeecg:
   signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a
   # 本地:local\Minio:minio\阿里云:alioss
   uploadType: alioss
+  # 前端访问地址
+  domainUrl:
+    pc: http://localhost:3100
+    app: http://localhost:8051
   path:
     #文件上传根目录 设置
     upload: /opt/jeecg-boot/upload
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-test.yml b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-test.yml
index 671e559..1371d31 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-test.yml
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-test.yml
@@ -185,6 +185,10 @@ jeecg:
   signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a
   # 本地:local\Minio:minio\阿里云:alioss
   uploadType: local
+  # 前端访问地址
+  domainUrl:
+    pc: http://localhost:3100
+    app: http://localhost:8051
   path:
     #文件上传根目录 设置
     upload: D://opt//upFiles
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt b/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt
index 21783e0..14ea568 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt
@@ -9,6 +9,6 @@ ${AnsiColor.BRIGHT_BLUE}
 
 
 ${AnsiColor.BRIGHT_GREEN}
-Jeecg  Boot Version: 3.2.0
+Jeecg  Boot Version: 3.3.0
 Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}
 ${AnsiColor.BLACK}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/sql/menu_insert.ftl b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/sql/menu_insert.ftl
index ac35200..ced8333 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/sql/menu_insert.ftl
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/sql/menu_insert.ftl
@@ -1,5 +1,27 @@
 -- 注意:该页面对应的前台目录为views/${entityPackage}文件夹下
 -- 如果你想更改到其他目录,请修改sql中component字段对应的值
 
+<#assign id = '${.now?string["yyyyMMddhhmmSSsss"]}0'>
+
 INSERT INTO sys_permission(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive, hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time, update_by, update_time, internal_or_external) 
-VALUES ('${.now?string["yyyyMMddhhmmSSsss"]}', NULL, '${tableVo.ftlDescription}', '/${entityPackage}/${entityName?uncap_first}List', '${entityPackage}/${entityName}List', NULL, NULL, 0, NULL, '1', 1.00, 0, NULL, 1, 1, 0, 0, 0, NULL, '1', 0, 0, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0);
\ No newline at end of file
+VALUES ('${id}', NULL, '${tableVo.ftlDescription}', '/${entityPackage}/${entityName?uncap_first}List', '${entityPackage}/${entityName}List', NULL, NULL, 0, NULL, '1', 1.00, 0, NULL, 1, 1, 0, 0, 0, NULL, '1', 0, 0, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0);
+
+-- 权限控制sql
+-- 新增
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('${.now?string["yyyyMMddhhmmSSsss"]}1', '${id}', '添加${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${bussiPackage}:${tableName}:add', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
+-- 编辑
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('${.now?string["yyyyMMddhhmmSSsss"]}2', '${id}', '编辑${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${bussiPackage}:${tableName}:edit', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
+-- 删除
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('${.now?string["yyyyMMddhhmmSSsss"]}3', '${id}', '删除${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${bussiPackage}:${tableName}:delete', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
+-- 批量删除
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('${.now?string["yyyyMMddhhmmSSsss"]}4', '${id}', '批量删除${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${bussiPackage}:${tableName}:deleteBatch', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
+-- 导出excel
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('${.now?string["yyyyMMddhhmmSSsss"]}5', '${id}', '导出excel_${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${bussiPackage}:${tableName}:exportXls', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
+-- 导入excel
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('${.now?string["yyyyMMddhhmmSSsss"]}6', '${id}', '导入excel_${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${bussiPackage}:${tableName}:importExcel', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/validatorRulesTemplate/core.ftl b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/validatorRulesTemplate/core.ftl
index 2b43ff6..c3a2143 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/validatorRulesTemplate/core.ftl
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/validatorRulesTemplate/core.ftl
@@ -32,7 +32,7 @@
               { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
         <#-- 邮政编码 -->
         <#elseif fieldValidType == 'p'>
-              { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+              { pattern: /^[0-9]\d{5}$/, message: '请输入正确的邮政编码!'},
         <#-- 字母 -->
         <#elseif fieldValidType == 's'>
               { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/validatorRulesTemplate/native/vue3CoreNative.ftl b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/validatorRulesTemplate/native/vue3CoreNative.ftl
index 45b269f..2c395d5 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/validatorRulesTemplate/native/vue3CoreNative.ftl
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/validatorRulesTemplate/native/vue3CoreNative.ftl
@@ -28,7 +28,7 @@
  { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}<#rt>,
 <#-- 邮政编码 -->
 <#elseif fieldValidType == 'p'>
- { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}<#rt>,
+ { pattern: /^[0-9]\d{5}$/, message: '请输入正确的邮政编码!'}<#rt>,
 <#-- 字母 -->
 <#elseif fieldValidType == 's'>
  { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}<#rt>,
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
index d7236b2..d12e75c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
@@ -86,6 +86,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-添加")
 	@ApiOperation(value="${tableVo.ftlDescription}-添加", notes="${tableVo.ftlDescription}-添加")
+	//@RequiresPermissions("${bussiPackage}:${tableName}:add")
 	@PostMapping(value = "/add")
 	public Result<String> add(@RequestBody ${entityName} ${entityName?uncap_first}) {
 	    <#if bpm_flag>
@@ -103,6 +104,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
 	@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
+	//@RequiresPermissions("${bussiPackage}:${tableName}:edit")
 	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<String> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
 		${entityName?uncap_first}Service.updateById(${entityName?uncap_first});
@@ -117,6 +119,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-通过id删除")
 	@ApiOperation(value="${tableVo.ftlDescription}-通过id删除", notes="${tableVo.ftlDescription}-通过id删除")
+	//@RequiresPermissions("${bussiPackage}:${tableName}:delete")
 	@DeleteMapping(value = "/delete")
 	public Result<String> delete(@RequestParam(name="id",required=true) String id) {
 		${entityName?uncap_first}Service.removeById(id);
@@ -131,6 +134,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-批量删除")
 	@ApiOperation(value="${tableVo.ftlDescription}-批量删除", notes="${tableVo.ftlDescription}-批量删除")
+	//@RequiresPermissions("${bussiPackage}:${tableName}:deleteBatch")
 	@DeleteMapping(value = "/deleteBatch")
 	public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
 		this.${entityName?uncap_first}Service.removeByIds(Arrays.asList(ids.split(",")));
@@ -160,6 +164,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
     * @param request
     * @param ${entityName?uncap_first}
     */
+    //@RequiresPermissions("${bussiPackage}:${tableName}:exportXls")
     @RequestMapping(value = "/exportXls")
     public ModelAndView exportXls(HttpServletRequest request, ${entityName} ${entityName?uncap_first}) {
         return super.exportXls(request, ${entityName?uncap_first}, ${entityName}.class, "${tableVo.ftlDescription}");
@@ -172,6 +177,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
     * @param response
     * @return
     */
+    //@RequiresPermissions("${tableName}:importExcel")
     @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
     public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
         return super.importExcel(request, response, ${entityName}.class);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
index 2d379bd..5400008 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
@@ -55,7 +55,7 @@
           <template v-if="toggleSearchStatus">
     </#if>
           <#-- update-begin-author:taoyan date:20220303 for: /issues/3420 内嵌风格,datetime控件样式异常 -->
-          <#if po.queryModel=='group' && po.classType=='datetime'>
+          <#if po.queryMode?default("")?trim=='group' && po.classType=='datetime'>
           ${indent}<a-col :xl="10" :lg="12" :md="12" :sm="24">
           <#else>
           ${indent}<a-col :xl="6" :lg="7" :md="8" :sm="24">
diff --git a/jeecg-boot/jeecg-boot-module-system/src/test/java/org/jeecg/modules/system/test/SysUserTest.java b/jeecg-boot/jeecg-boot-module-system/src/test/java/org/jeecg/modules/system/test/SysUserTest.java
index a02448a..5c1d38f 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/test/java/org/jeecg/modules/system/test/SysUserTest.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/test/java/org/jeecg/modules/system/test/SysUserTest.java
@@ -1,5 +1,6 @@
 package org.jeecg.modules.system.test;
 
+import com.alibaba.fastjson.JSONObject;
 import org.jeecg.JeecgSystemApplication;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.util.JwtUtil;
@@ -9,13 +10,11 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.ActiveProfiles;
-import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.MediaType;
-import com.alibaba.fastjson.JSONObject;
 import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.junit4.SpringRunner;
 
 /**
  * 系统用户单元测试