limeng 1 年之前
父節點
當前提交
dbc75ed43c
共有 100 個文件被更改,包括 10275 次插入15 次删除
  1. 15 15
      pom.xml
  2. 97 0
      src/main/java/com/baidu/ueditor/ActionEnter.java
  3. 8 0
      src/main/java/com/baidu/ueditor/App.java
  4. 155 0
      src/main/java/com/baidu/ueditor/ConfigManager.java
  5. 17 0
      src/main/java/com/baidu/ueditor/Encoder.java
  6. 123 0
      src/main/java/com/baidu/ueditor/PathFormat.java
  7. 32 0
      src/main/java/com/baidu/ueditor/define/ActionMap.java
  8. 6 0
      src/main/java/com/baidu/ueditor/define/ActionState.java
  9. 50 0
      src/main/java/com/baidu/ueditor/define/AppInfo.java
  10. 85 0
      src/main/java/com/baidu/ueditor/define/BaseState.java
  11. 22 0
      src/main/java/com/baidu/ueditor/define/FileType.java
  12. 21 0
      src/main/java/com/baidu/ueditor/define/MIMEType.java
  13. 88 0
      src/main/java/com/baidu/ueditor/define/MultiState.java
  14. 12 0
      src/main/java/com/baidu/ueditor/define/State.java
  15. 82 0
      src/main/java/com/baidu/ueditor/hunter/FileManager.java
  16. 104 0
      src/main/java/com/baidu/ueditor/hunter/ImageHunter.java
  17. 35 0
      src/main/java/com/baidu/ueditor/upload/Base64Uploader.java
  18. 72 0
      src/main/java/com/baidu/ueditor/upload/BinaryUploader.java
  19. 121 0
      src/main/java/com/baidu/ueditor/upload/StorageManager.java
  20. 29 0
      src/main/java/com/baidu/ueditor/upload/Uploader.java
  21. 44 0
      src/main/java/com/freemarker/AuthenticatedTag.java
  22. 42 0
      src/main/java/com/freemarker/GuestTag.java
  23. 19 0
      src/main/java/com/freemarker/HasAnyPermissionsTag.java
  24. 51 0
      src/main/java/com/freemarker/HasAnyRolesTag.java
  25. 12 0
      src/main/java/com/freemarker/HasPermissionTag.java
  26. 10 0
      src/main/java/com/freemarker/HasRoleTag.java
  27. 10 0
      src/main/java/com/freemarker/LacksPermissionTag.java
  28. 11 0
      src/main/java/com/freemarker/LacksRoleTag.java
  29. 32 0
      src/main/java/com/freemarker/NotAuthenticatedTag.java
  30. 55 0
      src/main/java/com/freemarker/PermissionTag.java
  31. 119 0
      src/main/java/com/freemarker/PrincipalTag.java
  32. 27 0
      src/main/java/com/freemarker/RoleTag.java
  33. 44 0
      src/main/java/com/freemarker/SecureTag.java
  34. 24 0
      src/main/java/com/freemarker/ShiroTags.java
  35. 37 0
      src/main/java/com/freemarker/UserTag.java
  36. 25 0
      src/main/java/com/jagregory/shiro/freemarker/AuthenticatedTag.java
  37. 25 0
      src/main/java/com/jagregory/shiro/freemarker/GuestTag.java
  38. 25 0
      src/main/java/com/jagregory/shiro/freemarker/HasAnyPermissionsTag.java
  39. 30 0
      src/main/java/com/jagregory/shiro/freemarker/HasAnyRolesTag.java
  40. 9 0
      src/main/java/com/jagregory/shiro/freemarker/HasPermissionTag.java
  41. 9 0
      src/main/java/com/jagregory/shiro/freemarker/HasRoleTag.java
  42. 9 0
      src/main/java/com/jagregory/shiro/freemarker/LacksPermissionTag.java
  43. 9 0
      src/main/java/com/jagregory/shiro/freemarker/LacksRoleTag.java
  44. 23 0
      src/main/java/com/jagregory/shiro/freemarker/NotAuthenticatedTag.java
  45. 54 0
      src/main/java/com/jagregory/shiro/freemarker/PermissionTag.java
  46. 72 0
      src/main/java/com/jagregory/shiro/freemarker/PrincipalTag.java
  47. 23 0
      src/main/java/com/jagregory/shiro/freemarker/RoleTag.java
  48. 44 0
      src/main/java/com/jagregory/shiro/freemarker/SecureTag.java
  49. 20 0
      src/main/java/com/jagregory/shiro/freemarker/ShiroTags.java
  50. 23 0
      src/main/java/com/jagregory/shiro/freemarker/UserTag.java
  51. 89 0
      src/main/java/com/mingsoft/ueditor/MsUeditorActionEnter.java
  52. 54 0
      src/main/java/net/mingsoft/base/MSVersion.java
  53. 332 0
      src/main/java/net/mingsoft/base/action/BaseAction.java
  54. 367 0
      src/main/java/net/mingsoft/base/biz/IBaseBiz.java
  55. 260 0
      src/main/java/net/mingsoft/base/biz/impl/BaseBizImpl.java
  56. 52 0
      src/main/java/net/mingsoft/base/constant/Const.java
  57. 32 0
      src/main/java/net/mingsoft/base/constant/e/BaseCookieEnum.java
  58. 38 0
      src/main/java/net/mingsoft/base/constant/e/BaseEnum.java
  59. 31 0
      src/main/java/net/mingsoft/base/constant/e/BaseSessionEnum.java
  60. 59 0
      src/main/java/net/mingsoft/base/constant/e/DeleteEnum.java
  61. 267 0
      src/main/java/net/mingsoft/base/dao/IBaseDao.java
  62. 500 0
      src/main/java/net/mingsoft/base/dao/IBaseDao.xml
  63. 275 0
      src/main/java/net/mingsoft/base/entity/BaseEntity.java
  64. 177 0
      src/main/java/net/mingsoft/base/entity/ResultData.java
  65. 94 0
      src/main/java/net/mingsoft/base/exception/BusinessException.java
  66. 36 0
      src/main/java/net/mingsoft/base/job/BaseJob.java
  67. 56 0
      src/main/java/net/mingsoft/base/resolver/MultipartResolver.java
  68. 182 0
      src/main/java/net/mingsoft/base/util/BundleUtil.java
  69. 53 0
      src/main/java/net/mingsoft/base/util/FtlUtil.java
  70. 94 0
      src/main/java/net/mingsoft/base/util/PropertiesUtil.java
  71. 122 0
      src/main/java/net/mingsoft/base/util/SqlInjectionUtil.java
  72. 258 0
      src/main/java/net/mingsoft/basic/action/AppAction.java
  73. 218 0
      src/main/java/net/mingsoft/basic/action/BaseAction.java
  74. 161 0
      src/main/java/net/mingsoft/basic/action/BaseFileAction.java
  75. 468 0
      src/main/java/net/mingsoft/basic/action/CityAction.java
  76. 164 0
      src/main/java/net/mingsoft/basic/action/LogAction.java
  77. 173 0
      src/main/java/net/mingsoft/basic/action/MainAction.java
  78. 180 0
      src/main/java/net/mingsoft/basic/action/ManageFileAction.java
  79. 316 0
      src/main/java/net/mingsoft/basic/action/ManagerAction.java
  80. 642 0
      src/main/java/net/mingsoft/basic/action/ModelAction.java
  81. 228 0
      src/main/java/net/mingsoft/basic/action/RoleAction.java
  82. 118 0
      src/main/java/net/mingsoft/basic/action/SystemAction.java
  83. 482 0
      src/main/java/net/mingsoft/basic/action/TemplateAction.java
  84. 109 0
      src/main/java/net/mingsoft/basic/action/web/CityAction.java
  85. 88 0
      src/main/java/net/mingsoft/basic/action/web/CodeAction.java
  86. 86 0
      src/main/java/net/mingsoft/basic/action/web/EditorAction.java
  87. 73 0
      src/main/java/net/mingsoft/basic/action/web/FileAction.java
  88. 92 0
      src/main/java/net/mingsoft/basic/action/web/IndexAction.java
  89. 142 0
      src/main/java/net/mingsoft/basic/action/web/LoginAction.java
  90. 60 0
      src/main/java/net/mingsoft/basic/annotation/LogAnn.java
  91. 102 0
      src/main/java/net/mingsoft/basic/aop/BaseAop.java
  92. 216 0
      src/main/java/net/mingsoft/basic/aop/BaseLogAop.java
  93. 218 0
      src/main/java/net/mingsoft/basic/aop/FileVerifyAop.java
  94. 59 0
      src/main/java/net/mingsoft/basic/aop/ManagerPasswordAop.java
  95. 89 0
      src/main/java/net/mingsoft/basic/aop/SaveOrUpdateAop.java
  96. 47 0
      src/main/java/net/mingsoft/basic/aop/SystemLogAop.java
  97. 80 0
      src/main/java/net/mingsoft/basic/bean/CityBean.java
  98. 64 0
      src/main/java/net/mingsoft/basic/bean/EUListBean.java
  99. 61 0
      src/main/java/net/mingsoft/basic/bean/ListBean.java
  100. 0 0
      src/main/java/net/mingsoft/basic/bean/LogBean.java

+ 15 - 15
pom.xml

@@ -41,16 +41,16 @@
         -->
     </repositories>
     <dependencies>
-        <dependency>
-            <groupId>net.mingsoft</groupId>
-            <artifactId>ms-base</artifactId>
-            <version>2.1.26</version>
-        </dependency>
-        <dependency>
-            <groupId>net.mingsoft</groupId>
-            <artifactId>ms-basic</artifactId>
-            <version>2.1.26</version>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>net.mingsoft</groupId>-->
+<!--            <artifactId>ms-base</artifactId>-->
+<!--            <version>2.1.26</version>-->
+<!--        </dependency>-->
+<!--        <dependency>-->
+<!--            <groupId>net.mingsoft</groupId>-->
+<!--            <artifactId>ms-basic</artifactId>-->
+<!--            <version>2.1.26</version>-->
+<!--        </dependency>-->
         <dependency>
             <groupId>net.mingsoft</groupId>
             <artifactId>ms-mdiy</artifactId>
@@ -58,11 +58,11 @@
         </dependency>
 
         <!--store入口依赖(源码不开发),如果不需要MStore可以直接去掉依赖-->
-        <dependency>
-            <groupId>net.mingsoft</groupId>
-            <artifactId>store-client</artifactId>
-            <version>2.1.26</version>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>net.mingsoft</groupId>-->
+<!--            <artifactId>store-client</artifactId>-->
+<!--            <version>2.1.26</version>-->
+<!--        </dependency>-->
         <dependency>
             <groupId>com.github.oshi</groupId>
             <artifactId>oshi-core</artifactId>

+ 97 - 0
src/main/java/com/baidu/ueditor/ActionEnter.java

@@ -0,0 +1,97 @@
+package com.baidu.ueditor;
+
+import com.baidu.ueditor.define.ActionMap;
+import com.baidu.ueditor.define.AppInfo;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.State;
+import com.baidu.ueditor.hunter.FileManager;
+import com.baidu.ueditor.hunter.ImageHunter;
+import com.baidu.ueditor.upload.Uploader;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/ActionEnter.class */
+public class ActionEnter {
+    private HttpServletRequest request;
+    private String rootPath;
+    private String contextPath;
+    private String actionType;
+    private ConfigManager configManager;
+
+    public ActionEnter(HttpServletRequest request, String rootPath) {
+        this.request = null;
+        this.rootPath = null;
+        this.contextPath = null;
+        this.actionType = null;
+        this.configManager = null;
+        this.request = request;
+        this.rootPath = rootPath;
+        this.actionType = request.getParameter("action");
+        this.contextPath = request.getContextPath();
+        this.configManager = ConfigManager.getInstance(this.rootPath, this.contextPath, request.getRequestURI());
+    }
+
+    public String exec() {
+        String callbackName = this.request.getParameter("callback");
+        if (callbackName == null) {
+            return invoke();
+        }
+        if (!validCallbackName(callbackName)) {
+            return new BaseState(false, (int) AppInfo.ILLEGAL).toJSONString();
+        }
+        return callbackName + "(" + invoke() + ");";
+    }
+
+    public String invoke() {
+        if (this.actionType == null || !ActionMap.mapping.containsKey(this.actionType)) {
+            return new BaseState(false, (int) AppInfo.INVALID_ACTION).toJSONString();
+        }
+        if (this.configManager == null || !this.configManager.valid()) {
+            return new BaseState(false, (int) AppInfo.CONFIG_ERROR).toJSONString();
+        }
+        State state = null;
+        int actionCode = ActionMap.getType(this.actionType);
+        switch (actionCode) {
+            case 0:
+                return this.configManager.getAllConfig().toString();
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+                state = new Uploader(this.request, this.configManager.getConfig(actionCode)).doExec();
+                break;
+            case 5:
+                Map<String, Object> conf = this.configManager.getConfig(actionCode);
+                state = new ImageHunter(conf).capture(this.request.getParameterValues((String) conf.get("fieldName")));
+                break;
+            case 6:
+            case 7:
+                state = new FileManager(this.configManager.getConfig(actionCode)).listFile(getStartIndex());
+                break;
+        }
+        return state.toJSONString();
+    }
+
+    public int getStartIndex() {
+        try {
+            return Integer.parseInt(this.request.getParameter("start"));
+        } catch (Exception e) {
+            return 0;
+        }
+    }
+
+    public boolean validCallbackName(String name) {
+        if (name.matches("^[a-zA-Z_]+[\\w0-9_]*$")) {
+            return true;
+        }
+        return false;
+    }
+
+    public ConfigManager getConfigManager() {
+        return this.configManager;
+    }
+
+    public void setConfigManager(ConfigManager configManager) {
+        this.configManager = configManager;
+    }
+}

+ 8 - 0
src/main/java/com/baidu/ueditor/App.java

@@ -0,0 +1,8 @@
+package com.baidu.ueditor;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/App.class */
+public class App {
+    public static void main(String[] args) {
+        System.out.println("Hello World!");
+    }
+}

+ 155 - 0
src/main/java/com/baidu/ueditor/ConfigManager.java

@@ -0,0 +1,155 @@
+package com.baidu.ueditor;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/ConfigManager.class */
+public final class ConfigManager {
+    private final String rootPath;
+    private final String originalPath;
+    private final String contextPath;
+    private static final String configFileName = "config.json";
+    private String parentPath = null;
+    private JSONObject jsonConfig = null;
+    private static final String SCRAWL_FILE_NAME = "scrawl";
+    private static final String REMOTE_FILE_NAME = "remote";
+
+    private ConfigManager(String rootPath, String contextPath, String uri) throws FileNotFoundException, IOException {
+        this.rootPath = rootPath.replace("\\", "/");
+        this.contextPath = contextPath;
+        if (contextPath.length() > 0) {
+            this.originalPath = this.rootPath + uri.substring(contextPath.length());
+        } else {
+            this.originalPath = this.rootPath + uri;
+        }
+        initEnv();
+    }
+
+    public static ConfigManager getInstance(String rootPath, String contextPath, String uri) {
+        try {
+            return new ConfigManager(rootPath, contextPath, uri);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public boolean valid() {
+        return this.jsonConfig != null;
+    }
+
+    public JSONObject getAllConfig() {
+        return this.jsonConfig;
+    }
+
+    public Map<String, Object> getConfig(int type) {
+        Map<String, Object> conf = new HashMap<>();
+        String savePath = null;
+        switch (type) {
+            case 1:
+                conf.put("isBase64", "false");
+                conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("imageMaxSize")));
+                conf.put("allowFiles", getArray("imageAllowFiles"));
+                conf.put("fieldName", this.jsonConfig.getString("imageFieldName"));
+                savePath = this.jsonConfig.getString("imagePathFormat");
+                break;
+            case 2:
+                conf.put("filename", SCRAWL_FILE_NAME);
+                conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("scrawlMaxSize")));
+                conf.put("fieldName", this.jsonConfig.getString("scrawlFieldName"));
+                conf.put("isBase64", "true");
+                savePath = this.jsonConfig.getString("imagePathFormat");
+                break;
+            case 3:
+                conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("videoMaxSize")));
+                conf.put("allowFiles", getArray("videoAllowFiles"));
+                conf.put("fieldName", this.jsonConfig.getString("videoFieldName"));
+                savePath = this.jsonConfig.getString("videoPathFormat");
+                break;
+            case 4:
+                conf.put("isBase64", "false");
+                conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("fileMaxSize")));
+                conf.put("allowFiles", getArray("fileAllowFiles"));
+                conf.put("fieldName", this.jsonConfig.getString("fileFieldName"));
+                savePath = this.jsonConfig.getString("filePathFormat");
+                break;
+            case 5:
+                conf.put("filename", REMOTE_FILE_NAME);
+                conf.put("filter", getArray("catcherLocalDomain"));
+                conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("catcherMaxSize")));
+                conf.put("allowFiles", getArray("catcherAllowFiles"));
+                conf.put("fieldName", this.jsonConfig.getString("catcherFieldName") + "[]");
+                savePath = this.jsonConfig.getString("imagePathFormat");
+                break;
+            case 6:
+                conf.put("allowFiles", getArray("fileManagerAllowFiles"));
+                conf.put("dir", this.jsonConfig.getString("fileManagerListPath"));
+                conf.put("count", Integer.valueOf(this.jsonConfig.getInt("fileManagerListSize")));
+                break;
+            case 7:
+                conf.put("allowFiles", getArray("imageManagerAllowFiles"));
+                conf.put("dir", this.jsonConfig.getString("imageManagerListPath"));
+                conf.put("count", Integer.valueOf(this.jsonConfig.getInt("imageManagerListSize")));
+                break;
+        }
+        conf.put("savePath", savePath);
+        conf.put("rootPath", this.rootPath);
+        return conf;
+    }
+
+    private void initEnv() throws FileNotFoundException, IOException {
+        File file = new File(this.originalPath);
+        if (!file.isAbsolute()) {
+            file = new File(file.getAbsolutePath());
+        }
+        this.parentPath = file.getParent();
+        try {
+            this.jsonConfig = new JSONObject(readFile(getConfigPath()));
+        } catch (Exception e) {
+            this.jsonConfig = null;
+        }
+    }
+
+    private String getConfigPath() {
+        return this.parentPath + File.separator + configFileName;
+    }
+
+    private String[] getArray(String key) {
+        JSONArray jsonArray = this.jsonConfig.getJSONArray(key);
+        String[] result = new String[jsonArray.length()];
+        int len = jsonArray.length();
+        for (int i = 0; i < len; i++) {
+            result[i] = jsonArray.getString(i);
+        }
+        return result;
+    }
+
+    private String readFile(String path) throws IOException {
+        StringBuilder builder = new StringBuilder();
+        try {
+            BufferedReader bfReader = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));
+            while (true) {
+                String tmpContent = bfReader.readLine();
+                if (tmpContent == null) {
+                    break;
+                }
+                builder.append(tmpContent);
+            }
+            bfReader.close();
+        } catch (UnsupportedEncodingException e) {
+        }
+        return filter(builder.toString());
+    }
+
+    private String filter(String input) {
+        return input.replaceAll("/\\*[\\s\\S]*?\\*/", "");
+    }
+}

+ 17 - 0
src/main/java/com/baidu/ueditor/Encoder.java

@@ -0,0 +1,17 @@
+package com.baidu.ueditor;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/Encoder.class */
+public class Encoder {
+    public static String toUnicode(String input) {
+        StringBuilder builder = new StringBuilder();
+        char[] chars = input.toCharArray();
+        for (char ch : chars) {
+            if (ch < 256) {
+                builder.append(ch);
+            } else {
+                builder.append("\\u" + Integer.toHexString(ch & 65535));
+            }
+        }
+        return builder.toString();
+    }
+}

+ 123 - 0
src/main/java/com/baidu/ueditor/PathFormat.java

@@ -0,0 +1,123 @@
+package com.baidu.ueditor;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/PathFormat.class */
+public class PathFormat {
+    private static final String TIME = "time";
+    private static final String FULL_YEAR = "yyyy";
+    private static final String YEAR = "yy";
+    private static final String MONTH = "mm";
+    private static final String DAY = "dd";
+    private static final String HOUR = "hh";
+    private static final String MINUTE = "ii";
+    private static final String SECOND = "ss";
+    private static final String RAND = "rand";
+    private static Date currentDate = null;
+
+    public static String parse(String input) {
+        Matcher matcher = Pattern.compile("\\{([^\\}]+)\\}", 2).matcher(input);
+        currentDate = new Date();
+        StringBuffer sb = new StringBuffer();
+        while (matcher.find()) {
+            matcher.appendReplacement(sb, getString(matcher.group(1)));
+        }
+        matcher.appendTail(sb);
+        return sb.toString();
+    }
+
+    public static String format(String input) {
+        return input.replace("\\", "/");
+    }
+
+    public static String parse(String input, String filename) {
+        Matcher matcher = Pattern.compile("\\{([^\\}]+)\\}", 2).matcher(input);
+        currentDate = new Date();
+        StringBuffer sb = new StringBuffer();
+        while (matcher.find()) {
+            String matchStr = matcher.group(1);
+            if (matchStr.indexOf("filename") != -1) {
+                filename = filename.replace("$", "\\$").replaceAll("[\\/:*?\"<>|]", "");
+                matcher.appendReplacement(sb, filename);
+            } else {
+                matcher.appendReplacement(sb, getString(matchStr));
+            }
+        }
+        matcher.appendTail(sb);
+        return sb.toString();
+    }
+
+    private static String getString(String pattern) {
+        String pattern2 = pattern.toLowerCase();
+        if (pattern2.indexOf(TIME) != -1) {
+            return getTimestamp();
+        }
+        if (pattern2.indexOf(FULL_YEAR) != -1) {
+            return getFullYear();
+        }
+        if (pattern2.indexOf(YEAR) != -1) {
+            return getYear();
+        }
+        if (pattern2.indexOf(MONTH) != -1) {
+            return getMonth();
+        }
+        if (pattern2.indexOf(DAY) != -1) {
+            return getDay();
+        }
+        if (pattern2.indexOf(HOUR) != -1) {
+            return getHour();
+        }
+        if (pattern2.indexOf(MINUTE) != -1) {
+            return getMinute();
+        }
+        if (pattern2.indexOf(SECOND) != -1) {
+            return getSecond();
+        }
+        if (pattern2.indexOf(RAND) != -1) {
+            return getRandom(pattern2);
+        }
+        return pattern2;
+    }
+
+    private static String getTimestamp() {
+        return System.currentTimeMillis() + "";
+    }
+
+    private static String getFullYear() {
+        return new SimpleDateFormat(FULL_YEAR).format(currentDate);
+    }
+
+    private static String getYear() {
+        return new SimpleDateFormat(YEAR).format(currentDate);
+    }
+
+    private static String getMonth() {
+        return new SimpleDateFormat("MM").format(currentDate);
+    }
+
+    private static String getDay() {
+        return new SimpleDateFormat(DAY).format(currentDate);
+    }
+
+    private static String getHour() {
+        return new SimpleDateFormat("HH").format(currentDate);
+    }
+
+    private static String getMinute() {
+        return new SimpleDateFormat(MONTH).format(currentDate);
+    }
+
+    private static String getSecond() {
+        return new SimpleDateFormat(SECOND).format(currentDate);
+    }
+
+    private static String getRandom(String pattern) {
+        return (Math.random() + "").replace(".", "").substring(0, Integer.parseInt(pattern.split(":")[1].trim()));
+    }
+
+    public static void main(String[] args) {
+    }
+}

+ 32 - 0
src/main/java/com/baidu/ueditor/define/ActionMap.java

@@ -0,0 +1,32 @@
+package com.baidu.ueditor.define;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/define/ActionMap.class */
+public final class ActionMap {
+    public static final Map<String, Integer> mapping = new HashMap<String, Integer>() { // from class: com.baidu.ueditor.define.ActionMap.1
+        {
+            put("config", 0);
+            put("uploadimage", 1);
+            put("uploadscrawl", 2);
+            put("uploadvideo", 3);
+            put("uploadfile", 4);
+            put("catchimage", 5);
+            put("listfile", 6);
+            put("listimage", 7);
+        }
+    };
+    public static final int CONFIG = 0;
+    public static final int UPLOAD_IMAGE = 1;
+    public static final int UPLOAD_SCRAWL = 2;
+    public static final int UPLOAD_VIDEO = 3;
+    public static final int UPLOAD_FILE = 4;
+    public static final int CATCH_IMAGE = 5;
+    public static final int LIST_FILE = 6;
+    public static final int LIST_IMAGE = 7;
+
+    public static int getType(String key) {
+        return mapping.get(key).intValue();
+    }
+}

+ 6 - 0
src/main/java/com/baidu/ueditor/define/ActionState.java

@@ -0,0 +1,6 @@
+package com.baidu.ueditor.define;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/define/ActionState.class */
+public enum ActionState {
+    UNKNOW_ERROR
+}

+ 50 - 0
src/main/java/com/baidu/ueditor/define/AppInfo.java

@@ -0,0 +1,50 @@
+package com.baidu.ueditor.define;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/define/AppInfo.class */
+public final class AppInfo {
+    public static final int SUCCESS = 0;
+    public static final int MAX_SIZE = 1;
+    public static final int PERMISSION_DENIED = 2;
+    public static final int FAILED_CREATE_FILE = 3;
+    public static final int IO_ERROR = 4;
+    public static final int NOT_MULTIPART_CONTENT = 5;
+    public static final int PARSE_REQUEST_ERROR = 6;
+    public static final int NOTFOUND_UPLOAD_DATA = 7;
+    public static final int NOT_ALLOW_FILE_TYPE = 8;
+    public static final int INVALID_ACTION = 101;
+    public static final int CONFIG_ERROR = 102;
+    public static final int PREVENT_HOST = 201;
+    public static final int CONNECTION_ERROR = 202;
+    public static final int REMOTE_FAIL = 203;
+    public static final int NOT_DIRECTORY = 301;
+    public static final int NOT_EXIST = 302;
+    public static final int ILLEGAL = 401;
+    public static Map<Integer, String> info = new HashMap<Integer, String>() { // from class: com.baidu.ueditor.define.AppInfo.1
+        {
+            put(0, "SUCCESS");
+            put(Integer.valueOf((int) AppInfo.INVALID_ACTION), "无效的Action");
+            put(Integer.valueOf((int) AppInfo.CONFIG_ERROR), "配置文件初始化失败");
+            put(Integer.valueOf((int) AppInfo.REMOTE_FAIL), "抓取远程图片失败");
+            put(Integer.valueOf((int) AppInfo.PREVENT_HOST), "被阻止的远程主机");
+            put(Integer.valueOf((int) AppInfo.CONNECTION_ERROR), "远程连接出错");
+            put(1, "文件大小超出限制");
+            put(2, "权限不足");
+            put(3, "创建文件失败");
+            put(4, "IO错误");
+            put(5, "上传表单不是multipart/form-data类型");
+            put(6, "解析上传表单错误");
+            put(7, "未找到上传数据");
+            put(8, "不允许的文件类型");
+            put(Integer.valueOf((int) AppInfo.NOT_DIRECTORY), "指定路径不是目录");
+            put(Integer.valueOf((int) AppInfo.NOT_EXIST), "指定路径并不存在");
+            put(Integer.valueOf((int) AppInfo.ILLEGAL), "Callback参数名不合法");
+        }
+    };
+
+    public static String getStateInfo(int key) {
+        return info.get(Integer.valueOf(key));
+    }
+}

+ 85 - 0
src/main/java/com/baidu/ueditor/define/BaseState.java

@@ -0,0 +1,85 @@
+package com.baidu.ueditor.define;
+
+import com.baidu.ueditor.Encoder;
+import java.util.HashMap;
+import java.util.Map;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/define/BaseState.class */
+public class BaseState implements State {
+    private boolean state;
+    private String info;
+    private Map<String, String> infoMap;
+
+    public BaseState() {
+        this.state = false;
+        this.info = null;
+        this.infoMap = new HashMap();
+        this.state = true;
+    }
+
+    public BaseState(boolean state) {
+        this.state = false;
+        this.info = null;
+        this.infoMap = new HashMap();
+        setState(state);
+    }
+
+    public BaseState(boolean state, String info) {
+        this.state = false;
+        this.info = null;
+        this.infoMap = new HashMap();
+        setState(state);
+        this.info = info;
+    }
+
+    public BaseState(boolean state, int infoCode) {
+        this.state = false;
+        this.info = null;
+        this.infoMap = new HashMap();
+        setState(state);
+        this.info = AppInfo.getStateInfo(infoCode);
+    }
+
+    @Override // com.baidu.ueditor.define.State
+    public boolean isSuccess() {
+        return this.state;
+    }
+
+    public void setState(boolean state) {
+        this.state = state;
+    }
+
+    public void setInfo(String info) {
+        this.info = info;
+    }
+
+    public void setInfo(int infoCode) {
+        this.info = AppInfo.getStateInfo(infoCode);
+    }
+
+    @Override // com.baidu.ueditor.define.State
+    public String toJSONString() {
+        return toString();
+    }
+
+    public String toString() {
+        String stateVal = isSuccess() ? AppInfo.getStateInfo(0) : this.info;
+        StringBuilder builder = new StringBuilder();
+        builder.append("{\"state\": \"" + stateVal + "\"");
+        for (String key : this.infoMap.keySet()) {
+            builder.append(",\"" + key + "\": \"" + this.infoMap.get(key) + "\"");
+        }
+        builder.append("}");
+        return Encoder.toUnicode(builder.toString());
+    }
+
+    @Override // com.baidu.ueditor.define.State
+    public void putInfo(String name, String val) {
+        this.infoMap.put(name, val);
+    }
+
+    @Override // com.baidu.ueditor.define.State
+    public void putInfo(String name, long val) {
+        putInfo(name, val + "");
+    }
+}

+ 22 - 0
src/main/java/com/baidu/ueditor/define/FileType.java

@@ -0,0 +1,22 @@
+package com.baidu.ueditor.define;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/define/FileType.class */
+public class FileType {
+    public static final String JPG = "JPG";
+    private static final Map<String, String> types = new HashMap<String, String>() { // from class: com.baidu.ueditor.define.FileType.1
+        {
+            put(FileType.JPG, ".jpg");
+        }
+    };
+
+    public static String getSuffix(String key) {
+        return types.get(key);
+    }
+
+    public static String getSuffixByFilename(String filename) {
+        return filename.substring(filename.lastIndexOf(".")).toLowerCase();
+    }
+}

+ 21 - 0
src/main/java/com/baidu/ueditor/define/MIMEType.java

@@ -0,0 +1,21 @@
+package com.baidu.ueditor.define;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/define/MIMEType.class */
+public class MIMEType {
+    public static final Map<String, String> types = new HashMap<String, String>() { // from class: com.baidu.ueditor.define.MIMEType.1
+        {
+            put("image/gif", ".gif");
+            put("image/jpeg", ".jpg");
+            put("image/jpg", ".jpg");
+            put("image/png", ".png");
+            put("image/bmp", ".bmp");
+        }
+    };
+
+    public static String getSuffix(String mime) {
+        return types.get(mime);
+    }
+}

+ 88 - 0
src/main/java/com/baidu/ueditor/define/MultiState.java

@@ -0,0 +1,88 @@
+package com.baidu.ueditor.define;
+
+import com.baidu.ueditor.Encoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/define/MultiState.class */
+public class MultiState implements State {
+    private boolean state;
+    private String info;
+    private Map<String, Long> intMap;
+    private Map<String, String> infoMap;
+    private List<String> stateList;
+
+    public MultiState(boolean state) {
+        this.state = false;
+        this.info = null;
+        this.intMap = new HashMap();
+        this.infoMap = new HashMap();
+        this.stateList = new ArrayList();
+        this.state = state;
+    }
+
+    public MultiState(boolean state, String info) {
+        this.state = false;
+        this.info = null;
+        this.intMap = new HashMap();
+        this.infoMap = new HashMap();
+        this.stateList = new ArrayList();
+        this.state = state;
+        this.info = info;
+    }
+
+    public MultiState(boolean state, int infoKey) {
+        this.state = false;
+        this.info = null;
+        this.intMap = new HashMap();
+        this.infoMap = new HashMap();
+        this.stateList = new ArrayList();
+        this.state = state;
+        this.info = AppInfo.getStateInfo(infoKey);
+    }
+
+    @Override // com.baidu.ueditor.define.State
+    public boolean isSuccess() {
+        return this.state;
+    }
+
+    public void addState(State state) {
+        this.stateList.add(state.toJSONString());
+    }
+
+    @Override // com.baidu.ueditor.define.State
+    public void putInfo(String name, String val) {
+        this.infoMap.put(name, val);
+    }
+
+    @Override // com.baidu.ueditor.define.State
+    public String toJSONString() {
+        String stateVal = isSuccess() ? AppInfo.getStateInfo(0) : this.info;
+        StringBuilder builder = new StringBuilder();
+        builder.append("{\"state\": \"" + stateVal + "\"");
+        for (String stateVal2 : this.intMap.keySet()) {
+            builder.append(",\"" + stateVal2 + "\": " + this.intMap.get(stateVal2));
+        }
+        for (String stateVal3 : this.infoMap.keySet()) {
+            builder.append(",\"" + stateVal3 + "\": \"" + this.infoMap.get(stateVal3) + "\"");
+        }
+        builder.append(", list: [");
+        Iterator<String> iterator = this.stateList.iterator();
+        while (iterator.hasNext()) {
+            builder.append(iterator.next() + ",");
+        }
+        if (this.stateList.size() > 0) {
+            builder.deleteCharAt(builder.length() - 1);
+        }
+        builder.append(" ]}");
+        return Encoder.toUnicode(builder.toString());
+    }
+
+    @Override // com.baidu.ueditor.define.State
+    public void putInfo(String name, long val) {
+        this.intMap.put(name, Long.valueOf(val));
+    }
+}

+ 12 - 0
src/main/java/com/baidu/ueditor/define/State.java

@@ -0,0 +1,12 @@
+package com.baidu.ueditor.define;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/define/State.class */
+public interface State {
+    boolean isSuccess();
+
+    void putInfo(String str, String str2);
+
+    void putInfo(String str, long j);
+
+    String toJSONString();
+}

+ 82 - 0
src/main/java/com/baidu/ueditor/hunter/FileManager.java

@@ -0,0 +1,82 @@
+package com.baidu.ueditor.hunter;
+
+import com.baidu.ueditor.PathFormat;
+import com.baidu.ueditor.define.AppInfo;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.MultiState;
+import com.baidu.ueditor.define.State;
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import org.apache.commons.io.FileUtils;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/hunter/FileManager.class */
+public class FileManager {
+    private String dir;
+    private String rootPath;
+    private String[] allowFiles;
+    private int count;
+
+    public FileManager(Map<String, Object> conf) {
+        this.dir = null;
+        this.rootPath = null;
+        this.allowFiles = null;
+        this.count = 0;
+        this.rootPath = (String) conf.get("rootPath");
+        this.dir = this.rootPath + ((String) conf.get("dir"));
+        this.allowFiles = getAllowFiles(conf.get("allowFiles"));
+        this.count = ((Integer) conf.get("count")).intValue();
+    }
+
+    public State listFile(int index) {
+        State state;
+        File dir = new File(this.dir);
+        if (!dir.exists()) {
+            return new BaseState(false, (int) AppInfo.NOT_EXIST);
+        }
+        if (!dir.isDirectory()) {
+            return new BaseState(false, (int) AppInfo.NOT_DIRECTORY);
+        }
+        Collection<File> list = FileUtils.listFiles(dir, this.allowFiles, true);
+        if (index < 0 || index > list.size()) {
+            state = new MultiState(true);
+        } else {
+            state = getState(Arrays.copyOfRange(list.toArray(), index, index + this.count));
+        }
+        state.putInfo("start", (long) index);
+        state.putInfo("total", (long) list.size());
+        return state;
+    }
+
+    private State getState(Object[] files) {
+        Object obj;
+        MultiState state = new MultiState(true);
+        int length = files.length;
+        int i = 0;
+        while (i < length && (obj = files[i]) != null) {
+            File file = (File) obj;
+            BaseState fileState = new BaseState(true);
+            fileState.putInfo("url", PathFormat.format(getPath(file)));
+            state.addState(fileState);
+            i++;
+        }
+        return state;
+    }
+
+    private String getPath(File file) {
+        return file.getAbsolutePath().replace(this.rootPath, "/");
+    }
+
+    private String[] getAllowFiles(Object fileExt) {
+        if (fileExt == null) {
+            return new String[0];
+        }
+        String[] exts = (String[]) fileExt;
+        int len = exts.length;
+        for (int i = 0; i < len; i++) {
+            exts[i] = exts[i].replace(".", "");
+        }
+        return exts;
+    }
+}

+ 104 - 0
src/main/java/com/baidu/ueditor/hunter/ImageHunter.java

@@ -0,0 +1,104 @@
+package com.baidu.ueditor.hunter;
+
+import com.baidu.ueditor.PathFormat;
+import com.baidu.ueditor.define.AppInfo;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.MIMEType;
+import com.baidu.ueditor.define.MultiState;
+import com.baidu.ueditor.define.State;
+import com.baidu.ueditor.upload.StorageManager;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/hunter/ImageHunter.class */
+public class ImageHunter {
+    private String filename;
+    private String savePath;
+    private String rootPath;
+    private List<String> allowTypes;
+    private long maxSize;
+    private List<String> filters;
+
+    public ImageHunter(Map<String, Object> conf) {
+        this.filename = null;
+        this.savePath = null;
+        this.rootPath = null;
+        this.allowTypes = null;
+        this.maxSize = -1;
+        this.filters = null;
+        this.filename = (String) conf.get("filename");
+        this.savePath = (String) conf.get("savePath");
+        this.rootPath = (String) conf.get("rootPath");
+        this.maxSize = ((Long) conf.get("maxSize")).longValue();
+        this.allowTypes = Arrays.asList((String[]) conf.get("allowFiles"));
+        this.filters = Arrays.asList((String[]) conf.get("filter"));
+    }
+
+    public State capture(String[] list) {
+        MultiState state = new MultiState(true);
+        for (String source : list) {
+            state.addState(captureRemoteData(source));
+        }
+        return state;
+    }
+
+    public State captureRemoteData(String urlStr) {
+        try {
+            URL url = new URL(urlStr);
+            if (!validHost(url.getHost())) {
+                return new BaseState(false, (int) AppInfo.PREVENT_HOST);
+            }
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+            connection.setInstanceFollowRedirects(true);
+            connection.setUseCaches(true);
+            if (!validContentState(connection.getResponseCode())) {
+                return new BaseState(false, (int) AppInfo.CONNECTION_ERROR);
+            }
+            String suffix = MIMEType.getSuffix(connection.getContentType());
+            if (!validFileType(suffix)) {
+                return new BaseState(false, 8);
+            }
+            if (!validFileSize(connection.getContentLength())) {
+                return new BaseState(false, 1);
+            }
+            String savePath = getPath(this.savePath, this.filename, suffix);
+            State state = StorageManager.saveFileByInputStream(connection.getInputStream(), this.rootPath + savePath);
+            if (state.isSuccess()) {
+                state.putInfo("url", PathFormat.format(savePath));
+                state.putInfo("source", urlStr);
+            }
+            return state;
+        } catch (Exception e) {
+            return new BaseState(false, (int) AppInfo.REMOTE_FAIL);
+        }
+    }
+
+    private String getPath(String savePath, String filename, String suffix) {
+        return PathFormat.parse(savePath + suffix, filename);
+    }
+
+    private boolean validHost(String hostname) {
+        try {
+            return !InetAddress.getByName(hostname).isSiteLocalAddress() && !this.filters.contains(hostname);
+        } catch (UnknownHostException e) {
+            return false;
+        }
+    }
+
+    private boolean validContentState(int code) {
+        return 200 == code;
+    }
+
+    private boolean validFileType(String type) {
+        return this.allowTypes.contains(type);
+    }
+
+    private boolean validFileSize(int size) {
+        return ((long) size) < this.maxSize;
+    }
+}

+ 35 - 0
src/main/java/com/baidu/ueditor/upload/Base64Uploader.java

@@ -0,0 +1,35 @@
+package com.baidu.ueditor.upload;
+
+import com.baidu.ueditor.PathFormat;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.FileType;
+import com.baidu.ueditor.define.State;
+import java.util.Map;
+import org.apache.commons.codec.binary.Base64;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/upload/Base64Uploader.class */
+public final class Base64Uploader {
+    public static State save(String content, Map<String, Object> conf) {
+        byte[] data = decode(content);
+        if (!validSize(data, ((Long) conf.get("maxSize")).longValue())) {
+            return new BaseState(false, 1);
+        }
+        String suffix = FileType.getSuffix(FileType.JPG);
+        String savePath = PathFormat.parse((String) conf.get("savePath"), (String) conf.get("filename")) + suffix;
+        State storageState = StorageManager.saveBinaryFile(data, ((String) conf.get("rootPath")) + savePath);
+        if (storageState.isSuccess()) {
+            storageState.putInfo("url", PathFormat.format(savePath));
+            storageState.putInfo("type", suffix);
+            storageState.putInfo("original", "");
+        }
+        return storageState;
+    }
+
+    private static byte[] decode(String content) {
+        return Base64.decodeBase64(content);
+    }
+
+    private static boolean validSize(byte[] data, long length) {
+        return ((long) data.length) <= length;
+    }
+}

+ 72 - 0
src/main/java/com/baidu/ueditor/upload/BinaryUploader.java

@@ -0,0 +1,72 @@
+package com.baidu.ueditor.upload;
+
+import com.baidu.ueditor.PathFormat;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.FileType;
+import com.baidu.ueditor.define.State;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/upload/BinaryUploader.class */
+public class BinaryUploader {
+    public static final State save(HttpServletRequest request, Map<String, Object> conf) {
+        FileItemStream fileStream = null;
+        boolean isAjaxUpload = request.getHeader("X_Requested_With") != null;
+        if (!ServletFileUpload.isMultipartContent(request)) {
+            return new BaseState(false, 5);
+        }
+        ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
+        if (isAjaxUpload) {
+            upload.setHeaderEncoding("UTF-8");
+        }
+        try {
+            FileItemIterator iterator = upload.getItemIterator(request);
+            while (iterator.hasNext()) {
+                fileStream = iterator.next();
+                if (!fileStream.isFormField()) {
+                    break;
+                }
+                fileStream = null;
+            }
+            if (fileStream == null) {
+                return new BaseState(false, 7);
+            }
+            String savePath = (String) conf.get("savePath");
+            String originFileName = fileStream.getName();
+            String suffix = FileType.getSuffixByFilename(originFileName);
+            String originFileName2 = originFileName.substring(0, originFileName.length() - suffix.length());
+            String savePath2 = savePath + suffix;
+            long maxSize = ((Long) conf.get("maxSize")).longValue();
+            if (!validType(suffix, (String[]) conf.get("allowFiles"))) {
+                return new BaseState(false, 8);
+            }
+            String savePath3 = PathFormat.parse(savePath2, originFileName2);
+            String physicalPath = ((String) conf.get("rootPath")) + savePath3;
+            InputStream is = fileStream.openStream();
+            State storageState = StorageManager.saveFileByInputStream(is, physicalPath, maxSize);
+            is.close();
+            if (storageState.isSuccess()) {
+                storageState.putInfo("url", PathFormat.format(savePath3));
+                storageState.putInfo("type", suffix);
+                storageState.putInfo("original", originFileName2 + suffix);
+            }
+            return storageState;
+        } catch (FileUploadException e) {
+            return new BaseState(false, 6);
+        } catch (IOException e2) {
+            return new BaseState(false, 4);
+        }
+    }
+
+    private static boolean validType(String type, String[] allowTypes) {
+        return Arrays.asList(allowTypes).contains(type);
+    }
+}

+ 121 - 0
src/main/java/com/baidu/ueditor/upload/StorageManager.java

@@ -0,0 +1,121 @@
+package com.baidu.ueditor.upload;
+
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.State;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.apache.commons.io.FileUtils;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/upload/StorageManager.class */
+public class StorageManager {
+    public static final int BUFFER_SIZE = 8192;
+
+    public static State saveBinaryFile(byte[] data, String path) {
+        File file = new File(path);
+        State state = valid(file);
+        if (!state.isSuccess()) {
+            return state;
+        }
+        try {
+            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
+            bos.write(data);
+            bos.flush();
+            bos.close();
+            State state2 = new BaseState(true, file.getAbsolutePath());
+            state2.putInfo("size", (long) data.length);
+            state2.putInfo("title", file.getName());
+            return state2;
+        } catch (IOException e) {
+            return new BaseState(false, 4);
+        }
+    }
+
+    public static State saveFileByInputStream(InputStream is, String path, long maxSize) {
+        File tmpFile = getTmpFile();
+        byte[] dataBuf = new byte[2048];
+        BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
+        try {
+            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmpFile), BUFFER_SIZE);
+            while (true) {
+                int count = bis.read(dataBuf);
+                if (count == -1) {
+                    break;
+                }
+                bos.write(dataBuf, 0, count);
+            }
+            bos.flush();
+            bos.close();
+            if (tmpFile.length() > maxSize) {
+                tmpFile.delete();
+                return new BaseState(false, 1);
+            }
+            State state = saveTmpFile(tmpFile, path);
+            if (!state.isSuccess()) {
+                tmpFile.delete();
+            }
+            return state;
+        } catch (IOException e) {
+            return new BaseState(false, 4);
+        }
+    }
+
+    public static State saveFileByInputStream(InputStream is, String path) {
+        File tmpFile = getTmpFile();
+        byte[] dataBuf = new byte[2048];
+        BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
+        try {
+            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmpFile), BUFFER_SIZE);
+            while (true) {
+                int count = bis.read(dataBuf);
+                if (count == -1) {
+                    break;
+                }
+                bos.write(dataBuf, 0, count);
+            }
+            bos.flush();
+            bos.close();
+            State state = saveTmpFile(tmpFile, path);
+            if (!state.isSuccess()) {
+                tmpFile.delete();
+            }
+            return state;
+        } catch (IOException e) {
+            return new BaseState(false, 4);
+        }
+    }
+
+    private static File getTmpFile() {
+        return new File(FileUtils.getTempDirectory(), ((Math.random() * 10000.0d) + "").replace(".", ""));
+    }
+
+    private static State saveTmpFile(File tmpFile, String path) {
+        File targetFile = new File(path);
+        if (targetFile.canWrite()) {
+            return new BaseState(false, 2);
+        }
+        try {
+            FileUtils.moveFile(tmpFile, targetFile);
+            State state = new BaseState(true);
+            state.putInfo("size", targetFile.length());
+            state.putInfo("title", targetFile.getName());
+            return state;
+        } catch (IOException e) {
+            return new BaseState(false, 4);
+        }
+    }
+
+    private static State valid(File file) {
+        File parentPath = file.getParentFile();
+        if (!parentPath.exists() && !parentPath.mkdirs()) {
+            return new BaseState(false, 3);
+        }
+        if (!parentPath.canWrite()) {
+            return new BaseState(false, 2);
+        }
+        return new BaseState(true);
+    }
+}

+ 29 - 0
src/main/java/com/baidu/ueditor/upload/Uploader.java

@@ -0,0 +1,29 @@
+package com.baidu.ueditor.upload;
+
+import com.baidu.ueditor.define.State;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+
+/* loaded from: ms-ueditor-1.0.6.jar:com/baidu/ueditor/upload/Uploader.class */
+public class Uploader {
+    private HttpServletRequest request;
+    private Map<String, Object> conf;
+
+    public Uploader(HttpServletRequest request, Map<String, Object> conf) {
+        this.request = null;
+        this.conf = null;
+        this.request = request;
+        this.conf = conf;
+    }
+
+    public final State doExec() {
+        State state;
+        String filedName = (String) this.conf.get("fieldName");
+        if ("true".equals(this.conf.get("isBase64"))) {
+            state = Base64Uploader.save(this.request.getParameter(filedName), this.conf);
+        } else {
+            state = BinaryUploader.save(this.request, this.conf);
+        }
+        return state;
+    }
+}

+ 44 - 0
src/main/java/com/freemarker/AuthenticatedTag.java

@@ -0,0 +1,44 @@
+package com.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.log.Logger;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+
+import java.io.IOException;
+import java.util.Map;
+
+
+/**
+ * JSP tag that renders the tag body only if the current user has executed a <b>successful</b> authentication attempt
+ * <em>during their current session</em>.
+ *
+ * <p>This is more restrictive than the {@link UserTag}, which only
+ * ensures the current user is known to the system, either via a current login or from Remember Me services,
+ * which only makes the assumption that the current user is who they say they are, and does not guarantee it like
+ * this tag does.
+ *
+ * <p>The logically opposite tag of this one is the {@link NotAuthenticatedTag}
+ *
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.AuthenticatedTag}</p>
+ *
+ * @since 0.2
+ */
+public class AuthenticatedTag extends SecureTag {
+    private static final Logger log = Logger.getLogger("AuthenticatedTag");
+
+    @Override
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (getSubject() != null && getSubject().isAuthenticated()) {
+            if (log.isDebugEnabled()) {
+                log.debug("Subject exists and is authenticated.  Tag body will be evaluated.");
+            }
+
+            renderBody(env, body);
+        } else {
+            if (log.isDebugEnabled()) {
+                log.debug("Subject does not exist or is not authenticated.  Tag body will not be evaluated.");
+            }
+        }
+    }
+}

+ 42 - 0
src/main/java/com/freemarker/GuestTag.java

@@ -0,0 +1,42 @@
+package com.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.log.Logger;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+
+import java.io.IOException;
+import java.util.Map;
+
+
+/**
+ * JSP tag that renders the tag body if the current user <em>is not</em> known to the system, either because they
+ * haven't logged in yet, or because they have no 'RememberMe' identity.
+ *
+ * <p>The logically opposite tag of this one is the {@link UserTag}.  Please read that class's JavaDoc as it explains
+ * more about the differences between Authenticated/Unauthenticated and User/Guest semantic differences.
+ *
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.GuestTag}</p>
+ *
+ * @since 0.9
+ */
+public class GuestTag extends SecureTag {
+    private static final Logger log = Logger.getLogger("AuthenticatedTag");
+
+    @Override
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (getSubject() == null || getSubject().getPrincipal() == null) {
+            if (log.isDebugEnabled()) {
+                log.debug("Subject does not exist or does not have a known identity (aka 'principal').  " +
+                        "Tag body will be evaluated.");
+            }
+
+            renderBody(env, body);
+        } else {
+            if (log.isDebugEnabled()) {
+                log.debug("Subject exists or has a known identity (aka 'principal').  " +
+                        "Tag body will not be evaluated.");
+            }
+        }
+    }
+}

+ 19 - 0
src/main/java/com/freemarker/HasAnyPermissionsTag.java

@@ -0,0 +1,19 @@
+package com.freemarker;
+
+/**
+ * 多个权限存在时,符合任意其中一个权限就表示有效,目前微信、mec会用到
+ */
+public class HasAnyPermissionsTag extends PermissionTag {
+    private static final String PERMISSION_NAMES_DELIMETER = ",";
+
+    protected boolean showTagBody(String ps) {
+        boolean hasAnyPermissions = false;
+        for(String p : ps.split(PERMISSION_NAMES_DELIMETER)){
+            if(isPermitted(p)){
+                hasAnyPermissions = true;
+                break;
+            }
+        }
+        return hasAnyPermissions;
+    }
+}

+ 51 - 0
src/main/java/com/freemarker/HasAnyRolesTag.java

@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.freemarker;
+
+import org.apache.shiro.subject.Subject;
+
+
+/**
+ * Displays body content if the current user has any of the roles specified.
+ *
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.HasAnyRolesTag}</p>
+ *
+ * @since 0.2
+ */
+public class HasAnyRolesTag extends RoleTag {
+    // Delimeter that separates role names in tag attribute
+    private static final String ROLE_NAMES_DELIMETER = ",";
+
+    protected boolean showTagBody(String roleNames) {
+        boolean hasAnyRole = false;
+        Subject subject = getSubject();
+
+        if (subject != null) {
+            // Iterate through roles and check to see if the user has one of the roles
+            for (String role : roleNames.split(ROLE_NAMES_DELIMETER)) {
+                if (subject.hasRole(role.trim())) {
+                    hasAnyRole = true;
+                    break;
+                }
+            }
+        }
+
+        return hasAnyRole;
+    }
+}

+ 12 - 0
src/main/java/com/freemarker/HasPermissionTag.java

@@ -0,0 +1,12 @@
+package com.freemarker;
+
+/**
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.HasPermissionTag}</p>
+ *
+ * @since 0.1
+ */
+public class HasPermissionTag extends PermissionTag {
+    protected boolean showTagBody(String p) {
+        return isPermitted(p);
+    }
+}

+ 10 - 0
src/main/java/com/freemarker/HasRoleTag.java

@@ -0,0 +1,10 @@
+package com.freemarker;
+
+/**
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.HasRoleTag}</p>
+ */
+public class HasRoleTag extends RoleTag {
+    protected boolean showTagBody(String roleName) {
+        return getSubject() != null && getSubject().hasRole(roleName);
+    }
+}

+ 10 - 0
src/main/java/com/freemarker/LacksPermissionTag.java

@@ -0,0 +1,10 @@
+package com.freemarker;
+
+/**
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.LacksPermissionTag}</p>
+ */
+public class LacksPermissionTag extends PermissionTag {
+    protected boolean showTagBody(String p) {
+        return !isPermitted(p);
+    }
+}

+ 11 - 0
src/main/java/com/freemarker/LacksRoleTag.java

@@ -0,0 +1,11 @@
+package com.freemarker;
+
+/**
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.LacksRoleTag}</p>
+ */
+public class LacksRoleTag extends RoleTag {
+    protected boolean showTagBody(String roleName) {
+        boolean hasRole = getSubject() != null && getSubject().hasRole(roleName);
+        return !hasRole;
+    }
+}

+ 32 - 0
src/main/java/com/freemarker/NotAuthenticatedTag.java

@@ -0,0 +1,32 @@
+package com.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.log.Logger;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+
+import java.io.IOException;
+import java.util.Map;
+
+
+/**
+ * Freemarker tag that renders the tag body only if the current user has <em>not</em> executed a successful authentication
+ * attempt <em>during their current session</em>.
+ *
+ * <p>The logically opposite tag of this one is the {@link org.apache.shiro.web.tags.AuthenticatedTag}.
+ *
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.NotAuthenticatedTag}</p>
+ */
+public class NotAuthenticatedTag extends SecureTag {
+    static final Logger log = Logger.getLogger("NotAuthenticatedTag");
+
+    @Override
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (getSubject() == null || !getSubject().isAuthenticated()) {
+            log.debug("Subject does not exist or is not authenticated.  Tag body will be evaluated.");
+            renderBody(env, body);
+        } else {
+            log.debug("Subject exists and is authenticated.  Tag body will not be evaluated.");
+        }
+    }
+}

+ 55 - 0
src/main/java/com/freemarker/PermissionTag.java

@@ -0,0 +1,55 @@
+package com.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModelException;
+import org.apache.shiro.util.StringUtils;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.PermissionTag}</p>
+ */
+public abstract class PermissionTag extends SecureTag {
+    String getName(Map params) {
+        return getParam(params, "name");
+    }
+    
+    @Override
+    protected void verifyParameters(Map params) throws TemplateModelException {
+        String permission = getName(params);
+
+        if (permission == null || permission.length() == 0) {
+            throw new TemplateModelException("The 'name' tag attribute must be set.");
+        }
+    }
+
+    @Override
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        String p = getName(params);
+
+        boolean show = showTagBody(p);
+        if (show) {
+            renderBody(env, body);
+        }
+    }
+
+    protected boolean isPermitted(String p) {
+        boolean isPermitted = false;
+        if(StringUtils.hasText(p) && getSubject() != null) {
+            String[] ps = p.split(",");
+            for(String _p : ps ) {
+                if(StringUtils.hasText(_p) && getSubject().isPermitted(_p)) {
+                    isPermitted = true;
+                    break;
+                }
+            }
+
+        }
+        return isPermitted;
+    }
+
+    protected abstract boolean showTagBody(String p);
+}

+ 119 - 0
src/main/java/com/freemarker/PrincipalTag.java

@@ -0,0 +1,119 @@
+package com.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.log.Logger;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModelException;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * <p>Tag used to print out the String value of a user's default principal,
+ * or a specific principal as specified by the tag's attributes.</p>
+ *
+ * <p> If no attributes are specified, the tag prints out the <tt>toString()</tt>
+ * value of the user's default principal.  If the <tt>type</tt> attribute
+ * is specified, the tag looks for a principal with the given type.  If the
+ * <tt>property</tt> attribute is specified, the tag prints the string value of
+ * the specified property of the principal.  If no principal is found or the user
+ * is not authenticated, the tag displays nothing unless a <tt>defaultValue</tt>
+ * is specified.</p>
+ *
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.PrincipalTag}</p>
+ *
+ * @since 0.2
+ */
+public class PrincipalTag extends SecureTag {
+    static final Logger log = Logger.getLogger("PrincipalTag");
+
+    /**
+     * The type of principal to be retrieved, or null if the default principal should be used.
+     */
+    String getType(Map params) {
+        return getParam(params, "type");
+    }
+
+    /**
+     * The property name to retrieve of the principal, or null if the <tt>toString()</tt> value should be used.
+     */
+    String getProperty(Map params) {
+        return getParam(params, "property");
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        String result = null;
+
+        if (getSubject() != null) {
+            // Get the principal to print out
+            Object principal;
+
+            if (getType(params) == null) {
+                principal = getSubject().getPrincipal();
+            } else {
+                principal = getPrincipalFromClassName(params);
+            }
+
+            // Get the string value of the principal
+            if (principal != null) {
+                String property = getProperty(params);
+
+                if (property == null) {
+                    result = principal.toString();
+                } else {
+                    result = getPrincipalProperty(principal, property);
+                }
+            }
+        }
+
+        // Print out the principal value if not null
+        if (result != null) {
+            try {
+                env.getOut().write(result);
+            } catch (IOException ex) {
+                throw new TemplateException("Error writing ["+result+"] to Freemarker.", ex, env);
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    Object getPrincipalFromClassName(Map params) {
+        String type = getType(params);
+
+        try {
+            Class cls = Class.forName(type);
+            
+            return getSubject().getPrincipals().oneByType(cls);
+        } catch (ClassNotFoundException ex) {
+            log.error("Unable to find class for name ["+type+"]", ex);
+        }
+
+        return null;
+    }
+
+    String getPrincipalProperty(Object principal, String property) throws TemplateModelException {
+        try {
+            BeanInfo beanInfo = Introspector.getBeanInfo(principal.getClass());
+
+            // Loop through the properties to get the string value of the specified property
+            for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) {
+                if (propertyDescriptor.getName().equals(property)) {
+                    Object value = propertyDescriptor.getReadMethod().invoke(principal, (Object[]) null);
+
+                    return String.valueOf(value);
+                }
+            }
+
+            // property not found, throw
+            throw new TemplateModelException("Property ["+property+"] not found in principal of type ["+principal.getClass().getName()+"]");
+        } catch (Exception ex) {
+            throw new TemplateModelException("Error reading property ["+property+"] from principal of type ["+principal.getClass().getName()+"]", ex);
+        }
+    }
+}

+ 27 - 0
src/main/java/com/freemarker/RoleTag.java

@@ -0,0 +1,27 @@
+package com.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.RoleTag}</p>
+ */
+public abstract class RoleTag extends SecureTag {
+    String getName(Map params) {
+        return getParam(params, "name");
+    }
+
+    @Override
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        boolean show = showTagBody(getName(params));
+        if (show) {
+            renderBody(env, body);
+        }
+    }
+
+    protected abstract boolean showTagBody(String roleName);
+}

+ 44 - 0
src/main/java/com/freemarker/SecureTag.java

@@ -0,0 +1,44 @@
+package com.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.template.*;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.SecureTag}</p>
+ */
+public abstract class SecureTag implements TemplateDirectiveModel {
+    public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
+        verifyParameters(params);
+        render(env, params, body);
+    }
+
+    public abstract void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException;
+
+    protected String getParam(Map params, String name) {
+        Object value = params.get(name);
+
+        if (value instanceof SimpleScalar) {
+            return ((SimpleScalar)value).getAsString();
+        }
+        
+        return null;
+    }
+
+    protected Subject getSubject() {
+        return SecurityUtils.getSubject();
+    }
+
+    protected void verifyParameters(Map params) throws TemplateModelException {
+    }
+
+    protected void renderBody(Environment env, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (body != null) {
+            body.render(env.getOut());
+        }
+    }
+}

+ 24 - 0
src/main/java/com/freemarker/ShiroTags.java

@@ -0,0 +1,24 @@
+package com.freemarker;
+
+import freemarker.template.SimpleHash;
+
+/**
+ * Shortcut for injecting the tags into Freemarker
+ *
+ * <p>Usage: cfg.setSharedVeriable("shiro", new ShiroTags());</p>
+ */
+public class ShiroTags extends SimpleHash {
+    public ShiroTags() {
+        put("authenticated", new AuthenticatedTag());
+        put("guest", new GuestTag());
+        put("hasAnyRoles", new HasAnyRolesTag());
+        put("hasPermission", new HasPermissionTag());
+        put("hasRole", new HasRoleTag());
+        put("lacksPermission", new LacksPermissionTag());
+        put("lacksRole", new LacksRoleTag());
+        put("notAuthenticated", new NotAuthenticatedTag());
+        put("principal", new PrincipalTag());
+        put("user", new UserTag());
+        put("hasAnyPermissions", new HasAnyPermissionsTag());
+    }
+}

+ 37 - 0
src/main/java/com/freemarker/UserTag.java

@@ -0,0 +1,37 @@
+package com.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.log.Logger;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Freemarker tag that renders the tag body if the current user known to the system, either from a successful login attempt
+ * (not necessarily during the current session) or from 'RememberMe' services.
+ *
+ * <p><b>Note:</b> This is <em>less</em> restrictive than the <code>AuthenticatedTag</code> since it only assumes
+ * the user is who they say they are, either via a current session login <em>or</em> via Remember Me services, which
+ * makes no guarantee the user is who they say they are.  The <code>AuthenticatedTag</code> however
+ * guarantees that the current user has logged in <em>during their current session</em>, proving they really are
+ * who they say they are.
+ *
+ * <p>The logically opposite tag of this one is the {@link org.apache.shiro.web.tags.GuestTag}.
+ *
+ * <p>Equivalent to {@link org.apache.shiro.web.tags.UserTag}</p>
+ */
+public class UserTag extends SecureTag {
+    static final Logger log = Logger.getLogger("UserTag");
+
+    @Override
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (getSubject() != null && getSubject().getPrincipal() != null) {
+            log.debug("Subject has known identity (aka 'principal'). Tag body will be evaluated.");
+            renderBody(env, body);
+        } else {
+            log.debug("Subject does not exist or have a known identity (aka 'principal'). Tag body will not be evaluated.");
+        }
+    }
+}

+ 25 - 0
src/main/java/com/jagregory/shiro/freemarker/AuthenticatedTag.java

@@ -0,0 +1,25 @@
+package com.jagregory.shiro.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.log.Logger;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+import java.io.IOException;
+import java.util.Map;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/AuthenticatedTag.class */
+public class AuthenticatedTag extends SecureTag {
+    private static final Logger log = Logger.getLogger("AuthenticatedTag");
+
+    @Override // com.jagregory.shiro.freemarker.SecureTag
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (getSubject() != null && getSubject().isAuthenticated()) {
+            if (log.isDebugEnabled()) {
+                log.debug("Subject exists and is authenticated.  Tag body will be evaluated.");
+            }
+            renderBody(env, body);
+        } else if (log.isDebugEnabled()) {
+            log.debug("Subject does not exist or is not authenticated.  Tag body will not be evaluated.");
+        }
+    }
+}

+ 25 - 0
src/main/java/com/jagregory/shiro/freemarker/GuestTag.java

@@ -0,0 +1,25 @@
+package com.jagregory.shiro.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.log.Logger;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+import java.io.IOException;
+import java.util.Map;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/GuestTag.class */
+public class GuestTag extends SecureTag {
+    private static final Logger log = Logger.getLogger("AuthenticatedTag");
+
+    @Override // com.jagregory.shiro.freemarker.SecureTag
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (getSubject() == null || getSubject().getPrincipal() == null) {
+            if (log.isDebugEnabled()) {
+                log.debug("Subject does not exist or does not have a known identity (aka 'principal').  Tag body will be evaluated.");
+            }
+            renderBody(env, body);
+        } else if (log.isDebugEnabled()) {
+            log.debug("Subject exists or has a known identity (aka 'principal').  Tag body will not be evaluated.");
+        }
+    }
+}

+ 25 - 0
src/main/java/com/jagregory/shiro/freemarker/HasAnyPermissionsTag.java

@@ -0,0 +1,25 @@
+package com.jagregory.shiro.freemarker;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/HasAnyPermissionsTag.class */
+public class HasAnyPermissionsTag extends PermissionTag {
+    private static final String PERMISSION_NAMES_DELIMETER = ",";
+
+    @Override // com.jagregory.shiro.freemarker.PermissionTag
+    protected boolean showTagBody(String ps) {
+        boolean hasAnyPermissions = false;
+        String[] split = ps.split(PERMISSION_NAMES_DELIMETER);
+        int length = split.length;
+        int i = 0;
+        while (true) {
+            if (i >= length) {
+                break;
+            } else if (isPermitted(split[i])) {
+                hasAnyPermissions = true;
+                break;
+            } else {
+                i++;
+            }
+        }
+        return hasAnyPermissions;
+    }
+}

+ 30 - 0
src/main/java/com/jagregory/shiro/freemarker/HasAnyRolesTag.java

@@ -0,0 +1,30 @@
+package com.jagregory.shiro.freemarker;
+
+import org.apache.shiro.subject.Subject;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/HasAnyRolesTag.class */
+public class HasAnyRolesTag extends RoleTag {
+    private static final String ROLE_NAMES_DELIMETER = ",";
+
+    @Override // com.jagregory.shiro.freemarker.RoleTag
+    protected boolean showTagBody(String roleNames) {
+        boolean hasAnyRole = false;
+        Subject subject = getSubject();
+        if (subject != null) {
+            String[] split = roleNames.split(ROLE_NAMES_DELIMETER);
+            int length = split.length;
+            int i = 0;
+            while (true) {
+                if (i >= length) {
+                    break;
+                } else if (subject.hasRole(split[i].trim())) {
+                    hasAnyRole = true;
+                    break;
+                } else {
+                    i++;
+                }
+            }
+        }
+        return hasAnyRole;
+    }
+}

+ 9 - 0
src/main/java/com/jagregory/shiro/freemarker/HasPermissionTag.java

@@ -0,0 +1,9 @@
+package com.jagregory.shiro.freemarker;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/HasPermissionTag.class */
+public class HasPermissionTag extends PermissionTag {
+    @Override // com.jagregory.shiro.freemarker.PermissionTag
+    protected boolean showTagBody(String p) {
+        return isPermitted(p);
+    }
+}

+ 9 - 0
src/main/java/com/jagregory/shiro/freemarker/HasRoleTag.java

@@ -0,0 +1,9 @@
+package com.jagregory.shiro.freemarker;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/HasRoleTag.class */
+public class HasRoleTag extends RoleTag {
+    @Override // com.jagregory.shiro.freemarker.RoleTag
+    protected boolean showTagBody(String roleName) {
+        return getSubject() != null && getSubject().hasRole(roleName);
+    }
+}

+ 9 - 0
src/main/java/com/jagregory/shiro/freemarker/LacksPermissionTag.java

@@ -0,0 +1,9 @@
+package com.jagregory.shiro.freemarker;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/LacksPermissionTag.class */
+public class LacksPermissionTag extends PermissionTag {
+    @Override // com.jagregory.shiro.freemarker.PermissionTag
+    protected boolean showTagBody(String p) {
+        return !isPermitted(p);
+    }
+}

+ 9 - 0
src/main/java/com/jagregory/shiro/freemarker/LacksRoleTag.java

@@ -0,0 +1,9 @@
+package com.jagregory.shiro.freemarker;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/LacksRoleTag.class */
+public class LacksRoleTag extends RoleTag {
+    @Override // com.jagregory.shiro.freemarker.RoleTag
+    protected boolean showTagBody(String roleName) {
+        return !(getSubject() != null && getSubject().hasRole(roleName));
+    }
+}

+ 23 - 0
src/main/java/com/jagregory/shiro/freemarker/NotAuthenticatedTag.java

@@ -0,0 +1,23 @@
+package com.jagregory.shiro.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.log.Logger;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+import java.io.IOException;
+import java.util.Map;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/NotAuthenticatedTag.class */
+public class NotAuthenticatedTag extends SecureTag {
+    static final Logger log = Logger.getLogger("NotAuthenticatedTag");
+
+    @Override // com.jagregory.shiro.freemarker.SecureTag
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (getSubject() == null || !getSubject().isAuthenticated()) {
+            log.debug("Subject does not exist or is not authenticated.  Tag body will be evaluated.");
+            renderBody(env, body);
+            return;
+        }
+        log.debug("Subject exists and is authenticated.  Tag body will not be evaluated.");
+    }
+}

+ 54 - 0
src/main/java/com/jagregory/shiro/freemarker/PermissionTag.java

@@ -0,0 +1,54 @@
+package com.jagregory.shiro.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModelException;
+import java.io.IOException;
+import java.util.Map;
+import org.apache.shiro.util.StringUtils;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/PermissionTag.class */
+public abstract class PermissionTag extends SecureTag {
+    protected abstract boolean showTagBody(String str);
+
+    String getName(Map params) {
+        return getParam(params, "name");
+    }
+
+    @Override // com.jagregory.shiro.freemarker.SecureTag
+    protected void verifyParameters(Map params) throws TemplateModelException {
+        String permission = getName(params);
+        if (permission == null || permission.length() == 0) {
+            throw new TemplateModelException("The 'name' tag attribute must be set.");
+        }
+    }
+
+    @Override // com.jagregory.shiro.freemarker.SecureTag
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (showTagBody(getName(params))) {
+            renderBody(env, body);
+        }
+    }
+
+    protected boolean isPermitted(String p) {
+        boolean isPermitted = false;
+        if (StringUtils.hasText(p) && getSubject() != null) {
+            String[] ps = p.split(",");
+            int length = ps.length;
+            int i = 0;
+            while (true) {
+                if (i >= length) {
+                    break;
+                }
+                String _p = ps[i];
+                if (StringUtils.hasText(_p) && getSubject().isPermitted(_p)) {
+                    isPermitted = true;
+                    break;
+                }
+                i++;
+            }
+        }
+        return isPermitted;
+    }
+}

+ 72 - 0
src/main/java/com/jagregory/shiro/freemarker/PrincipalTag.java

@@ -0,0 +1,72 @@
+package com.jagregory.shiro.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.log.Logger;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModelException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.util.Map;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/PrincipalTag.class */
+public class PrincipalTag extends SecureTag {
+    static final Logger log = Logger.getLogger("PrincipalTag");
+
+    String getType(Map params) {
+        return getParam(params, "type");
+    }
+
+    String getProperty(Map params) {
+        return getParam(params, "property");
+    }
+
+    @Override // com.jagregory.shiro.freemarker.SecureTag
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        Object principal;
+        String result = null;
+        if (getSubject() != null) {
+            if (getType(params) == null) {
+                principal = getSubject().getPrincipal();
+            } else {
+                principal = getPrincipalFromClassName(params);
+            }
+            if (principal != null) {
+                String property = getProperty(params);
+                result = property == null ? principal.toString() : getPrincipalProperty(principal, property);
+            }
+        }
+        if (result != null) {
+            try {
+                env.getOut().write(result);
+            } catch (IOException ex) {
+                throw new TemplateException("Error writing [" + result + "] to Freemarker.", ex, env);
+            }
+        }
+    }
+
+    Object getPrincipalFromClassName(Map params) {
+        String type = getType(params);
+        try {
+            return getSubject().getPrincipals().oneByType(Class.forName(type));
+        } catch (ClassNotFoundException ex) {
+            log.error("Unable to find class for name [" + type + "]", ex);
+            return null;
+        }
+    }
+
+    String getPrincipalProperty(Object principal, String property) throws TemplateModelException {
+        try {
+            PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(principal.getClass()).getPropertyDescriptors();
+            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
+                if (propertyDescriptor.getName().equals(property)) {
+                    return String.valueOf(propertyDescriptor.getReadMethod().invoke(principal, null));
+                }
+            }
+            throw new TemplateModelException("Property [" + property + "] not found in principal of type [" + principal.getClass().getName() + "]");
+        } catch (Exception ex) {
+            throw new TemplateModelException("Error reading property [" + property + "] from principal of type [" + principal.getClass().getName() + "]", ex);
+        }
+    }
+}

+ 23 - 0
src/main/java/com/jagregory/shiro/freemarker/RoleTag.java

@@ -0,0 +1,23 @@
+package com.jagregory.shiro.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+import java.io.IOException;
+import java.util.Map;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/RoleTag.class */
+public abstract class RoleTag extends SecureTag {
+    protected abstract boolean showTagBody(String str);
+
+    String getName(Map params) {
+        return getParam(params, "name");
+    }
+
+    @Override // com.jagregory.shiro.freemarker.SecureTag
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (showTagBody(getName(params))) {
+            renderBody(env, body);
+        }
+    }
+}

+ 44 - 0
src/main/java/com/jagregory/shiro/freemarker/SecureTag.java

@@ -0,0 +1,44 @@
+package com.jagregory.shiro.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.template.SimpleScalar;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateDirectiveModel;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import java.io.IOException;
+import java.util.Map;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/SecureTag.class */
+public abstract class SecureTag implements TemplateDirectiveModel {
+    public abstract void render(Environment environment, Map map, TemplateDirectiveBody templateDirectiveBody) throws IOException, TemplateException;
+
+    public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
+        verifyParameters(params);
+        render(env, params, body);
+    }
+
+    protected String getParam(Map params, String name) {
+        Object value = params.get(name);
+        if (value instanceof SimpleScalar) {
+            return ((SimpleScalar) value).getAsString();
+        }
+        return null;
+    }
+
+    protected Subject getSubject() {
+        return SecurityUtils.getSubject();
+    }
+
+    protected void verifyParameters(Map params) throws TemplateModelException {
+    }
+
+    protected void renderBody(Environment env, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (body != null) {
+            body.render(env.getOut());
+        }
+    }
+}

+ 20 - 0
src/main/java/com/jagregory/shiro/freemarker/ShiroTags.java

@@ -0,0 +1,20 @@
+package com.jagregory.shiro.freemarker;
+
+import freemarker.template.SimpleHash;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/ShiroTags.class */
+public class ShiroTags extends SimpleHash {
+    public ShiroTags() {
+        put("authenticated", new AuthenticatedTag());
+        put("guest", new GuestTag());
+        put("hasAnyRoles", new HasAnyRolesTag());
+        put("hasPermission", new HasPermissionTag());
+        put("hasRole", new HasRoleTag());
+        put("lacksPermission", new LacksPermissionTag());
+        put("lacksRole", new LacksRoleTag());
+        put("notAuthenticated", new NotAuthenticatedTag());
+        put("principal", new PrincipalTag());
+        put("user", new UserTag());
+        put("hasAnyPermissions", new HasAnyPermissionsTag());
+    }
+}

+ 23 - 0
src/main/java/com/jagregory/shiro/freemarker/UserTag.java

@@ -0,0 +1,23 @@
+package com.jagregory.shiro.freemarker;
+
+import freemarker.core.Environment;
+import freemarker.log.Logger;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateException;
+import java.io.IOException;
+import java.util.Map;
+
+/* loaded from: shiro-freemarker-tags-1.0.3.jar:com/jagregory/shiro/freemarker/UserTag.class */
+public class UserTag extends SecureTag {
+    static final Logger log = Logger.getLogger("UserTag");
+
+    @Override // com.jagregory.shiro.freemarker.SecureTag
+    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
+        if (getSubject() == null || getSubject().getPrincipal() == null) {
+            log.debug("Subject does not exist or have a known identity (aka 'principal'). Tag body will not be evaluated.");
+            return;
+        }
+        log.debug("Subject has known identity (aka 'principal'). Tag body will be evaluated.");
+        renderBody(env, body);
+    }
+}

+ 89 - 0
src/main/java/com/mingsoft/ueditor/MsUeditorActionEnter.java

@@ -0,0 +1,89 @@
+package com.mingsoft.ueditor;
+
+import com.baidu.ueditor.ActionEnter;
+import com.baidu.ueditor.ConfigManager;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.Iterator;
+import javax.servlet.http.HttpServletRequest;
+import org.json.JSONObject;
+
+public class MsUeditorActionEnter extends ActionEnter {
+    public MsUeditorActionEnter(HttpServletRequest request, String rootPath, String jsonConfig) {
+        super(request, rootPath);
+        if (jsonConfig != null && !jsonConfig.trim().equals("") && jsonConfig.length() >= 0) {
+            ConfigManager config = this.getConfigManager();
+            JSONObject _jsonConfig = new JSONObject(jsonConfig);
+            _jsonConfig.remove("fileManagerAllowFiles");
+            _jsonConfig.remove("imageManagerAllowFiles");
+            _jsonConfig.remove("catcherAllowFiles");
+            _jsonConfig.remove("imageAllowFiles");
+            _jsonConfig.remove("fileAllowFiles");
+            _jsonConfig.remove("videoAllowFiles");
+            _jsonConfig.remove("imageManagerListPath");
+            _jsonConfig.remove("fileManagerListPath");
+            JSONObject jsonObject = config.getAllConfig();
+            Iterator iterator = _jsonConfig.keys();
+
+            while(iterator.hasNext()) {
+                String key = (String)iterator.next();
+                jsonObject.put(key, _jsonConfig.get(key));
+            }
+
+        }
+    }
+
+    public MsUeditorActionEnter(HttpServletRequest request, String rootPath, String jsonConfig, String configPath) {
+        super(request, rootPath);
+        if (jsonConfig != null && !jsonConfig.trim().equals("") && jsonConfig.length() >= 0) {
+            this.setConfigManager(ConfigManager.getInstance(configPath, request.getContextPath(), request.getRequestURI()));
+            ConfigManager config = this.getConfigManager();
+            setValue(config, "rootPath", rootPath);
+            JSONObject _jsonConfig = new JSONObject(jsonConfig);
+            _jsonConfig.remove("fileManagerAllowFiles");
+            _jsonConfig.remove("imageManagerAllowFiles");
+            _jsonConfig.remove("catcherAllowFiles");
+            _jsonConfig.remove("imageAllowFiles");
+            _jsonConfig.remove("fileAllowFiles");
+            _jsonConfig.remove("videoAllowFiles");
+            _jsonConfig.remove("imageManagerListPath");
+            _jsonConfig.remove("fileManagerListPath");
+            JSONObject jsonObject = config.getAllConfig();
+            Iterator iterator = _jsonConfig.keys();
+
+            while(iterator.hasNext()) {
+                String key = (String)iterator.next();
+                jsonObject.put(key, _jsonConfig.get(key));
+            }
+
+        }
+    }
+
+    public static void setValue(Object target, String fieldName, Object value) {
+        Class<?> clazz = target.getClass();
+        String[] fs = fieldName.split("\\.");
+
+        try {
+            for(int i = 0; i < fs.length - 1; ++i) {
+                Field f = clazz.getDeclaredField(fs[i]);
+                f.setAccessible(true);
+                Object val = f.get(target);
+                if (val == null) {
+                    Constructor<?> c = f.getType().getDeclaredConstructor();
+                    c.setAccessible(true);
+                    val = c.newInstance();
+                    f.set(target, val);
+                }
+
+                target = val;
+                clazz = val.getClass();
+            }
+
+            Field f = clazz.getDeclaredField(fs[fs.length - 1]);
+            f.setAccessible(true);
+            f.set(target, value);
+        } catch (Exception var9) {
+            throw new RuntimeException(var9);
+        }
+    }
+}

+ 54 - 0
src/main/java/net/mingsoft/base/MSVersion.java

@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+package net.mingsoft.base;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.CodeSource;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+
+public class MSVersion {
+
+    public static String getVersion() {
+        return determineSpringBootVersion();
+    }
+
+    private static String determineSpringBootVersion() {
+        final Package pkg = MSVersion.class.getPackage();
+        if (pkg != null && pkg.getImplementationVersion() != null) {
+            return pkg.getImplementationVersion();
+        }
+        CodeSource codeSource = MSVersion.class.getProtectionDomain().getCodeSource();
+        if (codeSource == null) {
+            return null;
+        }
+        URL codeSourceLocation = codeSource.getLocation();
+        try {
+            URLConnection connection = codeSourceLocation.openConnection();
+            if (connection instanceof JarURLConnection) {
+                return getImplementationVersion(((JarURLConnection) connection).getJarFile());
+            }
+            try (JarFile jarFile = new JarFile(new File(codeSourceLocation.toURI()))) {
+                return getImplementationVersion(jarFile);
+            }
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    private static String getImplementationVersion(JarFile jarFile) throws IOException {
+        return jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+    }
+}

+ 332 - 0
src/main/java/net/mingsoft/base/action/BaseAction.java

@@ -0,0 +1,332 @@
+package net.mingsoft.base.action;
+
+import net.mingsoft.base.util.BundleUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+/**
+ * @ClassName:  BaseAction
+ * @Description:TODO(基础应用层,其他业务层必须基层该类)
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:28:27
+ *
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+@SuppressWarnings({ "rawtypes", "unchecked" })
+public abstract class BaseAction {
+
+	/*
+	 * log4j日志记录
+	 */
+	protected final Logger LOG = LoggerFactory.getLogger(this.getClass());
+
+	/** Wap网关Via头信息中特有的描述信息 */
+	private static String mobileGateWayHeaders[] = new String[] { "ZXWAP", // 中兴提供的wap网关的via信息,例如:Via=ZXWAP
+			// GateWayZTE
+			// Technologies,
+			"chinamobile.com", // 中国移动的诺基亚wap网关,例如:Via=WTP/1.1
+			// GDSZ-PB-GW003-WAP07.gd.chinamobile.com (Nokia
+			// WAP Gateway 4.1 CD1/ECD13_D/4.1.04)
+			"monternet.com", // 移动梦网的网关,例如:Via=WTP/1.1
+			// BJBJ-PS-WAP1-GW08.bj1.monternet.com. (Nokia
+			// WAP
+			// Gateway 4.1 CD1/ECD13_E/4.1.05)
+			"infoX", // 华为提供的wap网关,例如:Via=HTTP/1.1 GDGZ-PS-GW011-WAP2
+			// (infoX-WISG
+			// Huawei Technologies),或Via=infoX WAP Gateway V300R001
+			// Huawei Technologies
+			"XMS 724Solutions HTG", // 国外电信运营商的wap网关,不知道是哪一家
+			"wap.lizongbo.com", // 自己测试时模拟的头信息
+			"Bytemobile",// 貌似是一个给移动互联网提供解决方案提高网络运行效率的,例如:Via=1.1 Bytemobile OSN
+			// WebProxy/5.1
+	};
+	/** 电脑上的IE或Firefox浏览器等的User-Agent关键词 */
+	private static String[] pcHeaders = new String[] { "Windows 98", "Windows ME", "Windows 2000", "Windows XP",
+			"Windows NT", "Ubuntu" };
+	/** 手机浏览器的User-Agent里的关键词 */
+	private static String[] mobileUserAgents = new String[] { "Nokia", // 诺基亚,有山寨机也写这个的,总还算是手机,Mozilla/5.0
+			// (Nokia5800
+			// XpressMusic)UC
+			// AppleWebkit(like
+			// Gecko)
+			// Safari/530
+			"SAMSUNG", // 三星手机
+			// SAMSUNG-GT-B7722/1.0+SHP/VPP/R5+Dolfin/1.5+Nextreaming+SMM-MMS/1.2.0+profile/MIDP-2.1+configuration/CLDC-1.1
+			"MIDP-2", // j2me2.0,Mozilla/5.0 (SymbianOS/9.3; U; Series60/3.2
+			// NokiaE75-1 /110.48.125 Profile/MIDP-2.1
+			// Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML like
+			// Gecko) Safari/413
+			"CLDC1.1", // M600/MIDP2.0/CLDC1.1/Screen-240X320
+			"SymbianOS", // 塞班系统的,
+			"MAUI", // MTK山寨机默认ua
+			"UNTRUSTED/1.0", // 疑似山寨机的ua,基本可以确定还是手机
+			"Windows CE", // Windows CE,Mozilla/4.0 (compatible; MSIE 6.0;
+			// Windows CE; IEMobile 7.11)
+			"iPhone", // iPhone是否也转wap?不管它,先区分出来再说。Mozilla/5.0 (iPhone; U; CPU
+			// iPhone OS 4_1 like Mac OS X; zh-cn) AppleWebKit/532.9
+			// (KHTML like Gecko) Mobile/8B117
+			"iPad", // iPad的ua,Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X;
+			// zh-cn) AppleWebKit/531.21.10 (KHTML like Gecko)
+			// Version/4.0.4 Mobile/7B367 Safari/531.21.10
+			"Android", // Android是否也转wap?Mozilla/5.0 (Linux; U; Android
+			// 2.1-update1; zh-cn; XT800 Build/TITA_M2_16.22.7)
+			// AppleWebKit/530.17 (KHTML like Gecko) Version/4.0
+			// Mobile Safari/530.17
+			"BlackBerry", // BlackBerry8310/2.7.0.106-4.5.0.182
+			"UCWEB", // ucweb是否只给wap页面? Nokia5800
+			// XpressMusic/UCWEB7.5.0.66/50/999
+			"ucweb", // 小写的ucweb貌似是uc的代理服务器Mozilla/6.0 (compatible; MSIE 6.0;)
+			// Opera ucweb-squid
+			"BREW", // 很奇怪的ua,例如:REW-Applet/0x20068888 (BREW/3.1.5.20; DeviceId:
+			// 40105; Lang: zhcn) ucweb-squid
+			"J2ME", // 很奇怪的ua,只有J2ME四个字母
+			"YULONG", // 宇龙手机,YULONG-CoolpadN68/10.14 IPANEL/2.0 CTC/1.0
+			"YuLong", // 还是宇龙
+			"COOLPAD", // 宇龙酷派YL-COOLPADS100/08.10.S100 POLARIS/2.9 CTC/1.0
+			"TIANYU", // 天语手机TIANYU-KTOUCH/V209/MIDP2.0/CLDC1.1/Screen-240X320
+			"TY-", // 天语,TY-F6229/701116_6215_V0230 JUPITOR/2.2 CTC/1.0
+			"K-Touch", // 还是天语K-Touch_N2200_CMCC/TBG110022_1223_V0801 MTK/6223
+			// Release/30.07.2008 Browser/WAP2.0
+			"Haier", // 海尔手机,Haier-HG-M217_CMCC/3.0 Release/12.1.2007
+			// Browser/WAP2.0
+			"DOPOD", // 多普达手机
+			"Lenovo", // 联想手机,Lenovo-P650WG/S100 LMP/LML Release/2010.02.22
+			// Profile/MIDP2.0 Configuration/CLDC1.1
+			"LENOVO", // 联想手机,比如:LENOVO-P780/176A
+			"HUAQIN", // 华勤手机
+			"AIGO-", // 爱国者居然也出过手机,AIGO-800C/2.04 TMSS-BROWSER/1.0.0 CTC/1.0
+			"CTC/1.0", // 含义不明
+			"CTC/2.0", // 含义不明
+			"CMCC", // 移动定制手机,K-Touch_N2200_CMCC/TBG110022_1223_V0801 MTK/6223
+			// Release/30.07.2008 Browser/WAP2.0
+			"DAXIAN", // 大显手机DAXIAN X180 UP.Browser/6.2.3.2(GUI) MMP/2.0
+			"MOT-", // 摩托罗拉,MOT-MOTOROKRE6/1.0 LinuxOS/2.4.20 Release/8.4.2006
+			// Browser/Opera8.00 Profile/MIDP2.0 Configuration/CLDC1.1
+			// Software/R533_G_11.10.54R
+			"SonyEricsson", // 索爱手机,SonyEricssonP990i/R100 Mozilla/4.0
+			// (compatible; MSIE 6.0; Symbian OS; 405) Opera
+			// 8.65 [zh-CN]
+			"GIONEE", // 金立手机
+			"HTC", // HTC手机
+			"ZTE", // 中兴手机,ZTE-A211/P109A2V1.0.0/WAP2.0 Profile
+			"HUAWEI", // 华为手机,
+			"webOS", // palm手机,Mozilla/5.0 (webOS/1.4.5; U; zh-CN)
+			// AppleWebKit/532.2 (KHTML like Gecko) Version/1.0
+			// Safari/532.2 Pre/1.0
+			"GoBrowser", // 3g GoBrowser.User-Agent=Nokia5230/GoBrowser/2.0.290
+			// Safari
+			"IEMobile", // Windows CE手机自带浏览器,
+			"WAP2.0"// 支持wap 2.0的
+	};
+
+	/**
+	 * 获取本地化文件
+	 * @param key
+	 * @param resources 资源文件所在位置
+	 * @return
+	 * 推荐使用 BasicUtil.getString
+	 */
+	@Deprecated
+	protected String getLocaleString(String key,String resources){
+		return BundleUtil.getLocaleString(key,resources);
+	}
+
+
+	/**
+	 * 获取项目路径
+	 * @see BasicUtil.getUrl
+	 * @param request
+	 *            HttpServletRequest对象
+	 * @return 返回项目路径,例如:http://www.ip.com/projectName 后面没有反斜杠,后面接地址或参数必须加/
+	 */
+	@Deprecated
+	protected String getUrl(HttpServletRequest request) {
+		String path = request.getContextPath();
+		String basePath = request.getScheme() + "://" + request.getServerName();
+		if (request.getServerPort() == 80) {
+			basePath += path;
+		} else {
+			basePath += ":" + request.getServerPort() + path;
+		}
+		return basePath;
+	}
+
+	/**
+	 * 获取请求域名,域名不包括http请求协议头
+	 * @see BasicUtil.getDomain
+	 * @param request
+	 *            HttpServletRequest对象
+	 * @return 返回域名地址
+	 */
+	@Deprecated
+	protected String getDomain(HttpServletRequest request) {
+		String path = request.getContextPath();
+		String domain = request.getServerName();
+		if (request.getServerPort() == 80) {
+			domain += path;
+		} else {
+			domain += ":" + request.getServerPort() + path;
+		}
+		return domain;
+	}
+
+	/**
+	 * 读取服务器主机信息
+	 *
+	 * @param request
+	 *            HttpServletRequest对象
+	 * @return 返回主机信息
+	 */
+	protected String getHost(HttpServletRequest request) {
+		String basePath = request.getServerName();
+		if (request.getServerPort() != 80) {
+			basePath += ":" + request.getServerPort();
+		}
+		return basePath;
+	}
+
+	/**
+	 * 读取服务器主机ip信息
+	 *
+	 * @return 返回主机IP,异常将会获取不到ip
+	 */
+	protected String getHostIp() {
+		InetAddress addr;
+		try {
+			addr = InetAddress.getLocalHost();
+			return addr.getHostAddress();// 获得本机IP
+		} catch (UnknownHostException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return "";
+	}
+
+	/**
+	 * 读取国际化资源文件
+	 *
+	 * @param key
+	 *            键值
+	 * @return 返回获取到的字符串
+	 * 推荐使用 BundleUtil.getString
+	 */
+	@Deprecated
+	protected String getResString(String key) {
+		return BundleUtil.getResString(key);
+	}
+
+	/**
+	 * 读取国际化资源文件,优先模块对应的资源文件,如果模块资源文件找不到就会优先基础层
+	 *
+	 * @param key
+	 *            键值
+	 * @param rb
+	 *            模块对应资源文件
+	 * @return 返回获取到的字符串
+	 * 推荐使用 BundleUtil.getString
+	 */
+	@Deprecated
+	protected String getResString(String key, ResourceBundle rb) {
+		return BundleUtil.getResString(key,rb);
+	}
+
+	/**
+	 * 读取国际化资源文件
+	 *
+	 * @param key
+	 *            键值
+	 * @param fullStrs
+	 *            需填充的值
+	 * @return 返回获取到的字符串
+	 */
+	protected String getResString(String key, String... fullStrs) {
+		return BundleUtil.getResString(key,fullStrs);
+	}
+
+	/**
+	 * 读取国际化资源文件,优先模块对应的资源文件,如果模块资源文件找不到就会优先基础层
+	 *
+	 * @param key
+	 *            键值
+	 * @param rb
+	 *            模块对应资源文件
+	 * @return 返回获取到的字符串
+	 * 推荐使用 BundleUtil.getString
+	 */
+	@Deprecated
+	protected String getResString(String key, ResourceBundle rb, String... fullStrs) {
+		return BundleUtil.getResString(key,rb,fullStrs);
+	}
+
+	/**
+	 * 根据当前请求的特征,判断该请求是否来自手机终端,主要检测特殊的头信息,以及user-Agent这个header
+	 *
+	 * @param request
+	 *            HttpServletRequest对象,http请求
+	 * @return 如果命中手机特征规则,则返回对应的特征字符串
+	 */
+	public boolean isMobileDevice(HttpServletRequest request) {
+		boolean b = false;
+		boolean pcFlag = false;
+		boolean mobileFlag = false;
+		String via = request.getHeader("Via");
+		String userAgent = request.getHeader("user-agent");
+		for (int i = 0; via != null && !via.trim().equals("") && i < mobileGateWayHeaders.length; i++) {
+			if (via.contains(mobileGateWayHeaders[i])) {
+				mobileFlag = true;
+				break;
+			}
+		}
+		for (int i = 0; !mobileFlag && userAgent != null && !userAgent.trim().equals("")
+				&& i < mobileUserAgents.length; i++) {
+			if (userAgent.contains(mobileUserAgents[i])) {
+				mobileFlag = true;
+				break;
+			}
+		}
+		for (int i = 0; userAgent != null && !userAgent.trim().equals("") && i < pcHeaders.length; i++) {
+			if (userAgent.contains(pcHeaders[i])) {
+				pcFlag = true;
+				break;
+			}
+		}
+		if (mobileFlag == true && pcFlag == false) {
+			b = true;
+		}
+		return b;// false pc true shouji
+
+	}
+
+	/**
+	 * 根据属性配置文件返回map
+	 *
+	 * @return 返回Map
+	 */
+	protected Map<String, String> getMapByProperties(String filePath) {
+		if (StringUtils.isBlank(filePath)) {
+			return null;
+		}
+		ResourceBundle rb = ResourceBundle.getBundle(filePath);
+		return this.getMapByProperties(rb);
+	}
+
+	protected Map<String, String> getMapByProperties(ResourceBundle rb) {
+		Map<String, String> map = new HashMap<String, String>();
+		Enumeration<String> en = rb.getKeys();
+		while (en.hasMoreElements()) {
+			String key = en.nextElement();
+			map.put(key, rb.getString(key));
+		}
+		return map;
+	}
+
+}

+ 367 - 0
src/main/java/net/mingsoft/base/biz/IBaseBiz.java

@@ -0,0 +1,367 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.base.biz;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import net.mingsoft.base.entity.BaseEntity;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName: BaseAction
+ * @Description:TODO(基础接口,应用层可继承该类)
+ * @author: 铭飞开发团队
+ * @date: 2018年3月19日 下午3:28:27
+ *
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+
+public interface IBaseBiz<T> extends IService<T> {
+
+    /**
+     * 添加记录
+     *
+     * @param table
+     *            表名称
+     * @param fields
+     *            编号
+     */
+    void insertBySQL(String table, Map fields);
+
+    /**
+     * 动态sql查询
+     *
+     * @param table
+     *            表名称
+     * @param fields
+     *            list集合
+     * @param wheres
+     *            条件 都是key-value对应
+     * @return 返回list实体数组
+     */
+    List queryBySQL(String table, List<String> fields, Map wheres);
+
+    /**
+     * 动态sql查询
+     *
+     * @param table
+     *            表名称
+     * @param fields
+     *            list集合
+     * @param wheres
+     *            条件 都是key-value对应
+     * @param begin
+     *            开始
+     * @param end
+     *            结束
+     * @return 返回list实体数组
+     */
+    List queryBySQL(String table, List<String> fields, Map wheres, Integer begin, Integer end);
+
+    /**
+     * 动态sql查询
+     *
+     * @param table
+     *            表名称
+     * @param fields
+     *            list集合
+     * @param wheres
+     *            条件 都是key-value对应
+     * @param sqlWhereList
+     *      前端高级搜索条件 示例:[{"action":"and","field":"qj_group","el":"like","model":"qjGroup","name":"任务组","type":"input","value":"1"}]
+     * @return 返回list实体数组
+     */
+    List queryBySQL(String table, List<String> fields, Map wheres,List<Map> sqlWhereList);
+
+    /**
+     * 动态sql查询
+     *
+     * @param table
+     *            表名称
+     * @param fields
+     *            list集合
+     * @param wheres
+     *            条件 都是key-value对应
+     * @param sqlWhereList
+     *      前端高级搜索条件 示例:[{"action":"and","field":"qj_group","el":"like","model":"qjGroup","name":"任务组","type":"input","value":"1"}]
+     * @param begin
+     *            开始
+     * @param end
+     *            结束
+     * @return 返回list实体数组
+     */
+    List queryBySQL(String table, List<String> fields, Map wheres,List<Map> sqlWhereList, Integer begin, Integer end);
+
+    /**
+     * 动态sql查询
+     *
+     * @param table
+     *            表名称
+     * @param fields
+     *            list集合
+     * @param wheres
+     *            条件 都是key-value对应
+     * @param sqlWhereList
+     *      前端高级搜索条件 示例:[{"action":"and","field":"qj_group","el":"like","model":"qjGroup","name":"任务组","type":"input","value":"1"}]
+     * @param orderBy
+     *            排序字段
+     * @param order
+     *            排序方式,asc;desc
+     * @return 返回list实体数组
+     */
+    List queryBySQL(String table, List<String> fields, Map wheres,List<Map> sqlWhereList, String orderBy,String order);
+
+    /**
+     * 动态sql查询
+     *
+     * @param table
+     *            表名称
+     * @param fields
+     *            list集合
+     * @param wheres
+     *            条件 都是key-value对应
+     * @param sqlWhereList
+     *      前端高级搜索条件 示例:[{"action":"and","field":"qj_group","el":"like","model":"qjGroup","name":"任务组","type":"input","value":"1"}]
+     * @param begin
+     *            开始
+     * @param end
+     *            结束
+     * @param orderBy
+     *            排序字段
+     * @param order
+     *            排序方式,asc;desc
+     * @return 返回list实体数组
+     */
+    List queryBySQL(String table, List<String> fields, Map wheres,List<Map> sqlWhereList, Integer begin, Integer end,String orderBy,String order);
+
+    /**
+     * 查询表中记录总数
+     *
+     * @param table
+     *            表名称
+     * @param wheres
+     *            条件 都是key-value对应
+     * @return 返回查询总数
+     */
+    int countBySQL(String table, Map wheres);
+
+    /**
+     * 查询表中记录总数
+     *
+     * @param table
+     *            表名称
+     * @param wheres
+     *            条件 都是key-value对应
+     * @param sqlWhereList
+     * 前端高级搜索条件 示例:[{"action":"and","field":"qj_group","el":"like","model":"qjGroup","name":"任务组","type":"input","value":"1"}]
+     * @return 返回查询总数
+     */
+    int countBySQL(String table, Map wheres, List<Map> sqlWhereList);
+
+
+    /**
+     * 动态SQL删除
+     *
+     * @param table
+     *            表名称
+     * @param wheres
+     *            條件 都是key-value对应
+     */
+    void deleteBySQL(String table, Map wheres);
+
+
+
+    /**
+     * 根据id集合实现批量的删除
+     * 扩展雪花编号的id
+     * @param ids
+     *            id集合
+     */
+    void delete(String[] ids);
+
+
+    /**
+     * 根据id集合实现批量的删除
+     *
+     * @param ids
+     *            id集合
+     */
+    void delete(int[] ids);
+
+
+    /**
+     * 动态SQL更新
+     *
+     * @param table
+     *            表名称
+     * @param fields
+     *            list集合每个map都是key-value对应
+     * @param wheres
+     *            条件 都是key-value对应
+     */
+    void updateBySQL(String table, Map fields, Map wheres);
+
+
+
+
+    /**
+     * 创建表
+     *
+     * @param table
+     *            表名称
+     * @param fileds
+     *            key:字段名称 list[0] 类型 list[1]长度 list[2]默认值 list[3]是否不填
+     */
+    void createTable(String table, Map<Object, List> fileds);
+
+
+    /**
+     * SQL修改表
+     *
+     * @param table
+     *            表名称
+     * @param fileds
+     *            key:字段名称 list[0] 类型 list[1]长度 list[2]默认值 list[3]是否不填
+     */
+    void alterTable(String table,Map fileds,String type);
+
+
+    /**
+     * 删除表
+     *
+     * @param table
+     *            表名称
+     */
+    void dropTable(String table);
+
+
+    /**
+     * 导入执行数据
+     *
+     * @param sql
+     *            sql语句
+     */
+    Object excuteSql(String sql);
+
+
+
+
+
+
+    /**
+     * 更新缓存
+     * 使用场景:当前这个类存在数据缓存,使用了mybitsPlus的更新、保存等方法没有刷新数据缓存,
+     * 调用该方法需要dao xml中实现一个更新方法
+     * xml示例:
+     * 	<update id="updateCache"  flushCache="true">
+     * 		UPDATE table set del=0 where del=-1
+     * 	</update>
+     */
+    void updateCache();
+
+
+
+    /**
+     * 根据id删除实体
+     *
+     * @param ene
+     *            要删除的主键id
+     */
+    @Deprecated
+    void deleteEntity(BaseEntity entity);
+
+    /**
+     * 根据id删除实体
+     *
+     * @param id
+     *            要删除的主键id
+     */
+    @Deprecated
+    void deleteEntity(int id);
+
+    /**
+     * 更具ID查询实体信息
+     *
+     * @param id
+     *            实体ID
+     * @return 返回实体
+     */
+    @Deprecated
+    <E> E getEntity(BaseEntity entity);
+
+    /**
+     * 更具ID查询实体信息
+     *
+     * @param id
+     *            实体ID
+     * @return 返回实体
+     */
+    @Deprecated
+    <E> BaseEntity getEntity(int id);
+
+
+
+    /**
+     * 查询,如果使用数据权限控制,推荐使用当前方法
+     */
+    List<T> query(BaseEntity entity);
+
+    /**
+     * 查询所有
+     *
+     * @return 返回list实体数组
+     */
+    @Deprecated
+    List<T> queryAll();
+
+    /**
+     * 查询数据表中记录集合总数</br>
+     * 可配合分页使用</br>
+     *
+     * @return 返回集合总数
+     */
+    @Deprecated
+    int queryCount();
+
+    /**
+     * 批量新增
+     *
+     * @param list
+     *            新增数据
+     */
+    @Deprecated
+    void saveBatch(List list);
+
+    /**
+     * 保存
+     *
+     * @param entity
+     *            实体
+     * @return 返回保存后的id
+     */
+    @Deprecated
+    int saveEntity(BaseEntity entity);
+
+
+
+    /**
+     * 更新实体
+     *
+     * @param entity
+     */
+    @Deprecated
+    void updateEntity(BaseEntity entity);
+
+
+}

+ 260 - 0
src/main/java/net/mingsoft/base/biz/impl/BaseBizImpl.java

@@ -0,0 +1,260 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+
+
+package net.mingsoft.base.biz.impl;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import net.mingsoft.base.biz.IBaseBiz;
+import net.mingsoft.base.dao.IBaseDao;
+import net.mingsoft.base.entity.BaseEntity;
+import net.mingsoft.base.util.SqlInjectionUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName:  BaseAction
+ * @Description:TODO(这里用一句话描述这个类的作用)
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:28:27
+ *
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public abstract class BaseBizImpl<M extends BaseMapper<T>,T> extends ServiceImpl<M,T> implements IBaseBiz<T> {
+
+
+	protected final Logger LOG = LoggerFactory.getLogger(this.getClass());
+
+	@Override
+	public int saveEntity(BaseEntity entity) {
+		return getDao().saveEntity(entity);
+	}
+
+	@Override
+	public void deleteEntity(int id) {
+		// TODO Auto-generated method stub
+		getDao().deleteEntity(id);
+	}
+
+	@Override
+	public void updateEntity(BaseEntity entity) {
+
+		// TODO Auto-generated method stub
+		getDao().updateEntity(entity);
+	}
+
+	@Override
+	public List<T> queryAll() {
+		// TODO Auto-generated method stub
+		return getDao().queryAll();
+	}
+
+
+
+	@Override
+	@Deprecated
+	public int queryCount() {
+		return getDao().queryCount();
+	}
+
+	@Override
+	public BaseEntity getEntity(int id) {
+		return getDao().getEntity(id);
+	}
+
+	@Override
+	public List queryBySQL(String table, List fields, Map wheres, Integer begin, Integer end) {
+		SqlInjectionUtil.filterContent(table);
+		// TODO Auto-generated method stub
+		return getDao().queryBySQL(table, fields, wheres,null,  begin, end, null,null);
+	}
+
+	@Override
+	public int countBySQL(String table, Map wheres) {
+		SqlInjectionUtil.filterContent(table);
+		// TODO Auto-generated method stub
+		return getDao().countBySQL(table, wheres, null);
+	}
+
+	@Override
+	public int countBySQL(String table, Map wheres, List<Map> sqlWhereList) {
+		SqlInjectionUtil.filterContent(table);
+		//对高级搜索进行了注入过滤
+		if(sqlWhereList!=null) {
+			sqlWhereList.forEach(map->{
+				SqlInjectionUtil.filterContent(map.get("field")+"");
+			});
+		}
+
+		return getDao().countBySQL(table, wheres, sqlWhereList);
+	}
+
+	@Override
+	public List queryBySQL(String table, List fields, Map wheres) {
+		SqlInjectionUtil.filterContent(table);
+		// TODO Auto-generated method stub
+		return getDao().queryBySQL(table, fields, wheres, null,null,  null, null,null);
+	}
+	@Override
+	public List queryBySQL(String table, List<String> fields, Map wheres, List<Map>sqlWhereList) {
+		SqlInjectionUtil.filterContent(table);
+		//对高级搜索进行了注入过滤
+		if(sqlWhereList!=null) {
+			sqlWhereList.forEach(map->{
+				SqlInjectionUtil.filterContent(map.get("field")+"");
+			});
+		}
+		// TODO Auto-generated method stub
+		return getDao().queryBySQL(table, fields, wheres,sqlWhereList,null,  null, null,null);
+	}
+	@Override
+	public List queryBySQL(String table, List<String> fields, Map wheres, List<Map>sqlWhereList, Integer begin, Integer end) {
+		SqlInjectionUtil.filterContent(table);
+		//对高级搜索进行了注入过滤
+		if(sqlWhereList!=null) {
+			sqlWhereList.forEach(map->{
+				SqlInjectionUtil.filterContent(map.get("field")+"");
+			});
+		}
+		// TODO Auto-generated method stub
+		return getDao().queryBySQL(table, fields, wheres,sqlWhereList,  begin, end, null,null);
+	}
+	@Override
+	public List queryBySQL(String table, List<String> fields, Map wheres, List<Map>sqlWhereList,String orderBy,String order) {
+		SqlInjectionUtil.filterContent(table);
+		//对高级搜索进行了注入过滤
+		if(sqlWhereList!=null) {
+			sqlWhereList.forEach(map->{
+				SqlInjectionUtil.filterContent(map.get("field")+"");
+			});
+		}
+		// TODO Auto-generated method stub
+		return getDao().queryBySQL(table, fields, wheres,sqlWhereList,  null, null, orderBy,order);
+	}
+	@Override
+	public List queryBySQL(String table, List<String> fields, Map wheres, List<Map>sqlWhereList, Integer begin, Integer end ,String orderBy,String order) {
+		SqlInjectionUtil.filterContent(table);
+		//对高级搜索进行了注入过滤
+		if(sqlWhereList!=null) {
+			sqlWhereList.forEach(map->{
+				SqlInjectionUtil.filterContent(map.get("field")+"");
+			});
+		}
+		// TODO Auto-generated method stub
+		return getDao().queryBySQL(table, fields, wheres,sqlWhereList,  begin, end, orderBy,order);
+	}
+	@Override
+	public void updateBySQL(String table, Map fields, Map wheres) {
+		SqlInjectionUtil.filterContent(table);
+		// TODO Auto-generated method stub
+		getDao().updateBySQL(table, fields, wheres);
+	}
+
+	@Override
+	public void deleteBySQL(String table, Map wheres) {
+		SqlInjectionUtil.filterContent(table);
+		// TODO Auto-generated method stub
+		getDao().deleteBySQL(table, wheres);
+	}
+
+	@Override
+	public void insertBySQL(String table, Map fields) {
+		SqlInjectionUtil.filterContent(table);
+		// TODO Auto-generated method stub
+		getDao().insertBySQL(table, fields);
+	}
+
+	@Override
+	public void createTable(String table, Map fileds) {
+		SqlInjectionUtil.filterContent(table);
+		// TODO Auto-generated method stub
+		getDao().createTable(table, fileds);
+	}
+
+
+	@Override
+	public void dropTable(String table) {
+		SqlInjectionUtil.filterContent(table);
+		// TODO Auto-generated method stub
+		getDao().dropTable(table);
+	}
+
+	@Override
+	public Object excuteSql(String sql) {
+		// TODO Auto-generated method stub
+		return getDao().excuteSql(sql);
+	}
+
+	@Override
+	public void alterTable(String table, Map fileds, String type) {
+		SqlInjectionUtil.filterContent(table);
+		getDao().alterTable(table, fileds, type);
+	}
+
+	/**
+	 * 不需要重写此方法,自动会
+	 *
+	 * @return
+	 */
+	protected abstract IBaseDao<T> getDao();
+
+	@Override
+	public void saveBatch(List list) {
+		getDao().saveBatch(list);
+	}
+
+	@Override
+	public void updateCache(){
+		getDao().updateCache();
+	}
+	@Override
+	public void delete(int[] ids) {
+		getDao().delete(ids);
+	}
+	@Override
+	public void delete(String[] ids) {
+		getDao().delete(ids);
+	}
+
+	@Override
+	public void deleteEntity(BaseEntity entity) {
+		// TODO Auto-generated method stub
+		getDao().deleteByEntity(entity);
+	}
+
+	@Override
+	public T getEntity(BaseEntity entity) {
+		// TODO Auto-generated method stub
+		return getDao().getByEntity(entity);
+	}
+
+	@Override
+	public List<T> query(BaseEntity entity) {
+		// TODO Auto-generated method stub
+		return getDao().query(entity);
+	}
+
+	@Override
+	public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
+		return super.getOne(queryWrapper, throwEx);
+	}
+
+
+}

+ 52 - 0
src/main/java/net/mingsoft/base/constant/Const.java

@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.base.constant;
+
+
+/**
+ * @ClassName:  BaseAction   
+ * @Description:TODO(这里用一句话描述这个类的作用)   
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:28:27   
+ *     
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public final class Const {
+
+	/**
+	 * action层对应的国际化资源文件
+	 */
+	public final static String RESOURCES = "net.mingsoft.base.resources.resources";
+
+	
+	/**
+	 * 默认编码格式
+	 */
+	public final static String UTF8 = "utf-8";
+	
+	/**
+	 * URL路径符
+	 */
+	public final static String SEPARATOR ="/";
+	
+
+	/**
+	 * 统一定义error错误值,用户返回消息统一
+	 */
+	public final static String ERROR ="error";
+	
+	/**
+	 * 统一定义error错误值,用户返回消息统一
+	 */
+	public final static String ERROR_500 ="/500/error.do";
+}

+ 32 - 0
src/main/java/net/mingsoft/base/constant/e/BaseCookieEnum.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.base.constant.e;
+
+
+/**
+ * @ClassName:  BaseAction   
+ * @Description:TODO(基础层cookie枚举,所有的cookie定义必须实现该结构)   
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:28:27   
+ *     
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public interface BaseCookieEnum {
+	/**
+	 * 返回该对象的字符串表示
+	 * 
+	 * @return 字符串
+	 */
+	public String toString();
+
+}

+ 38 - 0
src/main/java/net/mingsoft/base/constant/e/BaseEnum.java

@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.base.constant.e;
+
+
+/**
+ * @ClassName:  BaseAction   
+ * @Description:TODO(基模块用枚举类接口)   
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:28:27   
+ *     
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public interface BaseEnum {
+	
+	/**
+	 * 返回该对象的字符串表示
+	 * @return 字符串
+	 */
+	public String toString();
+
+	/**
+	 * 返回该对象的整型表示
+	 * @return 整型
+	 */
+	public int toInt() ;
+	
+}

+ 31 - 0
src/main/java/net/mingsoft/base/constant/e/BaseSessionEnum.java

@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.base.constant.e;
+
+
+/**
+ * @ClassName:  BaseAction
+ * @Description:TODO(基础层session枚举,所有的session定义必须实现该结构)
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:28:27
+ *
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public interface BaseSessionEnum {
+	/**
+	 * 返回该对象的字符串表示
+	 *
+	 * @return 字符串
+	 */
+	String toString();
+}

+ 59 - 0
src/main/java/net/mingsoft/base/constant/e/DeleteEnum.java

@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+package net.mingsoft.base.constant.e;
+
+/**
+ * 
+ * @ClassName:  DeleteEnum   
+ * @Description:TODO(删除枚举)
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:34:02   
+ *     
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public enum DeleteEnum implements BaseEnum{
+	/**
+	 * 伪删除(NOTDEL正常,值为0)
+	 */
+	NOTDEL(0,"正常"),
+
+	/**
+	 * 伪删除(DEL已删除,值为1)
+	 */
+	DEL(1,"已删除");
+	
+
+	
+	private String code;
+	
+	private int id;
+
+	/**
+	 * 构造方法
+	 * @param id 默认ID
+	 * @param code 传入的枚举类型
+	 */
+	DeleteEnum(int id,String code) {
+		this.code = code;
+		this.id = id;
+	}
+
+	@Override
+	public int toInt() {
+		return this.id;
+	}
+
+	@Override
+	public String toString() {
+		return this.code.toString();
+	}
+}

+ 267 - 0
src/main/java/net/mingsoft/base/dao/IBaseDao.java

@@ -0,0 +1,267 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.base.dao;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import net.mingsoft.base.entity.BaseEntity;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @ClassName:  IBaseDao
+ * @Description:TODO(基础dao)
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:34:58
+ *
+ * @param <E>
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public interface IBaseDao<E> extends BaseMapper<E> {
+
+	/**
+	 * SQL修改表
+	 *
+	 * @param table
+	 *            表名称
+	 * @param fileds
+	 *            key:字段名称 list[0] 类型 list[1]长度 list[2]默认值 list[3]是否不填
+	 */
+	void alterTable(@Param("table") String table, @Param("fileds") Map fileds, @Param("type") String type);
+
+	/**
+	 * SQL总数
+	 *
+	 * @param table
+	 *            表名称
+	 * @param wheres
+	 *            条件 都是key-value对应
+	 * @return 总数
+	 */
+	int countBySQL(@Param("table") String table, @Param("wheres") Map wheres, @Param("sqlWhereList") List<Map> sqlWhereList);
+
+	/**
+	 * SQL创建表
+	 *
+	 * @param table
+	 *            表名称
+	 * @param fileds
+	 *            key:字段名称 list[0] 类型 list[1]长度 list[2]默认值 list[3]是否不填
+	 */
+	void createTable(@Param("table") String table, @Param("fileds") Map<Object, List> fileds);
+
+	/**
+	 * SQL动态SQL删除
+	 *
+	 * @param table
+	 *            表名称
+	 * @param wheres
+	 *            條件 都是key-value对应
+	 */
+
+	void deleteBySQL(@Param("table") String table, @Param("wheres") Map wheres);
+
+	/**
+	 * SQL删除表
+	 *
+	 * @param table
+	 *            表名称
+	 */
+	void dropTable(@Param("table") String table);
+
+	/**
+	 * SQL导入执行数据
+	 *
+	 * @param sql
+	 *            sql语句
+	 */
+	@InterceptorIgnore(tenantLine = "true")
+	List excuteSql(@Param("sql") String sql);
+
+	/**
+	 * SQL添加记录
+	 *
+	 * @param table
+	 *            表名称
+	 * @param fields
+	 *            编号
+	 */
+	void insertBySQL(@Param("table") String table, @Param("fields") Map fields);
+
+	/**
+	 * SQL动态sql查询
+	 *
+	 * @param table
+	 *            表名称
+	 * @param fields
+	 *            list集合
+	 * @param wheres
+	 *            条件 都是key-value对应
+	 * @param begin
+	 *            开始位置
+	 * @param end
+	 *            结束位置
+	 * @param order
+	 *            排序方式,asc;desc
+	 * @return 返回查询结果
+	 */
+	@SuppressWarnings("rawtypes")
+	List queryBySQL(@Param("table") String table, @Param("fields") List<String> fields, @Param("wheres") Map wheres, @Param("sqlWhereList") List<Map> sqlWhereList,
+			@Param("begin") Integer begin, @Param("end") Integer end, @Param("orderBy") String orderBy, @Param("order") String order);
+
+	/**
+	 * SQL动态SQL更新
+	 *
+	 * @param table
+	 *            表名称
+	 * @param fields
+	 *            list集合每个map都是key-value对应
+	 * @param wheres
+	 *            条件 都是key-value对应
+	 */
+	void updateBySQL(@Param("table") String table, @Param("fields") Map fields, @Param("wheres") Map wheres);
+
+	/**
+	 * 根据id集合实现批量的删除
+	 *
+	 * @param ids
+	 *            id集合
+	 */
+	void delete(@Param("ids") int[] ids);
+
+	/**
+	 * 根据id集合实现批量的删除
+	 *
+	 * @param ids
+	 *            id集合
+	 */
+	void delete(@Param("ids") String[] ids);
+
+	/**
+	 * 更新缓存
+	 * 使用场景:当前这个类存在数据缓存,使用了mybitsPlus的更新、保存等方法没有刷新数据缓存,
+	 * 调用该方法需要dao xml中实现一个更新方法
+	 * xml示例:
+	 * 	<update id="updateCache"  flushCache="true">
+	 * 		UPDATE table set del=0 where del=-1
+	 * 	</update>
+	 */
+	void updateCache();
+
+	/**
+	 * 根据id删除实体 推荐使用delete(int[] ids)
+	 *
+	 * @param id
+	 *            要删除的主键id
+	 */
+	@Deprecated
+	void deleteEntity(int id);
+
+	/**
+	 * 通过entity条件删除对应entity
+	 * @param entity
+	 */
+	@Deprecated
+	void deleteByEntity(BaseEntity entity);
+
+	/**
+	 * 根据ID查询实体信息
+	 *
+	 * @param id
+	 *            实体ID
+	 * @return 返回base实体
+	 */
+	@Deprecated
+	BaseEntity getEntity(Integer id);
+	/**
+	 * 根据entity查询实体信息
+	 *
+	 * @param entity
+	 *            实体
+	 * @return 返回base实体
+	 */
+	@Deprecated
+	<E>E getByEntity(BaseEntity entity);
+
+	/**
+	 * 查询
+	 */
+	List<E> query(BaseEntity entity);
+
+	/**
+	 * 查询所有
+	 *
+	 * @return 返回list数组
+	 */
+	@Deprecated
+	List<E> queryAll();
+
+	/**
+	 * 分页查询,4.5.8版本之后推荐使用query方法查询
+	 *
+	 * @param pageNo
+	 *            页码
+	 * @param pageSize
+	 *            显示条数
+	 * @param orderBy
+	 *            排序字段
+	 * @param order
+	 *            order 排序方式,true:asc;fales:desc
+	 * @return 返回list数组
+	 */
+	@Deprecated
+	List<E> queryByPage(@Param("pageNo") int pageNo, @Param("pageSize") int pageSize,
+			@Param("orderBy") String orderBy, @Param("order") boolean order);
+
+	/**
+	 * 查询数据表中记录集合总数
+	 *
+	 * @return 返回查询总条数
+	 */
+	@Deprecated
+	int queryCount();
+
+	/**
+	 * 批量新增
+	 *
+	 * @param list
+	 *            新增数据
+	 *过期理由不适配oracle,请使用mybatis-plus的biz.saveBatch批量保存,注:mybatis-plus在dao层没有批量保存方法
+	 */
+	@Deprecated
+	void saveBatch(@Param("list") List list);
+
+	/**
+	 * 保存
+	 *
+	 * @param entity
+	 *            实体
+	 * @return 返回保存后的id
+	 */
+	@Deprecated
+	int saveEntity(BaseEntity entity);
+
+	/**
+	 * 更新实体
+	 *
+	 * @param entity
+	 *            实体
+	 */
+	@Deprecated
+	void updateEntity(BaseEntity entity);
+
+
+}

+ 500 - 0
src/main/java/net/mingsoft/base/dao/IBaseDao.xml

@@ -0,0 +1,500 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="net.mingsoft.base.dao.IBaseDao">
+
+    <!-- mysql根据sql动态查询开始 -->
+    <select id="queryBySQL" resultType="Map" databaseId="mysql">
+        select
+        <if test="fields !=null">
+            <foreach item="field" collection="fields" open=""
+                     separator="," close="">
+                ${field}
+            </foreach>
+        </if>
+        <if test="fields ==null">
+            *
+        </if>
+        from ${table}
+        <where>
+            <foreach item="item" index="key" collection="wheres" open="AND"
+                     separator="AND" close=""> ${key} = #{item}
+            </foreach>
+            <include refid="net.mingsoft.base.dao.IBaseDao.sqlWhere"></include>
+        </where>
+        <if test="orderBy !=null">
+            order by ${orderBy}
+            <if test="order != null">
+                <if test="order =='desc'">
+                    desc
+                </if>
+                <if test="order =='asc'">
+                    asc
+                </if>
+            </if>
+            <if test="order==null">desc</if>
+        </if>
+        <if test="begin != null">
+            limit ${begin}
+            <if test="end !=null ">
+                ,${end}
+            </if>
+        </if>
+    </select>
+    <!-- mysql根据sql动态查询结束 -->
+
+    <!-- oracle根据sql动态查询开始 -->
+    <select id="queryBySQL" resultType="Map" databaseId="oracle">
+        select
+        <if test="fields !=null">
+            <foreach item="field" collection="fields" open=""
+                     separator="," close="">
+                ${field}
+            </foreach>
+        </if>
+        <if test="fields ==null">
+            *
+        </if>
+        from ${table}
+        <where>
+            <foreach item="item" index="key" collection="wheres" close="">
+                <if test="item != null">
+                    AND ${key} = #{item}
+                </if>
+            </foreach>
+            <include refid="net.mingsoft.base.dao.IBaseDao.sqlWhere"></include>
+        </where>
+        <if test="orderBy !=null">
+            order by ${orderBy}
+            <if test="order != null">
+                <if test="order =='desc'">
+                    desc
+                </if>
+                <if test="order =='asc'">
+                    asc
+                </if>
+            </if>
+            <if test="order==null">desc</if>
+        </if>
+    </select>
+    <!-- oracle根据sql动态查询结束 -->
+
+    <!-- sqlserver根据sql动态查询开始 -->
+    <select id="queryBySQL" resultType="Map" databaseId="sqlserver">
+        select
+            <if test="end !=null ">
+                TOP ${end}
+            </if>
+            <if test="fields !=null">
+                <foreach item="field" collection="fields" open=""
+                         separator="," close="">
+                    ${field}
+                </foreach>
+            </if>
+            <if test="fields ==null">
+                *
+            </if>,ROW_NUMBER ( ) OVER ( ORDER BY RAND( ) ) PAGE_ROW_NUMBER from ${table}
+        <where>
+            <foreach item="item" index="key" collection="wheres" open="AND"
+                     separator="AND" close=""> ${key} = #{item}
+            </foreach>
+            <include refid="net.mingsoft.base.dao.IBaseDao.sqlWhere"></include>
+        </where>
+        <if test="begin != null">
+            and PAGE_ROW_NUMBER > ${begin}
+        </if>
+        <if test="orderBy !=null">
+            order by ${orderBy}
+            <if test="order != null">
+                <if test="order =='desc'">
+                    desc
+                </if>
+                <if test="order =='asc'">
+                    asc
+                </if>
+            </if>
+            <if test="order==null">desc</if>
+        </if>
+    </select>
+    <!-- sqlserver根据sql动态查询结束 -->
+
+    <!-- 根据sql动态查询开始 -->
+    <select id="countBySQL" resultType="int">
+        select count(*)
+        from ${table}
+        <where>
+            <if test="wheres != null">
+                <foreach item="item" index="key" collection="wheres" open=""
+                         separator="AND" close=""> ${key} = ${item}
+                </foreach>
+            </if>
+            <if test="wheres == null">
+                del = 0
+            </if>
+            <include refid="net.mingsoft.base.dao.IBaseDao.sqlWhere"></include>
+        </where>
+    </select>
+    <!-- 根据sql动态查询结束 -->
+
+    <!-- mysql或SqlServer根据sql动态更新开始 -->
+    <update id="updateBySQL">
+        update ${table} set
+        <foreach item="field" index="name" collection="fields" open=""
+                 separator="," close="">
+            ${name}=#{field}
+        </foreach>
+        <where>
+            <foreach item="item" index="key" collection="wheres" open=""
+                     separator="AND" close=""> ${key} = ${item}
+            </foreach>
+        </where>
+    </update>
+    <!-- mysql或SqlServer根据sql动态更新结束 -->
+
+    <!-- 根据sql动态删除开始 -->
+    <update id="deleteBySQL">
+        delete from ${table} where
+        <foreach item="item" index="key" collection="wheres" open=""
+                 separator="AND" close=""> ${key} = #{item}
+        </foreach>
+    </update>
+    <!-- 根据sql动态删除结束 -->
+
+    <!-- 根据sql动态新增开始 -->
+    <insert id="insertBySQL">
+        insert into ${table}
+        <foreach item="field" index="key" collection="fields" open="("
+                 separator="," close=")">${key}
+        </foreach>
+        values
+        <foreach item="field" index="key" collection="fields" open="("
+                 separator="," close=")">#{field}
+        </foreach>
+    </insert>
+    <!-- 根据sql动态新增结束 -->
+
+    <!-- 根据sql动态创建表开始 -->
+    <sql id="createTables">
+		 CONSTRAINT fk_${table}_id FOREIGN KEY (basicId) REFERENCES basic (basic_id) ON DELETE CASCADE
+	</sql>
+    <update id="createTable" statementType="STATEMENT" databaseId="mysql">
+        CREATE TABLE ${table} (
+        basicId int(11) NOT NULL,
+        PRIMARY KEY (basicId),
+        <include refid="createTables"></include>
+        ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
+    </update>
+    <!-- 根据sql动态创建表结束 -->
+    <!-- 根据sql动态更新表开始 -->
+    <sql id="alterTableSql" databaseId="mysql">
+        ALTER TABLE ${table} change ${fileds.fieldOldName}
+        ${fileds.fieldName} ${fileds.fieldType}
+        <if test="fileds.default !=null and fileds.default !=''">default '${fileds.default}'</if>
+    </sql>
+
+    <sql id="alterTableSql" databaseId="sqlserver">
+        ALTER TABLE ${table} change ${fileds.fieldOldName}
+        ${fileds.fieldName} ${fileds.fieldType}
+        <if test="fileds.default !=null and fileds.default !=''">default '${fileds.default}'</if>
+    </sql>
+
+    <sql id="alterTableSql" databaseId="oracle">
+        ALTER TABLE ${table} RENAME TO ${fileds.fieldOldName}
+        ${fileds.fieldName} ${fileds.fieldType}
+        <if test="fileds.default !=null and fileds.default !=''">default '${fileds.default}'</if>
+    </sql>
+
+    <sql id="alterTableAddType">${fileds.fieldType}</sql>
+    <update id="alterTable" statementType="STATEMENT">
+        <choose>
+            <when test="type=='add'">
+                ALTER TABLE ${table} add ${fileds.fieldName}
+                <include refid="alterTableAddType"></include>
+                <if test="fileds.default !=null and fileds.default != ''">default '${fileds.default}'</if>
+            </when>
+            <when test="type=='modify'">
+                <include refid="alterTableSql"></include>
+            </when>
+            <when test="type=='drop'">
+                ALTER TABLE ${table} drop column ${fileds.fieldName}
+            </when>
+        </choose>
+
+    </update>
+    <!-- 根据sql动态更新表结束 alterTable-->
+
+    <!-- 根据sql动态删除表开始 -->
+    <update id="dropTable" statementType="STATEMENT">
+		DROP TABLE ${table}
+	</update>
+    <!-- 根据sql动态删除表结束 -->
+
+    <!-- 导入sql语句 -->
+    <select id="excuteSql" parameterType="String" statementType="STATEMENT" resultType="java.util.Map">
+		${sql}
+	</select>
+    <!--导入sql语句 -->
+
+    <sql id="sqlWhere" databaseId="mysql">
+        <if test="sqlWhereList != null">
+        <foreach collection="sqlWhereList" item="item" index="index"
+                 open="and( " separator=" " close=" )">
+
+            <if test="item.el == 'eq'">
+                <choose>
+                    <when test="item.multiple != null and item.multiple == true">
+                        FIND_IN_SET(#{item.value}, ${item.field})>0
+                    </when>
+                    <otherwise>
+                        ${item.field} = #{item.value}
+                    </otherwise>
+                </choose>
+            </if>
+            <if test="item.el == 'gt'">
+                <choose>
+                    <when test="item.type=='time'||item.type=='date'">
+                        <if test="item.type=='time'">
+                            date_format(${item.field},'%T') &gt; date_format(#{item.value},'%T')
+                        </if>
+                        <if test="item.type=='date'">
+                            date_format(${item.field},'%Y-%m-%d %H:%i:%s') &gt; date_format(#{item.value},'%Y-%m-%d %H:%i:%s')
+                        </if>
+                    </when>
+                    <otherwise>
+                        ${item.field} &gt; #{item.value}
+                    </otherwise>
+                </choose>
+            </if>
+            <if test="item.el == 'gte'">
+                ${item.field} &gt;= #{item.value}
+            </if>
+            <if test="item.el == 'lt'">
+                <choose>
+                    <when test="item.type=='time'||item.type=='date'">
+                        <if test="item.type=='time'">
+                            date_format(${item.field},'%T') &lt; date_format(#{item.value},'%T')
+                        </if>
+                        <if test="item.type=='date'">
+                            date_format(${item.field},'%Y-%m-%d %H:%i:%s') &lt; date_format(#{item.value},'%Y-%m-%d %H:%i:%s')
+                        </if>
+                    </when>
+                    <otherwise>
+                        ${item.field} &lt; #{item.value}
+                    </otherwise>
+                </choose>
+            </if>
+            <if test="item.el == 'lte'">
+                ${item.field} &lt;= #{item.value}
+            </if>
+            <if test="item.el == 'like'">
+                ${item.field} like CONCAT(CONCAT('%',#{item.value}),'%')
+            </if>
+            <if test="item.el == 'likeLeft'">
+                ${item.field} like CONCAT(CONCAT(#{item.value}),'%')
+            </if>
+            <if test="item.el == 'likeRight'">
+                ${item.field} like CONCAT('%',#{item.value})
+            </if>
+            <if test="item.el == 'in'">
+                ${item.field} in (${item.value})
+            </if>
+            <if test="item.el == 'range'">
+                <if test="item.type=='time'">
+                    date_format(${item.field},'%T') BETWEEN date_format(#{item.value[0]},'%T') AND date_format(#{item.value[1]},'%T')
+                </if>
+                <if test="item.type=='date'">
+                    date_format(${item.field},'%Y-%m-%d %H:%i:%s') BETWEEN date_format(#{item.value[0]},'%Y-%m-%d %H:%i:%s') AND date_format(#{item.value[1]},'%Y-%m-%d %H:%i:%s')
+                </if>
+            </if>
+
+            <if test="index != (sqlWhereList.size() - 1)">
+                <choose>
+                    <!--防注入-->
+                    <when test="item.action == 'and' or item.action == 'or'">
+                        ${item.action}
+                    </when>
+                    <otherwise>
+                        and
+                    </otherwise>
+                </choose>
+            </if>
+        </foreach>
+        </if>
+    </sql>
+
+    <sql id="sqlWhere" databaseId="sqlserver">
+        <if test="sqlWhereList != null">
+            <foreach collection="sqlWhereList" item="item" index="index"
+                     open="and( " separator=" " close=" )">
+
+                <if test="item.el == 'eq'">
+                    <choose>
+                        <when test="item.multiple != null and item.multiple == true">
+                            FIND_IN_SET(#{item.value}, ${item.field})>0
+                        </when>
+                        <otherwise>
+                            ${item.field} = #{item.value}
+                        </otherwise>
+                    </choose>
+                </if>
+                <if test="item.el == 'gt'">
+                    <choose>
+                        <when test="item.type=='time'||item.type=='date'">
+                            <if test="item.type=='time'">
+                                date_format(${item.field},'%T') &gt; date_format(#{item.value},'%T')
+                            </if>
+                            <if test="item.type=='date'">
+                                date_format(${item.field},'%Y-%m-%d %H:%i:%s') &gt; date_format(#{item.value},'%Y-%m-%d %H:%i:%s')
+                            </if>
+                        </when>
+                        <otherwise>
+                            ${item.field} &gt; #{item.value}
+                        </otherwise>
+                    </choose>
+                </if>
+                <if test="item.el == 'gte'">
+                    ${item.field} &gt;= #{item.value}
+                </if>
+                <if test="item.el == 'lt'">
+                    <choose>
+                        <when test="item.type=='time'||item.type=='date'">
+                            <if test="item.type=='time'">
+                                date_format(${item.field},'%T') &lt; date_format(#{item.value},'%T')
+                            </if>
+                            <if test="item.type=='date'">
+                                date_format(${item.field},'%Y-%m-%d %H:%i:%s') &lt; date_format(#{item.value},'%Y-%m-%d %H:%i:%s')
+                            </if>
+                        </when>
+                        <otherwise>
+                            ${item.field} &lt; #{item.value}
+                        </otherwise>
+                    </choose>
+                </if>
+                <if test="item.el == 'lte'">
+                    ${item.field} &lt;= #{item.value}
+                </if>
+                <if test="item.el == 'like'">
+                    ${item.field} like CONCAT(CONCAT('%',#{item.value}),'%')
+                </if>
+                <if test="item.el == 'likeLeft'">
+                    ${item.field} like CONCAT(CONCAT(#{item.value}),'%')
+                </if>
+                <if test="item.el == 'likeRight'">
+                    ${item.field} like CONCAT('%',#{item.value})
+                </if>
+                <if test="item.el == 'in'">
+                    ${item.field} in (${item.value})
+                </if>
+                <if test="item.el == 'range'">
+                    <if test="item.type=='time'">
+                        date_format(${item.field},'%T') BETWEEN date_format(#{item.value[0]},'%T') AND date_format(#{item.value[1]},'%T')
+                    </if>
+                    <if test="item.type=='date'">
+                        date_format(${item.field},'%Y-%m-%d %H:%i:%s') BETWEEN date_format(#{item.value[0]},'%Y-%m-%d %H:%i:%s') AND date_format(#{item.value[1]},'%Y-%m-%d %H:%i:%s')
+                    </if>
+                </if>
+
+                <if test="index != (sqlWhereList.size() - 1)">
+                    <choose>
+                        <!--防注入-->
+                        <when test="item.action == 'and' or item.action == 'or'">
+                            ${item.action}
+                        </when>
+                        <otherwise>
+                            and
+                        </otherwise>
+                    </choose>
+                </if>
+            </foreach>
+        </if>
+    </sql>
+
+    <sql id="sqlWhere" databaseId="oracle">
+        <if test="sqlWhereList != null">
+            <foreach collection="sqlWhereList" item="item" index="index"
+                     open="and( " separator=" " close=" )">
+                <if test="item.value != null">
+                    <if test="item.el == 'eq'">
+                        <choose>
+                            <when test="item.multiple != null and item.multiple == true">
+                                FIND_IN_SET('${item.value}', ${item.field})>0
+                            </when>
+                            <otherwise>
+                                ${item.field} = '${item.value}'
+                            </otherwise>
+                        </choose>
+                    </if>
+                    <if test="item.el == 'gt'">
+                        <choose>
+                            <when test="item.type=='time'||item.type=='date'">
+                                <if test="item.type=='time'">
+                                    to_date(${item.field},'%T') &gt; to_date(${item.value},'%T')
+                                </if>
+                                <if test="item.type=='date'">
+                                    ${item.field} &gt; to_date('${item.value}','yyyy-mm-dd hh24:mi:ss')
+                                </if>
+                            </when>
+                            <otherwise>
+                                ${item.field} &gt; #{item.value}
+                            </otherwise>
+                        </choose>
+                    </if>
+                    <if test="item.el == 'gte'">
+                        ${item.field} &gt;= #{item.value}
+                    </if>
+                    <if test="item.el == 'lt'">
+                        <choose>
+                            <when test="item.type=='time'||item.type=='date'">
+                                <if test="item.type=='time'">
+                                    to_date(${item.field},'%T') &lt; to_date(${item.value},'%T')
+                                </if>
+                                <if test="item.type=='date'">
+                                    ${item.field} &lt; to_date('${item.value}','yyyy-mm-dd hh24:mi:ss')
+                                </if>
+                            </when>
+                            <otherwise>
+                                ${item.field} &lt; #{item.value}
+                            </otherwise>
+                        </choose>
+                    </if>
+                    <if test="item.el == 'lte'">
+                        ${item.field} &lt;= #{item.value}
+                    </if>
+                    <if test="item.el == 'like'">
+                        ${item.field} like CONCAT(CONCAT('%',#{item.value}),'%')
+                    </if>
+                    <if test="item.el == 'likeLeft'">
+                        ${item.field} like CONCAT(CONCAT(#{item.value}),'%')
+                    </if>
+                    <if test="item.el == 'likeRight'">
+                        ${item.field} like CONCAT('%',#{item.value})
+                    </if>
+                    <if test="item.el == 'in'">
+                        ${item.field} in (${item.value})
+                    </if>
+                    <if test="item.el == 'range'">
+                        <if test="item.type=='time'">
+                            to_date(${item.field},'%T') BETWEEN to_date(#{item.value[0]},'%T') AND to_date(#{item.value[1]},'%T')
+                        </if>
+                        <if test="item.type=='date'">
+                            ${item.field} BETWEEN to_date('${item.value[0]}','yyyy-mm-dd hh24:mi:ss') AND to_date('${item.value[1]}','yyyy-mm-dd hh24:mi:ss')
+                        </if>
+                    </if>
+
+                    <if test="index != (sqlWhereList.size() - 1)">
+                        <choose>
+                            <!--防注入-->
+                            <when test="item.action == 'and' or item.action == 'or'">
+                                ${item.action}
+                            </when>
+                            <otherwise>
+                                and
+                            </otherwise>
+                        </choose>
+                    </if>
+                </if>
+            </foreach>
+        </if>
+    </sql>
+
+
+</mapper>

+ 275 - 0
src/main/java/net/mingsoft/base/entity/BaseEntity.java

@@ -0,0 +1,275 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.base.entity;
+
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import net.mingsoft.base.constant.e.DeleteEnum;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @ClassName:  BaseEntity
+ * @Description:TODO(基础实体类,其他所有实体都需要继承)
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:36:17
+ *历史修订: 2022-02-17 setOrderBy() 修复orderBy字段可能存在的sql注入问题
+ *
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public abstract class  BaseEntity implements Serializable{
+
+	/**
+	 * 创建用户编号
+	 */
+	protected String createBy;
+	/**
+	 * 创建日期
+	 */
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+	protected Date createDate;
+
+	/**
+	 * 标记
+	 */
+	protected Integer del=0;
+
+	/**
+	 * 实体编号(唯一标识)
+	 */
+	protected String id;
+
+	/**
+	 * 备注
+	 */
+	@TableField(exist = false)
+	protected String remarks;
+
+	/**
+	 * 最后更新用户编号
+	 */
+	protected String updateBy;
+
+	/**
+	 * 最后更新日期
+	 */
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+	protected Date updateDate;
+
+	/**
+	 * 自定义SQL where条件,需要配合对应dao.xml使用
+	 */
+	@JsonIgnore
+	@TableField(exist = false)
+	protected String sqlWhere;
+
+	/**
+	 * 自定义SQL where条件,需要配合对应dao.xml使用
+	 */
+	@JsonIgnore
+	@TableField(exist = false)
+	protected String sqlDataScope;
+
+	/**
+	 * 排序字段
+	 */
+	@JsonIgnore
+	@TableField(exist = false)
+	protected String orderBy;
+
+	/**
+	 * 排序方式
+	 */
+	@TableField(exist = false)
+	protected String order;
+
+
+	public String getCreateBy() {
+		return createBy;
+	}
+
+	public void setCreateBy(String createBy) {
+		this.createBy = createBy;
+	}
+
+	public Date getCreateDate() {
+		return createDate;
+	}
+
+	public void setCreateDate(Date createDate) {
+		this.createDate = createDate;
+	}
+
+	public Integer getDel() {
+		return del;
+	}
+
+	@JsonIgnore
+	@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+	public void setDel(DeleteEnum del) {
+		this.del = del.toInt();
+	}
+
+	public void setDel(Integer del) {
+		this.del = del;
+	}
+
+	public String getId() {
+		if(StringUtils.isEmpty(this.id) || this.id.equals("0")){
+			return null;
+		}
+		return this.id;
+	}
+
+	/**
+	 * 方便业务层获取id,为空返回null
+	 * @return
+	 */
+	public Integer getIntegerId(){
+		if(StringUtils.isEmpty(this.getId())){
+			return null;
+		}else {
+			return Integer.parseInt(this.getId());
+		}
+	}
+
+	/**
+	 * 方便业务层获取id,为空返回0
+	 * @return id
+	 */
+	public int getIntId(){
+		if(StringUtils.isEmpty(this.getId())){
+			return 0;
+		}else {
+			return Integer.parseInt(this.getId());
+		}
+	}
+
+
+	/**
+	 *
+	 * @param id
+	 */
+	public void setId(String id) {
+		if(StringUtils.isEmpty(id) || id.equals("0")){
+			id = null;
+		}
+		this.id = id;
+	}
+
+	/**
+	 * 方便业务层设置id
+	 * @return
+	 */
+	@JsonIgnore
+	public void setIntegerId(Integer id) {
+		this.id = String.valueOf(id);
+	}
+
+	/**
+	 * 方便业务层设置id
+	 * @return
+	 */
+	@JsonIgnore
+	public void setIntId(int id) {
+		this.id = String.valueOf(id);
+	}
+
+	public String getRemarks() {
+		return remarks;
+	}
+
+	public void setRemarks(String remarks) {
+		this.remarks = remarks;
+	}
+
+	public String getUpdateBy() {
+		return updateBy;
+	}
+
+	public void setUpdateBy(String updateBy) {
+		this.updateBy = updateBy;
+	}
+
+	public Date getUpdateDate() {
+		return updateDate;
+	}
+
+	public void setUpdateDate(Date updateDate) {
+		this.updateDate = updateDate;
+	}
+
+	@JsonIgnore
+	public String getSqlWhere() {
+		return sqlWhere;
+	}
+
+	@JsonIgnore
+	public List getSqlWhereList() {
+		if(StringUtils.isNotBlank(sqlWhere)){
+			try {
+				return JSONUtil.toList(sqlWhere,Map.class);
+			}catch (Exception e){
+				e.printStackTrace();
+			}
+		}
+		return Collections.EMPTY_LIST;
+	}
+
+	public void setSqlWhere(String sqlWhere) {
+		this.sqlWhere = sqlWhere;
+	}
+
+	public String getOrderBy() {
+		return orderBy;
+	}
+
+	public void setOrderBy(String orderBy) {
+		//若orderBy存在空格可能有sql注入问题
+		if (orderBy != null){
+			orderBy = orderBy.replaceAll(" ","");
+		}
+		this.orderBy = orderBy;
+	}
+
+
+	public String getSqlDataScope() {
+		return sqlDataScope;
+	}
+
+	public void setSqlDataScope(String sqlDataScope) {
+		this.sqlDataScope = sqlDataScope;
+	}
+
+	public String getOrder() {
+		return order;
+	}
+
+	public void setOrder(String order) {
+		this.order = order;
+	}
+
+
+
+}

+ 177 - 0
src/main/java/net/mingsoft/base/entity/ResultData.java

@@ -0,0 +1,177 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.base.entity;
+
+
+import cn.hutool.json.JSONUtil;
+import org.springframework.http.HttpStatus;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @ClassName: ResultJson
+ * @Description:TODO(json数据返回数据格式)
+ * @author: 铭飞开发团队
+ * @date: 2018年3月19日 下午3:41:53
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public class ResultData extends HashMap<String, Object> {
+
+    /**
+     * 状态码
+     */
+    public static final String CODE_KEY = "code";
+    /**
+     * 数据
+     */
+    public static final String DATA_KEY = "data";
+    /**
+     * 信息
+     */
+    public static final String MSG_KEY = "msg";
+    /**
+     * 请求状态
+     */
+    public static final String RESULT_KEY = "result";
+
+
+    public static ResultData build() {
+        return new ResultData();
+    }
+
+    public ResultData code(HttpStatus code) {
+        return add(RESULT_KEY, code == HttpStatus.OK).add(CODE_KEY, code.value());
+    }
+
+    public ResultData code(String code) {
+        return add(RESULT_KEY, code.equalsIgnoreCase(HttpStatus.OK.toString())).add(CODE_KEY, code);
+    }
+
+
+    /**
+     * 返回信息
+     *
+     * @param msg
+     * @return
+     */
+    public ResultData msg(String msg) {
+        return add(MSG_KEY, msg);
+    }
+
+    /**
+     * 返回数据
+     *
+     * @param data
+     * @return
+     */
+    public ResultData data(Object data) {
+        return add(DATA_KEY, data);
+    }
+
+    /**
+     * 成功返回
+     *
+     * @return
+     */
+    public ResultData success() {
+        return code(HttpStatus.OK);
+    }
+
+    /**
+     * 成功返回
+     *
+     * @return
+     */
+    public ResultData success(Object data) {
+        return success().data(data);
+    }
+
+    /**
+     * 成功返回
+     *
+     * @return
+     */
+    public ResultData success(String msg, Object data) {
+        return success().msg(msg).data(data);
+    }
+
+    /**
+     * 错误返回
+     *
+     * @return
+     */
+    public ResultData error() {
+        return code(HttpStatus.INTERNAL_SERVER_ERROR);
+    }
+
+    /**
+     * 错误返回
+     *
+     * @return
+     */
+    public ResultData error(String msg) {
+        return error().msg(msg);
+    }
+
+    /**
+     * 添加返回参数
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public ResultData add(String key, Object value) {
+        this.put(key, value);
+        return this;
+    }
+
+    /**
+     * 获取data对象
+     * @param c 对象类型
+     * @param <T> 泛性
+     * @return null 可能转换失败
+     */
+    public <T> T getData(Class<T> c) {
+        Object obj = this.get(DATA_KEY);
+        //主要是优化微服务转换,默认微服务是不能直接转换实体,需要将map 转 实体,
+        if(obj instanceof Map) {
+            return  JSONUtil.toBean(JSONUtil.toJsonStr(obj),c);
+        }
+        return (T)obj;
+    }
+
+    /**
+     * 获取文本提示信息
+     * @return
+     */
+    public String getMsg() {
+        return this.get(MSG_KEY)+"";
+    }
+
+    /**
+     * 获取编码
+     * @return
+     */
+    public int getCode() {
+        return Integer.parseInt(this.get(CODE_KEY)+"");
+    }
+
+    /**
+     * 判断接口成功状态
+     * @return true:成功
+     */
+    public boolean isSuccess() {
+        return Boolean.parseBoolean(this.get(RESULT_KEY)+"");
+    }
+}

+ 94 - 0
src/main/java/net/mingsoft/base/exception/BusinessException.java

@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+package net.mingsoft.base.exception;
+
+import org.springframework.http.HttpStatus;
+
+/**
+ * 业务异常处理
+ *
+ * @author 铭软开发团队-Administrator
+ * @date 2018年7月6日
+ * 历史修订: 2023-06-13 业务异常移至base包,暂不删除basic的异常类
+ */
+
+public class BusinessException extends RuntimeException {
+
+    private HttpStatus code = HttpStatus.INTERNAL_SERVER_ERROR;
+    private String msg;
+    private Object data;
+    private String url;
+
+    public BusinessException(String msg) {
+        super(msg);
+        this.msg = msg;
+    }
+
+    public BusinessException(HttpStatus code, String msg, Object data) {
+        super(msg);
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+    }
+
+    public BusinessException(String msg, Object data) {
+        super(msg);
+        this.msg = msg;
+        this.data = data;
+    }
+
+    public BusinessException(String msg, String url) {
+        super(msg);
+        this.msg = msg;
+        this.url = url;
+    }
+
+    /**
+     * 自定义异常信息
+     *
+     * @param code 错误码 HttpStatus
+     * @param msg  错误信息
+     */
+    public BusinessException(HttpStatus code, String msg) {
+        super(msg);
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public HttpStatus getCode() {
+        return code;
+    }
+
+    public void setCode(HttpStatus code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+}

+ 36 - 0
src/main/java/net/mingsoft/base/job/BaseJob.java

@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.base.job;
+
+import org.quartz.Job;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 
+ * @ClassName:  BaseJob   
+ * @Description:TODO(基础job类)   
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:44:09   
+ *     
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public abstract class BaseJob  implements Job {
+
+	/*
+	 * log4j日志记录
+	 */
+	protected final Logger LOG = LoggerFactory.getLogger(this.getClass());
+	
+	
+}

+ 56 - 0
src/main/java/net/mingsoft/base/resolver/MultipartResolver.java

@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+package net.mingsoft.base.resolver;
+
+import org.springframework.web.multipart.commons.CommonsMultipartResolver;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 
+ * @ClassName:  MultipartResolver   
+ * @Description:TODO(同时使用了MultipartResolver 和ServletFileUpload 的冲突解决)   
+ * @author: 铭飞开发团队
+ * @date:   2018年3月19日 下午3:46:38   
+ *     
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+public class MultipartResolver extends CommonsMultipartResolver {  
+    private String excludeUrls;     
+    private String[] excludeUrlArray;  
+      
+    public String getExcludeUrls() {  
+        return excludeUrls;  
+    }  
+    public void setExcludeUrls(String excludeUrls) {  
+        this.excludeUrls = excludeUrls;  
+        this.excludeUrlArray = excludeUrls.split(",");  
+    }  
+  
+    /** 
+     * 这里是处理Multipart http的方法。如果这个返回值为true,那么Multipart http body就会MyMultipartResolver 消耗掉.如果这里返回false 
+     * 那么就会交给后面的自己写的处理函数处理例如刚才ServletFileUpload 所在的函数 
+     * @see CommonsMultipartResolver#isMultipart(HttpServletRequest)
+     */  
+    @Override  
+    public boolean isMultipart(HttpServletRequest request) {  
+        for (String url: excludeUrlArray) {  
+            // 这里可以自己换判断  
+            if (request.getRequestURI().contains(url)) {  
+                return false;  
+            }  
+        }  
+        return super.isMultipart(request);  
+    }  
+       
+}  
+

+ 182 - 0
src/main/java/net/mingsoft/base/util/BundleUtil.java

@@ -0,0 +1,182 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+package net.mingsoft.base.util;
+
+import net.mingsoft.base.constant.Const;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.i18n.LocaleContextHolder;
+
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * 获取国际化资源工具类
+ */
+public class BundleUtil {
+
+    /*
+     * log4j日志记录
+     */
+    protected static final Logger LOG = LoggerFactory.getLogger(BundleUtil.class);
+
+    /**
+     * 获取本地化文件 推荐使用 BundleUtil.getString 方法
+     * @param key
+     * @param resources 资源文件所在位置
+     * @return
+     */
+    @Deprecated
+    public static String getLocaleString(String key, String resources) {
+        Locale locale = LocaleContextHolder.getLocale();
+        return ResourceBundle.getBundle(resources, locale).getString(key);
+    }
+
+    /**
+     * 读取国际化资源文件 推荐使用 BundleUtil.getString 方法
+     *
+     * @param key
+     *            键值
+     * @return 返回获取到的字符串
+     */
+    @Deprecated
+    public static String getResString(String key) {
+        return getLocaleString(key,Const.RESOURCES);
+    }
+
+    /**
+     * 读取国际化资源文件,优先模块对应的资源文件,如果模块资源文件找不到就会优先基础层 推荐使用 BundleUtil.getString 方法
+     *
+     * @param key
+     *            键值
+     * @param rb
+     *            模块对应资源文件
+     * @return 返回获取到的字符串
+     * 推荐: getString
+     */
+    @Deprecated
+    public static String getResString(String key, ResourceBundle rb) {
+        try {
+            return rb.getString(key);
+        } catch (MissingResourceException var4) {
+            return getLocaleString(key,Const.RESOURCES);
+        }
+    }
+
+    /**
+     * 读取国际化资源文件 推荐使用 BundleUtil.getString 方法
+     *
+     * @param key
+     *            键值
+     * @param fullStrs
+     *            需填充的值
+     * @return 返回获取到的字符串
+     * 推荐使用 getLocalString
+     */
+    @Deprecated
+    public static String getResString(String key, String... fullStrs) {
+        String temp = getResString(key);
+        for(int i = 0; i < fullStrs.length; ++i) {
+            temp = temp.replace("{" + i + "}", fullStrs[i]);
+        }
+
+        return temp;
+    }
+
+
+
+    /**
+     * 读取国际化资源文件,优先模块对应的资源文件,如果模块资源文件找不到就会优先基础层 推荐使用 BundleUtil.getString 方法
+     *
+     * @param key
+     *            键值
+     * @param rb
+     *            模块对应资源文件
+     * @return 返回获取到的字符串
+     * 推荐: getString
+     */
+    @Deprecated
+    public static String getResString(String key, ResourceBundle rb, String... fullStrs) {
+        String temp = "";
+        try {
+            temp = rb.getString(key);
+        } catch (MissingResourceException e) {
+            temp = getResString(key);
+        }
+        for (int i = 0; i < fullStrs.length; i++) {
+            temp = temp.replace("{" + i + "}", fullStrs[i]);
+        }
+        return temp;
+    }
+
+
+    /**
+     * 读取国际化资源文件 推荐使用 BundleUtil.getString 方法
+     *
+     * @param key
+     *            键值
+     * @param fullStrs
+     *            需填充的值
+     * @return 返回获取到的字符串
+     */
+    @Deprecated
+    public static String getLocalString(String key, String... fullStrs) {
+        String temp = getResString(key);
+        for(int i = 0; i < fullStrs.length; ++i) {
+            temp = temp.replace("{" + i + "}", fullStrs[i]);
+        }
+
+        return temp;
+    }
+
+    /**
+     * 读取国际化资源文件,优先模块对应的资源文件,如果模块资源文件找不到就会优先基础层,对应的控制层代码,可以直接使用this.getResString()方法
+     * @param resources 资源文件路径,通常是 每个模块包下*.constant 中Const.RESOURCES
+     * @param key 国际化文件key
+     * @param params 拼接值
+     * @return 国际化字符串
+     */
+    public static String getString(String resources,String key, String... params) {
+        Locale locale = LocaleContextHolder.getLocale();
+        String temp = "";
+        try {
+            temp = ResourceBundle.getBundle(resources, locale).getString(key);
+        } catch (MissingResourceException e) {
+            LOG.debug("不存在资源文件:{}",resources);
+            e.printStackTrace();
+
+        }
+        //替换占位
+        for (int i = 0; i < params.length; i++) {
+            temp = temp.replace("{" + i + "}", params[i]);
+        }
+        return temp;
+    }
+
+    /**
+     * 读取base包国际化文件,因为base包有通用的基本提示,也经常用到,具体看 net.mingsoft.base.resources.resources
+     * @param key 国际化文件key
+     * @param params 拼接值
+     * @return 国际化字符串
+     */
+    public static String getBaseString(String key, String... params) {
+        Locale locale = LocaleContextHolder.getLocale();
+        String temp = "";
+        temp = ResourceBundle.getBundle(Const.RESOURCES, locale).getString(key);
+
+        //替换占位
+        for (int i = 0; i < params.length; i++) {
+            temp = temp.replace("{" + i + "}", params[i]);
+        }
+        return temp;
+    }
+}

+ 53 - 0
src/main/java/net/mingsoft/base/util/FtlUtil.java

@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+package net.mingsoft.base.util;
+
+import freemarker.cache.StringTemplateLoader;
+import freemarker.core.TemplateClassResolver;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Map;
+
+public class FtlUtil {
+    /**
+     * 根据文本内容渲染模板
+     *
+     * @param root    参数值
+     * @param content 模板内容
+     * @return 渲染后的内容,如果解析有问题直接返回原始内容
+     */
+    public static String rendering(Map root, String content) {
+        Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
+        StringTemplateLoader stringLoader = new StringTemplateLoader();
+        stringLoader.putTemplate("template", content);
+        cfg.setNewBuiltinClassResolver(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER);
+        cfg.setNumberFormat("#");
+        cfg.setTemplateLoader(stringLoader);
+
+        Template template = null;
+        try {
+            template = cfg.getTemplate("template", "utf-8");
+            StringWriter writer = new StringWriter();
+            template.process(root, writer);
+            return writer.toString();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (TemplateException e) {
+            e.printStackTrace();
+        }
+        return content;
+    }
+}

+ 94 - 0
src/main/java/net/mingsoft/base/util/PropertiesUtil.java

@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+package net.mingsoft.base.util;
+
+import java.io.*;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * 读取Properties综合类,默认绑定到classpath下的config.properties文件。
+ */
+public class PropertiesUtil {
+
+	/**
+	 * 读取资源文件键值
+	 * @param properties  属性文件包路径 如:net/mingsoft/resources/a.properties
+	 * @param key 键
+	 * @return
+	 * @throws IOException
+	 */
+	public static String get(String properties, String key) throws IOException {
+		InputStream in = PropertiesUtil.class.getClassLoader().getResourceAsStream(properties);
+		Properties props = new Properties();
+		props.load(in);
+		String value = props.getProperty(key);
+		// 关闭资源
+		in.close();
+		return value;
+	}
+
+	/**
+	 * 读取资源文件所有信息
+	 * @param properties  属性文件包路径 如:net/mingsoft/resources/a.properties
+	 * @return
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 */
+	public static Map<String, String> getMap(String properties) throws FileNotFoundException, IOException {
+		// 保存所有的键值
+		Map<String, String> map = new HashMap<String, String>();
+		InputStream in = PropertiesUtil.class.getClassLoader().getResourceAsStream(properties);
+		Properties props = new Properties();
+		props.load(in);
+		Enumeration en = props.propertyNames();
+		while (en.hasMoreElements()) {
+			String key = (String) en.nextElement();
+			String Property = props.getProperty(key);
+			map.put(key, Property);
+		}
+		in.close();
+		return map;
+	}
+
+	/**
+	 * 设置属性值
+	 * 
+	 * @param properties
+	 *            属性文件包路径 如:net/mingsoft/resources/a.properties
+	 * @param key
+	 *            键
+	 * @param value
+	 *            值
+	 * @throws IOException
+	 */
+	public void setValue(String properties, String key, String value) throws IOException {
+		Properties prop = new Properties();
+		InputStream fis = new FileInputStream(PropertiesUtil.class.getClassLoader().getResource(properties).getPath());
+		// 从输入流中读取属性列表(键和元素对)
+		prop.load(fis);
+		// 调用 Hashtable 的方法 put。使用 getProperty 方法提供并行性。
+		// 强制要求为属性的键和值使用字符串。返回值是 Hashtable 调用 put 的结果。
+		OutputStream fos = new FileOutputStream(
+				PropertiesUtil.class.getClassLoader().getResource(properties).getPath());
+		prop.setProperty(key, value);
+		// 以适合使用 load 方法加载到 Properties 表中的格式,
+		// 将此 Properties 表中的属性列表(键和元素对)写入输出流
+		prop.store(fos, "last update");
+		// 关闭文件
+		fis.close();
+		fos.close();
+	}
+
+}

+ 122 - 0
src/main/java/net/mingsoft/base/util/SqlInjectionUtil.java

@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+package net.mingsoft.base.util;
+
+import net.mingsoft.base.exception.BusinessException;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * SQL注入工具类
+ *
+ * @author Administrator
+ * @version 创建日期:2021/4/7 8:43<br/>
+ * 历史修订:<br/>
+ */
+public class SqlInjectionUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SqlInjectionUtil.class);
+
+
+    private static final String REG = "\\b(and|exec|insert|select|drop|grant|alter|delete|update|count|chr|mid|master|truncate|char|declare|or|updatexml|extractvalue|floor|exp|linestring|multpolygon|multlinestring|multipoint|polygon|GeometryCollection|name_const|current_user|if|exists)\\b|(\\*|;|\\+|'|%)\n";
+
+
+    /**
+     * 表示忽略大小写
+     */
+    private static final Pattern sqlPattern = Pattern.compile(REG, Pattern.CASE_INSENSITIVE);
+
+    /**
+     * sql注入过滤处理,遇到注入关键字抛异常
+     *
+     * @param values
+     * @return
+     */
+    public static void filterContent(String... values) {
+        for (String value : values) {
+            if (value == null || "".equals(value)) {
+                continue;
+            }
+            if (!SqlInjectionUtil.isSqlValid(value)) {
+
+                LOG.debug("logo error请注意,值可能存在SQL注入风险: {}", value);
+                throw new BusinessException("请求地址:"+ getRequestUrl() +" \n 当前操作存在sql注入风险,bad sql word:"+ value);
+            }
+        }
+        return;
+    }
+
+
+    /**
+     * 过滤map的sql注入过滤处理,遇到注入关键字抛异常
+     * @param fields
+     */
+    public static void filterContent(Map<String,String> fields) {
+        Iterator iterator = fields.keySet().iterator();
+        while (iterator.hasNext()) {
+            String key = iterator.next().toString();
+            String value = fields.get(key);
+            LOG.debug("key:{} value:{}", key,value);
+            SqlInjectionUtil.filterContent(key);
+            SqlInjectionUtil.filterContent(value);
+        }
+    }
+
+
+    /**
+     * sql注入验证
+     * @param str 需要验证的内容
+     * @return false是否非法的,true通过
+     */
+    public static boolean isSqlValid(String str) {
+        Matcher matcher = sqlPattern.matcher(str);
+        if (matcher.find()) {
+            // TODO: 2023/1/4 有可能matcher.group() 没有匹配到内容
+            if(StringUtils.isNotBlank(matcher.group())) {
+                //获取非法字符:or
+                LOG.info("参数存在非法字符,请确认:"+matcher.group());
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 获取当前请求地址,包括参数会才有?a=1&b=1方式组装成一条新的完整地址
+     * @return 一条完整的get请求地址
+     */
+    public static String getRequestUrl() {
+        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+        StringBuffer requestURL = request.getRequestURL();
+        // 循环调用
+//        Map<String, String[]> map = request.getParameterMap();
+        return requestURL.toString();
+    }
+}

+ 258 - 0
src/main/java/net/mingsoft/basic/action/AppAction.java

@@ -0,0 +1,258 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action;
+
+import cn.hutool.core.util.ObjectUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.annotation.LogAnn;
+import net.mingsoft.basic.biz.IAppBiz;
+import net.mingsoft.basic.constant.e.BusinessTypeEnum;
+import net.mingsoft.basic.constant.e.CookieConstEnum;
+import net.mingsoft.basic.entity.AppEntity;
+import net.mingsoft.basic.entity.ManagerEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.basic.util.MapCacheUtil;
+import net.mingsoft.basic.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 网站基本信息控制层
+ *
+ * @author 铭飞开发团队
+ * @version 版本号:100-000-000<br/>
+ *          创建日期:2014-07-14<br/>
+ *          历史修订:<br/>
+ */
+@Api(tags={"后端-基础接口"})
+@Controller
+@RequestMapping("/${ms.manager.path}/basic/app")
+public class AppAction extends BaseAction {
+
+	/**
+	 * appBiz业务层的注入
+	 */
+	@Autowired
+	private IAppBiz appBiz;
+
+	/**
+	 * 跳转到修改页面
+	 *
+	 * @param mode
+	 *            ModelMap实体对象
+	 * @param appId
+	 *            站点id
+	 * @param request
+	 *            请求对象
+	 * @return 站点修改页面
+	 */
+	@GetMapping(value = "/app")
+	@RequiresPermissions("basic:app:view")
+	public String app(HttpServletRequest request) {
+		return "/basic/app/app";
+
+	}
+
+    /**
+     * 获取站点信息
+     * @param appId
+     * @return
+     */
+    @ApiOperation(value = "获取站点信息")
+    @ApiImplicitParam(name = "appId", value = "站点ID", required = true,paramType="path")
+    @GetMapping(value = "/get")
+    @ResponseBody
+    public ResultData get() {
+			// appId为空,表示查询当前站
+		String appId = BasicUtil.getString("appId", "");
+		AppEntity app = null;
+        //若有appid直接根据appId查询
+        if (StringUtils.isBlank(appId)) {
+            app = BasicUtil.getApp();
+            if(app!=null) {
+                //防止session再次压入appId
+                if(BasicUtil.getSession("appId")==null){
+                    BasicUtil.setSession("appId",app.getAppId());
+                }
+            } else {
+                appId = (String) BasicUtil.getSession("appId");
+                app =  appBiz.getById(appId);
+            }
+        } else {
+            app =  appBiz.getById(appId);
+        }
+		return ResultData.build().success(app);
+
+    }
+
+	/**
+	 * 更新站点信息
+	 *
+	 * @param mode
+	 *            ModelMap实体对象
+	 * @param app
+	 *            站点对象
+	 * @param request
+	 *            请求对象
+	 * @param response
+	 *            相应对象
+	 */
+	@ApiOperation(value ="更新站点信息")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "appName", value = "应用名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "appDescription", value = "应用描述", required = false,paramType="query"),
+		@ApiImplicitParam(name = "appLogo", value = "应用logo", required = false,paramType="query"),
+		@ApiImplicitParam(name = "appDatetime", value = "站点日期", required = false,paramType="query"),
+		@ApiImplicitParam(name = "appKeyword", value = "网站关键字", required = false,paramType="query"),
+		@ApiImplicitParam(name = "appCopyright", value = "网站版权信息", required = false,paramType="query"),
+		@ApiImplicitParam(name = "appStyle", value = "网站采用的模板风格", required = false,paramType="query"),
+		@ApiImplicitParam(name = "appUrl", value = "网站域名", required = false,paramType="query"),
+		@ApiImplicitParam(name = "appManagerId", value = "管理站点的管理员id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "appPayDate", value = "应用续费时间", required = false,paramType="query"),
+		@ApiImplicitParam(name = "appPay", value = "应用费用清单", required = false,paramType="query"),
+	})
+	@PostMapping("/update")
+	@LogAnn(title = "更新站点信息",businessType = BusinessTypeEnum.UPDATE)
+	@RequiresPermissions("basic:app:update")
+	@ResponseBody
+	public ResultData update(@ModelAttribute @ApiIgnore AppEntity app,ModelMap mode, HttpServletRequest request,
+							 HttpServletResponse response) {
+		mode.clear();
+		// 获取Session值
+		ManagerEntity managerSession = BasicUtil.getManager();
+		if (managerSession == null) {
+			return ResultData.build().error();
+		}
+		mode.addAttribute("managerSession", managerSession);
+
+		//验证重复
+		if(super.validated("app", "app_dir", app.getAppDir(), app.getId(), "id")){
+			return ResultData.build().error(getResString("err.exist", this.getResString("app.dir")));
+		}
+		if(StringUtils.isBlank(app.getAppDir())){
+			return ResultData.build().error(getResString("err.empty", this.getResString("app.dir")));
+		}
+		if(!StringUtil.checkLength(app.getAppDir()+"", 0, 50)){
+			return ResultData.build().error(getResString("err.length", this.getResString("app.dir"), "0", "10"));
+		}
+		// 判断站点数据的合法性
+		// 获取cookie
+		String cookie = BasicUtil.getCookie(CookieConstEnum.PAGENO_COOKIE);
+		int pageNo = 1;
+		// 判断cookies是否为空
+		if (StringUtils.isNotBlank(cookie) && Integer.valueOf(cookie) > 0) {
+			pageNo = Integer.valueOf(cookie);
+		}
+		mode.addAttribute("pageNo", pageNo);
+		ResultData resultData = ResultData.build();
+		if (!checkForm(app, resultData)) {
+			return resultData;
+		}
+		if (StringUtils.isNotBlank(app.getAppLogo())) {
+			app.setAppLogo(app.getAppLogo().replace("|", ""));
+		}
+		app.setAppUrl(BasicUtil.getUrl());
+		MapCacheUtil.remove(BasicUtil.getDomain());
+		appBiz.updateById(app);
+		appBiz.updateCache();
+		return ResultData.build().success();
+	}
+
+	@ApiOperation(value = "刷新站点缓存")
+	@PostMapping("/refreshCache")
+	@ResponseBody
+	public ResultData refreshCache(HttpServletRequest request) {
+		MapCacheUtil.remove(BasicUtil.getDomain());
+		appBiz.updateCache();
+		return ResultData.build().success();
+	}
+
+	/**
+	 * 判断站点域名的合法性
+	 *
+	 * @param app
+	 *            要验证的站点信息
+	 * @param resultData
+	 *            resultData对象
+	 */
+	private boolean checkForm(AppEntity app, ResultData resultData) {
+
+		/*
+		 * 判断数据的合法性
+		 */
+		if (StringUtils.isNotBlank(app.getAppKeyword()) && !StringUtil.checkLength(app.getAppKeyword(), 0, 1000)) {
+			resultData.error(getResString("err.length", this.getResString("appKeyword"), "0", "1000"));
+			return false;
+		}
+		if (StringUtils.isNotBlank(app.getAppCopyright()) && !StringUtil.checkLength(app.getAppCopyright(), 0, 1000)) {
+			resultData.error(getResString("err.length", this.getResString("appCopyright"), "0", "1000"));
+			return false;
+		}
+		if (StringUtils.isNotBlank(app.getAppDescription()) && !StringUtil.checkLength(app.getAppDescription(), 0, 1000)) {
+			resultData.error(getResString("err.length", this.getResString("appDescrip"), "0", "1000"));
+			return false;
+		}
+		if (!StringUtil.checkLength(app.getAppName(), 1, 50)) {
+			resultData.error(getResString("err.length", this.getResString("appTitle"), "1", "50"));
+			return false;
+		}
+		if (StringUtils.isNotBlank(app.getAppStyle()) && !StringUtil.checkLength(app.getAppStyle(), 1, 30)) {
+			resultData.error(getResString("err.length", this.getResString("appStyle"), "1", "30"));
+			return false;
+		}
+		if(ObjectUtil.isNotNull(app.getAppHostUrl())){
+			if (!StringUtil.checkLength(app.getAppHostUrl(), 10, 150)) {
+				resultData.error(getResString("err.length", this.getResString("appUrl"), "10", "150"));
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * 判断是否有重复的域名
+	 *
+	 * @param request
+	 *            请求对象
+	 * @return true:重复,false:不重复
+	 */
+	@ApiOperation(value = "判断是否有重复的域名")
+	@GetMapping("/checkUrl")
+	@ResponseBody
+	public ResultData checkUrl(HttpServletRequest request) {
+		if (request.getParameter("appUrl") != null) {
+			if (appBiz.countByUrl(request.getParameter("appUrl")) > 0) {
+				return ResultData.build().success();
+			} else {
+				return ResultData.build().error();
+			}
+		} else {
+			return ResultData.build().error();
+		}
+
+	}
+}

+ 218 - 0
src/main/java/net/mingsoft/basic/action/BaseAction.java

@@ -0,0 +1,218 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.crypto.SecureUtil;
+import io.swagger.annotations.Api;
+import net.mingsoft.base.util.SqlInjectionUtil;
+import net.mingsoft.basic.biz.IAppBiz;
+import net.mingsoft.basic.constant.Const;
+import net.mingsoft.basic.constant.e.CookieConstEnum;
+import net.mingsoft.basic.constant.e.SessionConstEnum;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.config.MSProperties;
+import org.apache.commons.collections.map.CaseInsensitiveMap;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.MissingResourceException;
+
+/**
+ * 基础应用层的父类base
+ *
+ * @author 铭飞开发团队
+ * @version 版本号:100-000-000<br/>
+ *          创建日期:2015-7-19<br/>
+ *          历史修订:<br/>
+ */
+@Api("基础应用层的父类base")
+public abstract class BaseAction extends net.mingsoft.base.action.BaseAction {
+	/**
+	 * appBiz业务层的注入
+	 */
+	@Autowired
+	private IAppBiz appBiz;
+
+//	@Value("${ms.manager.check-code:true}")
+//	private Boolean checkCode;
+
+
+	@Override
+	protected String getResString(String key) {
+		// TODO Auto-generated method stub
+		String str = "";
+		try {
+			str = super.getResString(key);
+		} catch (MissingResourceException e) {
+			str = getLocaleString(key, Const.RESOURCES);
+		}
+		return str;
+	}
+
+
+	/**
+	 * 验证验证码
+	 *
+	 * @return 如果相同,返回true,否则返回false
+	 */
+	protected boolean checkRandCode() {
+		return checkRandCode( SessionConstEnum.CODE_SESSION.toString());
+	}
+
+	/**
+	 * AES解密字符串,key值为当前应用编号
+	 *
+	 * @param request HttpServletRequest对象
+	 * @param str     需要解密的字符串
+	 * @return 返回解密后的字符串
+	 */
+	protected String decryptByAES(HttpServletRequest request, String str) {
+		// 这里存在一个糊涂工具的bug必须先用变量保存变量再返回
+		String _str = SecureUtil.aes(SecureUtil.md5(BasicUtil.getApp().getAppId() + "").substring(16).getBytes())
+				.decryptStr(str);
+		return _str;
+	}
+
+	/**
+	 * AES加密字符串,key值为当前应用编号
+	 *
+	 * @param request HttpServletRequest对象
+	 * @param str     需要加密的字符串
+	 * @return 返回加密后的字符串
+	 */
+	protected String encryptByAES(HttpServletRequest request, String str) {
+		// 这里存在一个糊涂工具的bug必须先用变量保存变量再返回
+		String _str = SecureUtil.aes(SecureUtil.md5(BasicUtil.getApp().getAppId() + "").substring(16).getBytes())
+				.encryptHex(str);
+		return _str;
+	}
+
+	/**
+	 * 获取验证码
+	 *
+	 * @return 返回验证码,获取不到返回null
+	 */
+	protected String getRandCode() {
+		return BasicUtil.getSession(SessionConstEnum.CODE_SESSION) + "";
+	}
+
+	/**
+	 * 返回重定向
+	 *
+	 * @param flag    true:提供给springMVC返回,false:只是获取地址
+	 * @return 返回重定向后的地址
+	 */
+	protected String redirectBack( boolean flag) {
+		if (flag) {
+			return "redirect:" + BasicUtil.getCookie(CookieConstEnum.BACK_COOKIE);
+		} else {
+			return BasicUtil.getCookie(CookieConstEnum.BACK_COOKIE);
+		}
+
+	}
+
+	/**
+	 * 验证验证码
+	 *
+	 * @param param   表单验证码参数名称
+	 * @return 如果相同,返回true,否则返回false
+	 */
+	protected boolean checkRandCode( String param) {
+		boolean checkCode = MSProperties.manager.checkCode;
+		if(!checkCode){
+			return true;
+		}
+		String sessionCode = this.getRandCode();
+		String requestCode = BasicUtil.getString(param);
+		LOG.debug("session_code:" + sessionCode + " requestCode:" + requestCode);
+
+		// 不请求code 验证码默认"null" 也可以一直登录
+		if ("null".equals(sessionCode)){
+			return false;
+		}
+		if (sessionCode.equalsIgnoreCase(requestCode)) {
+			// 验证码正确 删除session中的验证码  删除后为"null"
+			BasicUtil.removeSession(SessionConstEnum.CODE_SESSION);
+			return true;
+		}
+		return false;
+	}
+
+
+	/**
+	 * 移除url参数
+	 *
+	 * @param request
+	 * @param fitlers 需要移除的字段名称
+	 */
+	@Deprecated
+	protected void removeUrlParams(HttpServletRequest request, String[] fitlers) {
+		request.setAttribute(Const.PARAMS, BasicUtil.assemblyRequestUrlParams(fitlers));
+	}
+
+	/**
+	 * 适用于insert save数据时进行唯一性判断
+	 * 判断指定字段在数据库是否已经存在
+	 * @param tableName 表名
+	 * @param fieldName 字段名
+	 * @param fieldValue 字段值
+	 * @return
+	 */
+	protected boolean validated(String tableName,String fieldName, String fieldValue) {
+		SqlInjectionUtil.filterContent(tableName,fieldName,fieldValue);
+		Map where = new HashMap<>(1);
+		where.put(fieldName, fieldValue);
+		List list = appBiz.queryBySQL(tableName, null, where);
+		if (ObjectUtil.isNotNull(list) && !list.isEmpty()) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * 适用于update 更新 数据时进行唯一性判断
+	 * 判断指定字段在数据库是否已经存在
+	 * 主键id用来防止跟自身字段验证重复
+	 * @param tableName 表名
+	 * @param fieldName 字段名
+	 * @param fieldValue 字段值
+	 * @param id 要更新的主键id
+	 * @param idName 要更新的主键名称
+	 * @return
+	 */
+	protected boolean validated(String tableName, String fieldName, String fieldValue, String id,String idName) {
+		SqlInjectionUtil.filterContent(tableName,fieldName,fieldValue);
+		Map where = new HashMap<>(1);
+		where.put(fieldName, fieldValue);
+		List<CaseInsensitiveMap> list = appBiz.queryBySQL(tableName, null, where);
+		if (ObjectUtil.isNotNull(list) && !list.isEmpty()) {
+			//更新时判断是否是本身
+			if(list.size() == 1){
+				CaseInsensitiveMap _map = new CaseInsensitiveMap(list.get(0));
+				if(id.equals(_map.get(idName).toString())){
+					return false;
+				}
+			}
+			return true;
+		}
+		return false;
+	}
+
+
+}

+ 161 - 0
src/main/java/net/mingsoft/basic/action/BaseFileAction.java

@@ -0,0 +1,161 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+package net.mingsoft.basic.action;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.file.FileNameUtil;
+import net.mingsoft.base.constant.Const;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.bean.UploadConfigBean;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.config.MSProperties;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author by Administrator
+ * @Description TODO
+ * @date 2019/9/29 13:46
+ */
+public abstract class BaseFileAction extends BaseAction {
+
+    /**
+     * 统一上传文件方法
+     *
+     * @param config
+     * @return
+     * @throws IOException
+     */
+    public ResultData upload(UploadConfigBean config) throws IOException {
+        String uploadMapping = MSProperties.upload.mapping;
+        String uploadFileDenied = MSProperties.upload.denied;
+        String uploadFolderPath = MSProperties.upload.path;
+        // 过滤掉的文件类型
+        String[] errorType = uploadFileDenied.split(",");
+        //文件上传类型限制
+        String fileName = config.getFile().getOriginalFilename();
+        if (StringUtils.isBlank(fileName)) {
+            return ResultData.build().error("文件名不能为空!");
+        }
+        //清理无效的类型
+        fileName = FileNameUtil.cleanInvalid(fileName);
+        if (fileName.lastIndexOf(".") < 0) {
+            LOG.info("文件格式错误:{}", fileName);
+            return ResultData.build().error(getResString("err.error", getResString("file.name")));
+        }
+
+        String fileType = FileUtil.getSuffix(fileName);
+        //修改上传物理路径
+        String realPath = config.isUploadFolderPath() ? BasicUtil.getRealPath("") : BasicUtil.getRealPath(uploadFolderPath);
+        if (StringUtils.isNotBlank(config.getRootPath())) {
+            realPath = config.getRootPath();
+        }
+        //先判断文件类型是否合法
+        for (String type : errorType) {
+            if ((fileType).equalsIgnoreCase(type)) {
+                LOG.info("文件类型被拒绝:{}", fileType);
+                return ResultData.build().error(getResString("err.error", getResString("file.type")));
+            }
+        }
+        //修改文件名
+        if (config.isRename()) {
+            fileName = System.currentTimeMillis() + "." + fileType;
+        }
+
+        // 上传的文件路径,判断是否填的绝对路径
+        String uploadFolder = realPath + File.separator;
+        //修改upload下的上传路径
+        if (StringUtils.isNotBlank(config.getUploadPath())) {
+            uploadFolder += config.getUploadPath() + File.separator;
+        }
+        //保存文件
+        File saveFolder = new File(uploadFolder);
+        File saveFile = new File(uploadFolder, fileName);
+        if (!saveFolder.exists()) {
+            FileUtil.mkdir(saveFolder);
+        }
+        config.getFile().transferTo(saveFile);
+        //绝对映射路径处理
+        //如果uploadFolderPath = true则返回路径中不拼upload的路径
+        String path = (config.isUploadFolderPath() ? "" : uploadMapping.replace("**", ""))
+                //转为相对路径
+                + uploadFolder.replace(realPath, "")
+                //添加文件名
+                + Const.SEPARATOR + fileName;
+        //替换多余
+        return ResultData.build().success(new File(Const.SEPARATOR + path).getPath().replace("\\", "/").replace("//", "/"));
+    }
+
+    public ResultData uploadTemplate(UploadConfigBean config) throws IOException {
+        String uploadTemplatePath = MSProperties.upload.template;
+        String uploadFileDenied = MSProperties.upload.denied;
+        String[] errorType = uploadFileDenied.split(",");
+        //文件上传类型限制
+        //获取文件名字
+        String fileName = config.getFile().getOriginalFilename();
+        if (fileName.lastIndexOf(".") < 0) {
+            LOG.info("文件格式错误:{}", fileName);
+            return ResultData.build().error(getResString("err.error", getResString("file.name")));
+        }
+        //获取文件类型
+        String fileType = FileUtil.getSuffix(fileName);
+        //判断上传路径是否为绝对路径
+        boolean isReal = new File(uploadTemplatePath).isAbsolute();
+        String realPath = null;
+        if (!isReal) {
+            //如果不是就获取当前项目路径
+            realPath = BasicUtil.getRealPath("");
+        } else {
+            //如果是就直接取改绝对路径
+            realPath = uploadTemplatePath;
+        }
+        //修改文件名
+        if (!config.isRename()) {
+            fileName = config.getFile().getOriginalFilename();
+            //Windows 系统下文件名最后会去掉. 这种文件默认拒绝  xxx.jsp. => xxx.jsp
+            if (fileName.endsWith(".") && System.getProperty("os.name").startsWith("Windows")) {
+                LOG.info("文件类型被拒绝:{}", fileName);
+                return ResultData.build().error(getResString("err.error", getResString("file.type")));
+            }
+            fileType = FileUtil.getSuffix(fileName);
+        } else {
+            //取随机名
+            fileName = System.currentTimeMillis() + "." + fileType;
+        }
+        for (String type : errorType) {
+            //校验禁止上传的文件后缀名(忽略大小写)
+            if ((fileType).equalsIgnoreCase(type)) {
+                LOG.info("文件类型被拒绝:{}", fileType);
+                return ResultData.build().error(getResString("err.error", getResString("file.type")));
+            }
+        }
+        // 上传的文件路径,判断是否填的绝对路径
+        String uploadFolder = realPath + File.separator;
+        //修改upload下的上传路径
+        if (StringUtils.isNotBlank(config.getUploadPath())) {
+            uploadFolder += config.getUploadPath() + File.separator;
+        }
+        //保存文件
+        File saveFolder = new File(uploadFolder);
+        File saveFile = new File(uploadFolder, fileName);
+        if (!saveFolder.exists()) {
+            FileUtil.mkdir(saveFolder);
+        }
+        config.getFile().transferTo(saveFile);
+        //绝对映射路径处理
+        String path = uploadFolder.replace(realPath, "")
+                //添加文件名
+                + Const.SEPARATOR + fileName;
+        //替换多余
+        return ResultData.build().success(new File(Const.SEPARATOR + path).getPath().replace("\\", "/").replace("//", "/"));
+    }
+}

+ 468 - 0
src/main/java/net/mingsoft/basic/action/CityAction.java

@@ -0,0 +1,468 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+package net.mingsoft.basic.action;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.Snowflake;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.BaseEntity;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.bean.CityBean;
+import net.mingsoft.basic.bean.EUListBean;
+import net.mingsoft.basic.biz.ICityBiz;
+import net.mingsoft.basic.entity.CityEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 省市县镇村数据管理控制层
+ * @author 铭飞开发团队
+ * @version
+ * 版本号:100<br/>
+ * 创建日期:2017-7-27 14:47:29<br/>
+ * 历史修订:<br/>
+ */
+@Api(tags={"后端-基础接口"})
+@Controller
+@RequestMapping("/${ms.manager.path}/basic/city")
+public class CityAction extends BaseAction{
+
+	/**
+	 * 注入省市县镇村数据业务层
+	 */
+	@Autowired
+	private ICityBiz cityBiz;
+
+	/**
+	 * 返回主界面index
+	 */
+	@ApiIgnore
+	@ApiOperation(value = "返回主界面index")
+	@GetMapping("/index")
+	@RequiresPermissions("city:view")
+	public String index(HttpServletResponse response,HttpServletRequest request){
+		return  "/basic/city/index";
+	}
+
+	/**
+	 * 返回编辑界面city_form
+	 */
+	@ApiOperation(value = "返回编辑界面city_form")
+	@ApiImplicitParam(name = "id", value = "主键编号", required = true,paramType="query")
+	@GetMapping("/form")
+	@RequiresPermissions("city:view")
+	@ApiIgnore
+	public String form(@ModelAttribute @ApiIgnore CityEntity city,HttpServletResponse response,HttpServletRequest request,@ApiIgnore ModelMap model){
+		if(!StringUtils.isEmpty(city.getId())){
+			BaseEntity cityEntity = cityBiz.getEntity(Integer.parseInt(city.getId()));
+			model.addAttribute("cityEntity",cityEntity);
+		}
+		return "/basic/city/form";
+	}
+
+
+
+	@ApiOperation(value = "查询省市县镇村数据列表")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "provinceId", value = "省/直辖市/自治区级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "provinceName", value = "省/直辖市/自治区级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityId", value = "市级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityName", value = "市级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityPy", value = "城市拼音首字母", required = false,paramType="query"),
+		@ApiImplicitParam(name = "countyId", value = "县/区级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "countyName", value = "县/区级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "townId", value = "街道/镇级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "townName", value = "街道/镇级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "villageId", value = "村委会id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "villageName", value = "村委会名称", required = false,paramType="query"),
+	})
+	@RequestMapping(value ="/list",method = {RequestMethod.GET,RequestMethod.POST})
+	@RequiresPermissions("city:view")
+	@ResponseBody
+	public ResultData list(@ModelAttribute @ApiIgnore CityEntity city, HttpServletResponse response, HttpServletRequest request, @ApiIgnore ModelMap model) {
+		BasicUtil.startPage();
+		List<CityEntity> cityList = new ArrayList();
+		if(city.getProvinceId() == null){
+			cityList = cityBiz.queryProvinceAndName(city);
+		}else {
+			cityList = cityBiz.queryById(city);
+		}
+		return ResultData.build().success(new EUListBean(cityList, (int) BasicUtil.endPage(cityList).getTotal()));
+	}
+
+
+	/**
+	 * 获取省市县镇村数据
+	 * @param city 省市县镇村数据实体
+	 * <i>city参数包含字段信息参考:</i><br/>
+	 * id 主键编号<br/>
+	 * provinceId 省/直辖市/自治区级id<br/>
+	 * provinceName 省/直辖市/自治区级名称<br/>
+	 * cityId 市级id <br/>
+	 * cityName 市级名称<br/>
+	 * countyId 县/区级id<br/>
+	 * countyName 县/区级名称<br/>
+	 * townId 街道/镇级id<br/>
+	 * townName 街道/镇级名称<br/>
+	 * villageId 村委会id<br/>
+	 * villageName 村委会名称<br/>
+	 * <dt><span class="strong">返回</span></dt><br/>
+	 * <dd>{ <br/>
+	 * id: 主键编号<br/>
+	 * provinceId: 省/直辖市/自治区级id<br/>
+	 * provinceName: 省/直辖市/自治区级名称<br/>
+	 * cityId: 市级id <br/>
+	 * cityName: 市级名称<br/>
+	 * countyId: 县/区级id<br/>
+	 * countyName: 县/区级名称<br/>
+	 * townId: 街道/镇级id<br/>
+	 * townName: 街道/镇级名称<br/>
+	 * villageId: 村委会id<br/>
+	 * villageName: 村委会名称<br/>
+	 * }</dd><br/>
+	 */
+	@ApiOperation(value = "获取省市县镇村数据")
+	@ApiImplicitParam(name = "id", value = "主键编号", required = true,paramType="query")
+	@GetMapping("/get")
+	@RequiresPermissions("city:view")
+	@ResponseBody
+	public ResultData get(@ModelAttribute @ApiIgnore CityEntity city,HttpServletResponse response, HttpServletRequest request,@ApiIgnore ModelMap model){
+		if(StringUtils.isEmpty(city.getId())) {
+			return ResultData.build().error(getResString("err.error", this.getResString("id")));
+		}
+		CityEntity _city = (CityEntity)cityBiz.getEntity(Integer.parseInt(city.getId()));
+		return ResultData.build().success(_city);
+	}
+
+	/**
+	 * 保存省市县镇村数据实体
+	 * @param city 省市县镇村数据实体
+	 * <i>city参数包含字段信息参考:</i><br/>
+	 * id 主键编号<br/>
+	 * provinceId 省/直辖市/自治区级id<br/>
+	 * provinceName 省/直辖市/自治区级名称<br/>
+	 * cityId 市级id <br/>
+	 * cityName 市级名称<br/>
+	 * countyId 县/区级id<br/>
+	 * countyName 县/区级名称<br/>
+	 * townId 街道/镇级id<br/>
+	 * townName 街道/镇级名称<br/>
+	 * villageId 村委会id<br/>
+	 * villageName 村委会名称<br/>
+	 * <dt><span class="strong">返回</span></dt><br/>
+	 * <dd>{ <br/>
+	 * id: 主键编号<br/>
+	 * provinceId: 省/直辖市/自治区级id<br/>
+	 * provinceName: 省/直辖市/自治区级名称<br/>
+	 * cityId: 市级id <br/>
+	 * cityName: 市级名称<br/>
+	 * countyId: 县/区级id<br/>
+	 * countyName: 县/区级名称<br/>
+	 * townId: 街道/镇级id<br/>
+	 * townName: 街道/镇级名称<br/>
+	 * villageId: 村委会id<br/>
+	 * villageName: 村委会名称<br/>
+	 * }</dd><br/>
+	 */
+	@ApiOperation(value = "保存省市县镇村数据实体")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "provinceId", value = "省/直辖市/自治区级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "provinceName", value = "省/直辖市/自治区级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityId", value = "市级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityName", value = "市级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityPy", value = "城市拼音首字母", required = false,paramType="query"),
+		@ApiImplicitParam(name = "countyId", value = "县/区级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "countyName", value = "县/区级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "townId", value = "街道/镇级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "townName", value = "街道/镇级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "villageId", value = "村委会id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "villageName", value = "村委会名称", required = false,paramType="query"),
+	})
+	@RequiresPermissions("city:save")
+	@PostMapping("/save")
+	@ResponseBody
+	public ResultData save(@ModelAttribute @ApiIgnore CityEntity city, HttpServletResponse response, HttpServletRequest request) {
+		if (StringUtils.isBlank(city.getProvinceName()) && StringUtils.isBlank(city.getCityName()) && StringUtils.isBlank(city.getCountyName()) && StringUtils.isBlank(city.getTownName()) && StringUtils.isBlank(city.getVillageName())){
+			return ResultData.build().error(getResString("err.empty",this.getResString("area")));
+		}
+		// 保存
+		Snowflake snowflake = IdUtil.getSnowflake(0, 0);
+
+		CityEntity _city = new CityEntity();
+		BeanUtils.copyProperties(city,_city);
+		_city.setId(null);
+		_city.setCreateDate(null);
+		_city.setUpdateDate(null);
+		_city.setCreateBy(null);
+		LambdaQueryWrapper<CityEntity> wrapper = new LambdaQueryWrapper<>(_city);
+		List<CityEntity> list = cityBiz.list(wrapper);
+		if (list != null && list.size()>0){
+			return ResultData.build().error(getResString("err.exist",this.getResString("area")));
+		}
+		CityEntity queryEntity = new CityEntity();
+		queryEntity.setProvinceId(city.getProvinceId());
+		queryEntity.setCityId(city.getCityId());
+		queryEntity.setCountyId(city.getCountyId());
+		queryEntity.setTownId(city.getTownId());
+		queryEntity.setVillageId(city.getVillageId());
+		wrapper = new LambdaQueryWrapper<>(queryEntity);
+		List<CityEntity> citys = cityBiz.list(wrapper);
+		CityEntity cityEntity = null;
+		if(CollUtil.isNotEmpty(citys)) {
+			cityEntity = cityBiz.list(wrapper).get(0);
+		}
+		if (city.getProvinceId() != null){
+			//新增市
+			city.setProvinceName(cityEntity.getProvinceName());
+			city.setCityId(snowflake.nextId());
+		}
+		else if (city.getCityId() != null){
+			//新增县
+			city.setProvinceId(cityEntity.getProvinceId());
+			city.setProvinceName(cityEntity.getProvinceName());
+			city.setCityName(cityEntity.getCityName());
+			city.setCountyId(snowflake.nextId());
+		}else if (city.getCountyId() != null){
+			//新增镇
+			city.setProvinceId(cityEntity.getProvinceId());
+			city.setProvinceName(cityEntity.getProvinceName());
+			city.setCityId(cityEntity.getCityId());
+			city.setCityName(cityEntity.getCityName());
+			city.setCountyId(cityEntity.getCountyId());
+			city.setCountyName(cityEntity.getCountyName());
+			city.setTownId(snowflake.nextId());
+		}else if (city.getTownId() != null){
+			//新增村
+			city.setProvinceId(cityEntity.getProvinceId());
+			city.setProvinceName(cityEntity.getProvinceName());
+			city.setCityId(cityEntity.getCityId());
+			city.setCityName(cityEntity.getCityName());
+			city.setCountyId(cityEntity.getCountyId());
+			city.setCountyName(cityEntity.getCountyName());
+			city.setTownId(cityEntity.getTownId());
+			city.setTownName(cityEntity.getTownName());
+			city.setVillageId(snowflake.nextId());
+		}else if (city.getProvinceId() == null){
+			//省
+			city.setProvinceId(snowflake.nextId());
+		}
+		cityBiz.save(city);
+		cityBiz.updateCache();
+			return ResultData.build().success(city);
+	}
+
+	/**
+	 // * @param city 省市县镇村数据实体
+	 * <i>city参数包含字段信息参考:</i><br/>
+	 * id:多个id直接用逗号隔开,例如id=1,2,3,4
+	 * 批量删除省市县镇村数据
+	 *            <dt><span class="strong">返回</span></dt><br/>
+	 *            <dd>{code:"错误编码",<br/>
+	 *            result:"true|false",<br/>
+	 *            resultMsg:"错误信息"<br/>
+	 *            }</dd>
+	 */
+	@ApiOperation(value = "批量删除省市县镇村数据")
+	@RequiresPermissions("city:del")
+	@PostMapping("/delete")
+	@ResponseBody
+	public ResultData delete(@RequestBody List<CityEntity> citys,HttpServletResponse response, HttpServletRequest request) {
+		for (CityEntity city : citys) {
+			cityBiz.deleteEntity(city);
+		}
+		cityBiz.updateCache();
+		return ResultData.build().success();
+	}
+
+	/**
+	 * 更新省市县镇村数据信息省市县镇村数据
+	 * @param city 省市县镇村数据实体
+	 * <i>city参数包含字段信息参考:</i><br/>
+	 * id 主键编号<br/>
+	 * provinceId 省/直辖市/自治区级id<br/>
+	 * provinceName 省/直辖市/自治区级名称<br/>
+	 * cityId 市级id <br/>
+	 * cityName 市级名称<br/>
+	 * countyId 县/区级id<br/>
+	 * countyName 县/区级名称<br/>
+	 * townId 街道/镇级id<br/>
+	 * townName 街道/镇级名称<br/>
+	 * villageId 村委会id<br/>
+	 * villageName 村委会名称<br/>
+	 * <dt><span class="strong">返回</span></dt><br/>
+	 * <dd>{ <br/>
+	 * id: 主键编号<br/>
+	 * provinceId: 省/直辖市/自治区级id<br/>
+	 * provinceName: 省/直辖市/自治区级名称<br/>
+	 * cityId: 市级id <br/>
+	 * cityName: 市级名称<br/>
+	 * countyId: 县/区级id<br/>
+	 * countyName: 县/区级名称<br/>
+	 * townId: 街道/镇级id<br/>
+	 * townName: 街道/镇级名称<br/>
+	 * villageId: 村委会id<br/>
+	 * villageName: 村委会名称<br/>
+	 * }</dd><br/>
+	 */
+	@ApiOperation(value ="更新省市县镇村数据信息省市县镇村数据")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "id", value = "主键编号", required = true,paramType="query"),
+		@ApiImplicitParam(name = "provinceId", value = "省/直辖市/自治区级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "provinceName", value = "省/直辖市/自治区级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityId", value = "市级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityName", value = "市级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityPy", value = "城市拼音首字母", required = false,paramType="query"),
+		@ApiImplicitParam(name = "countyId", value = "县/区级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "countyName", value = "县/区级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "townId", value = "街道/镇级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "townName", value = "街道/镇级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "villageId", value = "村委会id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "villageName", value = "村委会名称", required = false,paramType="query"),
+	})
+	@RequiresPermissions("city:update")
+	@PostMapping("/update")
+	@ResponseBody
+	public ResultData update(@ModelAttribute @ApiIgnore CityEntity city, HttpServletResponse response,
+			HttpServletRequest request) {
+		if (StringUtils.isBlank(city.getProvinceName()) && StringUtils.isBlank(city.getCityName()) && StringUtils.isBlank(city.getCountyName()) && StringUtils.isBlank(city.getTownName()) && StringUtils.isBlank(city.getVillageName())){
+			return ResultData.build().error(getResString("err.empty",this.getResString("area")));
+		}
+		CityEntity _city = new CityEntity();
+		_city.setProvinceName(city.getProvinceName());
+		_city.setCityName(city.getCityName());
+		_city.setCountyName(city.getCountyName());
+		_city.setTownName(city.getTownName());
+		_city.setVillageName(city.getVillageName());
+		LambdaQueryWrapper<CityEntity> wrapper = new LambdaQueryWrapper<>(_city);
+		List<CityEntity> list = cityBiz.list(wrapper);
+		if (list != null && list.size()>1){
+			return ResultData.build().error(getResString("err.exist",this.getResString("area")));
+		}
+		cityBiz.updateEntity(city);
+		cityBiz.updateCache();
+		return ResultData.build().success(city);
+	}
+
+	/**
+	 * 查询省列表
+	 * @param response
+	 * @param request
+	 */
+	@ApiOperation(value = "查询省列表")
+	@GetMapping("/province")
+	@ResponseBody
+	public ResultData province(HttpServletResponse response, HttpServletRequest request) {
+		List cityList = cityBiz.queryProvince();
+		return ResultData.build().success(cityList);
+	}
+
+	/**
+	 * 根据省id查询城市列表
+	 * @param city
+	 * @param response
+	 * @param request
+	 */
+	@ApiOperation(value = "根据省id查询城市列表")
+	@ApiImplicitParam(name = "provinceId", value = "省/直辖市/自治区级id", required = true,paramType="query")
+	@GetMapping("/city")
+	@ResponseBody
+	public ResultData city(@ModelAttribute @ApiIgnore CityEntity city,HttpServletResponse response, HttpServletRequest request) {
+		List cityList = cityBiz.queryCity(city);
+		return ResultData.build().success(cityList);
+	}
+
+	/**
+	 * 根据城市id查询区域列表
+	 * @param city
+	 * @param response
+	 * @param request
+	 */
+	@ApiOperation(value = "根据城市id查询区域列表")
+	@ApiImplicitParam(name = "cityId", value = "市级id", required = true,paramType="query")
+	@GetMapping("/county")
+	@ResponseBody
+	public ResultData county(@ModelAttribute @ApiIgnore CityEntity city,HttpServletResponse response, HttpServletRequest request) {
+		List cityList = cityBiz.queryCounty(city);
+		return ResultData.build().success(cityList);
+	}
+
+	/**
+	 * 根据城市id查询区域列表
+	 * @param city
+	 * @param response
+	 * @param request
+	 */
+	@ApiOperation(value = "根据区县id查询城镇列表")
+	@ApiImplicitParam(name = "countyId", value = "区县Id", required = true,paramType="query")
+	@GetMapping("/town")
+	@ResponseBody
+	public ResultData town(@ModelAttribute @ApiIgnore CityEntity city,HttpServletResponse response, HttpServletRequest request) {
+		BasicUtil.startPage();
+		List cityList = cityBiz.queryTown(city);
+		return ResultData.build().success(cityList);
+	}
+
+	/**
+	 * 根据城市id查询区域列表
+	 * @param city
+	 * @param response
+	 * @param request
+	 */
+	@ApiOperation(value = "根据城镇id查询街道列表")
+	@ApiImplicitParam(name = "townId", value = "城镇Id", required = true,paramType="query")
+	@GetMapping("/village")
+	@ResponseBody
+	public ResultData village(@ModelAttribute @ApiIgnore CityEntity city,HttpServletResponse response, HttpServletRequest request) {
+		List cityList = cityBiz.queryVillage(city);
+		return ResultData.build().success(cityList);
+	}
+
+	/**
+	 * 生成json
+	 * @param response
+	 * @param request
+	 */
+	@ApiOperation(value = "生成json文件")
+	@PostMapping("/createJson")
+	@ResponseBody
+	@RequiresPermissions("city:createJson")
+	public ResultData creatJson(HttpServletResponse response, HttpServletRequest request) {
+		int level = 5;//默认5级
+		String type = "tree"; //默认为树形结构
+		List<CityBean> cityList = (List<CityBean>) cityBiz.queryForTree(level,type);
+		File file = FileUtil.file(BasicUtil.getRealPath(null), "/static/json/city.json");
+		FileUtil.writeBytes(JSONUtil.toJsonStr(ResultData.build().success(cityList)).getBytes(StandardCharsets.UTF_8),file);
+		return ResultData.build().success();
+	}
+
+
+}

+ 164 - 0
src/main/java/net/mingsoft/basic/action/LogAction.java

@@ -0,0 +1,164 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.basic.action;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.bean.EUListBean;
+import net.mingsoft.basic.bean.LogBean;
+import net.mingsoft.basic.biz.ILogBiz;
+import net.mingsoft.basic.constant.e.BusinessTypeEnum;
+import net.mingsoft.basic.entity.LogEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * 系统日志管理控制层
+ * @author 铭飞开发团队
+ * 创建日期:2020-11-21 9:41:34<br/>
+ * 历史修订:<br/>
+ */
+@Api(tags={"后端-基础接口"})
+@Controller("basicLogAction")
+@RequestMapping("/${ms.manager.path}/basic/log")
+public class LogAction extends BaseAction{
+
+
+	/**
+	 * 注入系统日志业务层
+	 */
+	@Autowired
+	private ILogBiz logBiz;
+
+	/**
+	 * 返回主界面index
+	 */
+	@ApiIgnore
+	@GetMapping("/index")
+	@RequiresPermissions("basic:log:view")
+	public String index(HttpServletResponse response,HttpServletRequest request){
+		return "/basic/log/index";
+	}
+
+	/**
+	 * 返回编辑界面log_form
+	 */
+	@ApiIgnore
+	@GetMapping("/form")
+	@RequiresPermissions("basic:log:view")
+	public String form(@ModelAttribute LogEntity log,HttpServletResponse response,HttpServletRequest request,ModelMap model){
+		return "/basic/log/form";
+	}
+
+	/**
+	 * 查询系统日志列表
+	 * @param log 系统日志实体
+	 */
+	@ApiOperation(value = "查询系统日志列表接口")
+	@ApiImplicitParams({
+    	@ApiImplicitParam(name = "logTitle", value = "标题", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logIp", value = "IP", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logMethod", value = "请求方法", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logRequestMethod", value = "请求方式", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logUrl", value = "请求地址", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logStatus", value = "请求状态", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logBusinessType", value = "业务类型", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logUserType", value = "用户类型", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logUser", value = "操作人员", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logLocation", value = "所在地区", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logParam", value = "请求参数", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logResult", value = "返回参数", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "logErrorMsg", value = "错误消息", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "createBy", value = "创建人", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "createDate", value = "创建时间", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "updateBy", value = "修改人", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "updateDate", value = "修改时间", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "del", value = "删除标记", required =false,paramType="query"),
+    	@ApiImplicitParam(name = "id", value = "编号", required =false,paramType="query"),
+    })
+	@RequestMapping(value ="/list",method = {RequestMethod.GET,RequestMethod.POST})
+	@ResponseBody
+	@RequiresPermissions("basic:log:view")
+	public ResultData list(@ModelAttribute @ApiIgnore LogBean log, HttpServletResponse response, HttpServletRequest request, @ApiIgnore ModelMap model, BindingResult result) {
+		BasicUtil.startPage();
+		List<LogEntity> logList = logBiz.query(log);
+		return ResultData.build().success(new EUListBean(logList,(int)BasicUtil.endPage(logList).getTotal()));
+	}
+
+	/**
+	 * 获取系统日志
+	 * @param log 系统日志实体
+	 */
+	@ApiOperation(value = "获取系统日志列表接口")
+    @ApiImplicitParam(name = "id", value = "编号", required =true,paramType="query")
+	@GetMapping("/get")
+	@ResponseBody
+	@RequiresPermissions("basic:log:view")
+	public ResultData get(@ModelAttribute @ApiIgnore LogEntity log,HttpServletResponse response, HttpServletRequest request,@ApiIgnore ModelMap model){
+		if(log.getId()==null) {
+			return ResultData.build().error("ID不能为空!");
+		}
+		LogEntity _log = logBiz.getById(log.getId());
+		return ResultData.build().success(_log);
+	}
+
+	/**
+	 * 获取日志类型枚举类
+	 */
+	@ApiOperation(value = "获取日志类型枚举类")
+	@PostMapping("/queryLogType")
+	@ResponseBody
+	public ResultData queryLogType(HttpServletResponse response, HttpServletRequest request) {
+		List<HashMap<String, String>> list = new ArrayList<>();
+		try {
+			Class _class = Class.forName(BusinessTypeEnum.class.getName());
+			Object[] enumConstants = _class.getEnumConstants();
+			Arrays.stream(enumConstants).forEach(e-> {
+				HashMap<String, String> map = new HashMap<>();
+				map.put("value", e.toString().toLowerCase());
+				try {
+					Method label = e.getClass().getMethod("getLabel");
+					map.put("label", label.invoke(e).toString());
+				} catch (NoSuchMethodException ex) {
+					ex.printStackTrace();
+				} catch (IllegalAccessException ex) {
+					ex.printStackTrace();
+				} catch (InvocationTargetException ex) {
+					ex.printStackTrace();
+				}
+				list.add(map);
+			});
+		} catch (ClassNotFoundException e) {
+			e.printStackTrace();
+		}
+		return ResultData.build().success(list);
+	}
+}

+ 173 - 0
src/main/java/net/mingsoft/basic/action/MainAction.java

@@ -0,0 +1,173 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action;
+
+
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.json.JSONUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.BaseEntity;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.annotation.LogAnn;
+import net.mingsoft.basic.bean.ManagerModifyPwdBean;
+import net.mingsoft.basic.biz.IManagerBiz;
+import net.mingsoft.basic.biz.IModelBiz;
+import net.mingsoft.basic.constant.e.BusinessTypeEnum;
+import net.mingsoft.basic.entity.ManagerEntity;
+import net.mingsoft.basic.entity.ModelEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.basic.util.StringUtil;
+import net.mingsoft.config.MSProperties;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 主界面控制层
+ * @author 铭飞开发团队
+ * @version
+ * 版本号:100-000-000<br/>
+ * 创建日期:2014-7-14<br/>
+ * 历史修订:<br/>
+ */
+@Api(tags={"后端-基础接口"})
+@Controller
+@RequestMapping("/${ms.manager.path}")
+public class MainAction extends BaseAction {
+
+	/**
+	 * 模块业务层
+	 */
+	@Autowired
+	private IModelBiz modelBiz;
+
+	/**
+	 * 管理员业务层
+	 */
+	@Autowired
+	private IManagerBiz managerBiz;
+
+
+
+
+
+	/**
+	 * 加载后台主界面,并查询数据
+	 * @param request 请求对象
+	 * @return  主界面地址
+	 */
+	@ApiOperation(value = "加载后台主界面,并查询数据")
+	@GetMapping(value = {"/index","/"})
+	public String index(HttpServletRequest request) {
+		String managerPath = MSProperties.manager.path;
+		ManagerEntity managerSession =  BasicUtil.getManager();
+		List<ModelEntity> modelList = new ArrayList<ModelEntity>();
+		ModelEntity model = new ModelEntity();
+		modelList = modelBiz.queryModelByRoleId(managerSession.getRoleId());
+		//如果ischild有值,则不显示
+		List<BaseEntity> _modelList = new ArrayList<BaseEntity>();
+		for(int i=0;i<modelList.size();i++){
+			ModelEntity _model = (ModelEntity) modelList.get(i);
+			if(StringUtils.isBlank(_model.getIsChild())){
+				_modelList.add(_model);
+			}
+		}
+		request.setAttribute("managerSession", managerSession);
+		request.setAttribute("modelList", JSONUtil.toJsonStr(modelList));
+		request.setAttribute("client", BasicUtil.getDomain()+"/"+managerPath);
+		request.setAttribute("app", BasicUtil.getApp());
+		return "/index";
+	}
+
+	@ApiIgnore
+	@GetMapping("/main")
+	public String main(HttpServletRequest request) {
+		return "/main";
+	}
+
+
+
+
+	/**
+	 * 修改登录密码,若不填写密码则表示不修改
+	 *
+	 * @param request
+	 *            请求
+	 * @param response
+	 *            响应
+	 */
+	@ApiOperation(value = "修改登录密码,若不填写密码则表示不修改")
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "oldManagerPassword", value = "旧密码", required = true,paramType="query"),
+			@ApiImplicitParam(name = "newManagerPassword", value = "新密码", required = true,paramType="query"),
+	})
+	@LogAnn(title = "修改登录密码",businessType= BusinessTypeEnum.UPDATE)
+	@PostMapping("/updatePassword")
+	@ResponseBody
+	public ResultData updatePassword(@ModelAttribute @ApiIgnore ManagerModifyPwdBean managerModifyPwdBean, HttpServletResponse response, HttpServletRequest request) {
+		//获取新的密码
+		String newManagerPassword = managerModifyPwdBean.getNewManagerPassword();
+		//获取管理员信息
+		ManagerEntity manager = BasicUtil.getManager();
+		// 判断新密码和旧密码是否为空
+		if (StringUtils.isBlank(newManagerPassword) || StringUtils.isBlank(managerModifyPwdBean.getOldManagerPassword())) {
+			return ResultData.build().error(getResString("err.empty", this.getResString("managerPassword")));
+		}
+
+		//判断旧的密码是否正确
+		if(!managerModifyPwdBean.getOldManagerPassword().equals(manager.getManagerPassword())){
+			return ResultData.build().error(this.getResString("manager.password.old.err"));
+		}
+		// 判断新密码长度
+		if (!StringUtil.checkLength(newManagerPassword, 6, 30)) {
+			return ResultData.build().error(getResString("err.length", this.getResString("managerPassword"), "6", "30"));
+		}
+		//更改密码
+		manager.setManagerPassword(SecureUtil.md5(newManagerPassword));
+		//更新
+		managerBiz.updateUserPasswordByUserName(manager);
+		Subject subject = SecurityUtils.getSubject();
+		subject.logout();
+		return ResultData.build().success();
+	}
+
+	/**
+	 * 退出系统
+	 * @param request 请求对象
+	 * @return true退出成功
+	 */
+	@ApiOperation(value = "退出系统")
+	@GetMapping("/loginOut")
+	@ResponseBody
+	public ResultData loginOut(HttpServletRequest request) {
+		Subject subject = SecurityUtils.getSubject();
+		subject.logout();
+		return ResultData.build().success();
+	}
+
+
+}

+ 180 - 0
src/main/java/net/mingsoft/basic/action/ManageFileAction.java

@@ -0,0 +1,180 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action;
+
+import cn.hutool.core.io.FileTypeUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.ZipUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.annotation.LogAnn;
+import net.mingsoft.basic.bean.UploadConfigBean;
+import net.mingsoft.basic.constant.e.BusinessTypeEnum;
+import net.mingsoft.basic.exception.BusinessException;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.config.MSProperties;
+import org.apache.commons.compress.utils.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * 上传文件
+ */
+@Api(tags={"后端-基础接口"})
+@Controller("ManageFileAction")
+@RequestMapping("${ms.manager.path}/file")
+public class ManageFileAction extends BaseFileAction {
+
+
+
+	/**
+	 * 处理post请求上传文件
+	 * 可以自定义项目路径下任意文件夹
+	 * @param req
+	 *            HttpServletRequest对象
+	 * @param res
+	 *            HttpServletResponse 对象
+	 * @throws ServletException
+	 *             异常处理
+	 * @throws IOException
+	 *             异常处理
+	 */
+	@ApiOperation(value = "处理post请求上传文件")
+	@LogAnn(title = "处理post请求上传文件",businessType= BusinessTypeEnum.OTHER)
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "uploadPath", value = "上传文件夹地址", required =false,paramType="form"),
+			@ApiImplicitParam(name = "file", value = "文件流", dataType="__file",required =false,paramType="form"),
+			@ApiImplicitParam(name = "rename", value = "是否重命名", required =false,paramType="form",defaultValue="true"),
+			@ApiImplicitParam(name = "appId", value = "上传路径是否需要拼接appId", required =false,paramType="form",defaultValue="false"),
+			@ApiImplicitParam(name = "uploadFolderPath", value = "是否修改上传目录", required =false,paramType="form",defaultValue="false"),
+	})
+	@PostMapping(value = "/upload",consumes = "multipart/*",headers = "content-type=multipart/form-data")
+	@ResponseBody
+	public ResultData upload(@ApiIgnore UploadConfigBean bean, @ApiIgnore boolean uploadFolderPath, HttpServletRequest req, HttpServletResponse res) throws IOException {
+		//非法路径过滤
+		if(checkUploadPath(bean)){
+			return ResultData.build().error();
+		}
+		// 是否需要拼接appId
+		if (bean.isAppId()) {
+			bean.setUploadPath(BasicUtil.getApp().getAppId() + File.separator + bean.getUploadPath());
+		}
+
+		UploadConfigBean config = new UploadConfigBean(bean.getUploadPath(),bean.getFile(),null,uploadFolderPath,bean.isRename());
+		return this.upload(config);
+	}
+
+	@ApiOperation(value = "处理post请求上传模板文件")
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "uploadPath", value = "上传文件夹地址", required =false,paramType="form"),
+			@ApiImplicitParam(name = "file", value = "文件流", dataType="__file",required =false,paramType="form"),
+			@ApiImplicitParam(name = "rename", value = "是否重命名", required =false,paramType="form",defaultValue="true"),
+			@ApiImplicitParam(name = "appId", value = "上传路径是否需要拼接appId", required =false,paramType="form",defaultValue="false"),
+			@ApiImplicitParam(name = "uploadFolderPath", value = "是否修改上传目录", required =false,paramType="form",defaultValue="false"),
+	})
+	@PostMapping("/uploadTemplate")
+	@ResponseBody
+	public ResultData uploadTemplate(@ApiIgnore UploadConfigBean bean, @ApiIgnore boolean uploadFolderPath, HttpServletResponse res) throws IOException {
+		String uploadTemplatePath = MSProperties.upload.template;
+		//非法路径过滤
+		if(checkUploadPath(bean)){
+			return ResultData.build().error(getResString("err.error", new String[]{getResString("file.path")}));
+		}
+		if (StringUtils.isEmpty(bean.getUploadPath())) {
+			bean.setUploadPath(uploadTemplatePath + File.separator +  BasicUtil.getApp().getAppId());
+		} else if(!bean.getUploadPath().substring(0,uploadTemplatePath.length()).equalsIgnoreCase(uploadTemplatePath)){
+			throw new BusinessException("uploadPath参数错误");
+		}
+
+		UploadConfigBean config = new UploadConfigBean(bean.getUploadPath(), bean.getFile(),null, uploadFolderPath, bean.isRename());
+		ResultData resultData = this.uploadTemplate(config);
+		if (!resultData.isSuccess()){
+			// 上传失败
+			return ResultData.build().error(resultData.getMsg());
+		}
+		String templateUrl = uploadTemplatePath + File.separator +  BasicUtil.getApp().getAppId();
+		// 上传模板zip才解压
+		if (!templateUrl.equals(bean.getUploadPath())){
+			return ResultData.build().success();
+		}
+		// TODO: 2023/7/11  开始解压
+		String fileUrl = (String) resultData.get(ResultData.DATA_KEY);
+		//校验路径
+		if (fileUrl != null && (fileUrl.contains("../") || fileUrl.contains("..\\"))) {
+			return ResultData.build().error();
+		}
+		File zipFile = new File(BasicUtil.getRealTemplatePath(fileUrl));
+		ZipUtil.unzip(zipFile.getPath(),zipFile.getParent(), Charset.forName("gbk"));
+		FileUtil.del(zipFile);
+
+		//删除分享模板下zip下的index.html文件\html\___data文件夹
+		String htmlPath = zipFile.getParent()+"/html";
+		if(FileUtil.exist(htmlPath)) {
+			FileUtil.del(htmlPath);
+		}
+
+		String dataPath = zipFile.getParent()+"/data";
+		if(FileUtil.exist(dataPath)) {
+			FileUtil.del(dataPath);
+		}
+
+		//获取文件夹下所有文件
+		List<File> files = FileUtil.loopFiles(zipFile.getParent());
+
+		//禁止上传的格式
+		List<String> deniedList = Arrays.stream(MSProperties.upload.denied.split(",")).map(String::toLowerCase).collect(Collectors.toList());
+		for (File file : files) {
+			FileInputStream fileInputStream = new FileInputStream(file);
+			//文件的真实类型
+			String fileType = FileTypeUtil.getType(file).toLowerCase();
+			//通过yml的配置检查文件格式是否合法
+			if (deniedList.contains(fileType)){
+				IOUtils.closeQuietly(fileInputStream);
+				// 如果同目录或其他模板下存在不合法的文件类型,会清除站点下所有文件
+				FileUtil.del(zipFile.getParent());
+				throw new RuntimeException(StrUtil.format("压缩包内文件{}的类型{}禁止上传",file.getName(),fileType));
+			}
+			IOUtils.closeQuietly(fileInputStream);
+		}
+
+		return ResultData.build().success();
+	}
+
+	protected boolean checkUploadPath(UploadConfigBean bean){
+		return (bean.getUploadPath()!=null&&(bean.getUploadPath().contains("../")||bean.getUploadPath().contains("..\\")));
+	}
+
+
+
+}

+ 316 - 0
src/main/java/net/mingsoft/basic/action/ManagerAction.java

@@ -0,0 +1,316 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.crypto.SecureUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.annotation.LogAnn;
+import net.mingsoft.basic.bean.EUListBean;
+import net.mingsoft.basic.biz.IManagerBiz;
+import net.mingsoft.basic.constant.e.BusinessTypeEnum;
+import net.mingsoft.basic.constant.e.ManagerAdminEnum;
+import net.mingsoft.basic.entity.AppEntity;
+import net.mingsoft.basic.entity.ManagerEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.basic.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 管理员管理控制层
+ * @author 铭飞开发团队
+ * @version
+ * 版本号:1.0<br/>
+ * 创建日期:2017-8-24 23:40:55<br/>
+ * 历史修订: 2022-1-27 12:00 list(), query() 添加站群插件查询管理员的容错 <br/>
+ */
+@Api(tags={"后端-基础接口"})
+@Controller
+@RequestMapping("/${ms.manager.path}/basic/manager")
+public class ManagerAction extends BaseAction{
+
+	/**
+	 * 注入管理员业务层
+	 */
+	@Autowired
+	private IManagerBiz managerBiz;
+
+	/**
+	 * 返回主界面index
+	 */
+	@ApiIgnore
+	@GetMapping("/index")
+	@RequiresPermissions("basic:manager:view")
+	public String index(HttpServletResponse response,HttpServletRequest request){
+		return "/basic/manager/index";
+	}
+
+
+	@ApiOperation(value = "查询管理员列表")
+	@GetMapping("/list")
+	@RequiresPermissions("basic:manager:view")
+	@ResponseBody
+	public ResultData list(@ModelAttribute @ApiIgnore ManagerEntity manager,HttpServletResponse response, HttpServletRequest request,@ApiIgnore ModelMap model) {
+		BasicUtil.startPage();
+		AppEntity websiteApp = BasicUtil.getWebsiteApp();
+		List<ManagerEntity> managerList;
+		if (websiteApp != null){
+			String appId = websiteApp.getAppId();
+			LambdaQueryWrapper<ManagerEntity> wrapper = new LambdaQueryWrapper<>();
+			wrapper.like(StringUtils.isNotBlank(manager.getManagerName()), ManagerEntity::getManagerName, manager.getManagerName());
+			wrapper.like(StringUtils.isNotBlank(manager.getManagerNickName()), ManagerEntity::getManagerNickName, manager.getManagerNickName());
+			wrapper.eq(StringUtils.isNotBlank(manager.getRoleIds()),ManagerEntity::getRoleIds,manager.getRoleIds());
+			wrapper.apply("APP_ID={0}",appId);
+			managerList = managerBiz.list(wrapper);
+		}else {
+			managerList = managerBiz.query(manager);
+		}
+		List<ManagerEntity> allManager = managerBiz.queryAllManager(managerList);
+		return ResultData.build().success( BasicUtil.filter(new EUListBean(allManager, (int) BasicUtil.endPage(allManager).getTotal()), "managerPassword",
+				"updateBy",
+				"createBy",
+				"del"));
+
+	}
+
+	@ApiOperation(value = "查询管理员列表,去掉当前管理员id,确保不能删除和修改自己")
+	@GetMapping("/query")
+	@RequiresPermissions("basic:manager:view")
+	@ResponseBody
+	public ResultData query(HttpServletResponse response, HttpServletRequest request, @ApiIgnore ModelMap model) {
+		ManagerEntity manager = BasicUtil.getManager();
+		BasicUtil.startPage();
+		AppEntity websiteApp = BasicUtil.getWebsiteApp();
+		List<ManagerEntity> managerList;
+		if (websiteApp != null){
+			String appId = websiteApp.getAppId();
+			QueryWrapper<ManagerEntity> wrapper = new QueryWrapper<ManagerEntity>().eq("APP_ID", appId);
+			managerList = managerBiz.list(wrapper);
+		}else {
+			managerList = managerBiz.list();
+
+		}
+		List<ManagerEntity> allManager = managerBiz.queryAllManager(managerList);
+		for (ManagerEntity _manager : allManager) {
+			assert manager != null;
+			if (_manager.getId().equals(manager.getId())) {
+				_manager.setId("0");
+			}
+		}
+		return ResultData.build().success(new EUListBean(allManager, (int) BasicUtil.endPage(allManager).getTotal()));
+
+	}
+
+	@ApiOperation(value="获取管理员接口")
+	@GetMapping("/get")
+	@RequiresPermissions("basic:manager:view")
+	@ResponseBody
+	public ResultData get(@ModelAttribute @ApiIgnore ManagerEntity manager,HttpServletResponse response, HttpServletRequest request,@ApiIgnore ModelMap model){
+		ManagerEntity managerEntity;
+		//判断是否传managerId
+		if (StringUtils.isNotEmpty(manager.getId())) {
+			managerEntity = managerBiz.getById(manager.getId());
+		} else {
+			ManagerEntity managerSession = BasicUtil.getManager();
+			if (managerSession == null) {
+				return ResultData.build().error("管理员已失效!");
+			}
+			managerEntity = managerBiz.getById(managerSession.getId());
+		}
+		if (managerEntity != null){
+			managerEntity.setManagerPassword("");
+		}
+		return ResultData.build().success(managerEntity);
+	}
+
+	@ApiOperation(value="获取当前管理员信息接口")
+	@GetMapping("/info")
+	@ResponseBody
+	public ResultData info(HttpServletResponse response, HttpServletRequest request){
+		ManagerEntity managerEntity =  BasicUtil.getManager();
+		if (managerEntity == null) {
+			return ResultData.build().error("管理员已失效!");
+		}
+		managerEntity = managerBiz.getById(managerEntity.getId());
+		if (managerEntity != null){
+			managerEntity.setManagerPassword("");
+		}
+		return ResultData.build().success(managerEntity);
+	}
+
+
+	@ApiOperation(value = "保存管理员实体")
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "managerName", value = "帐号", required = true,paramType="query"),
+			@ApiImplicitParam(name = "managerNickName", value = "昵称", required = true,paramType="query"),
+			@ApiImplicitParam(name = "managerPassword", value = "密码", required = true,paramType="query"),
+			@ApiImplicitParam(name = "roleId", value = "角色ID", required = false,paramType="query"),
+			@ApiImplicitParam(name = "peopleId", value = "用户ID", required = false,paramType="query"),
+	})
+	@LogAnn(title = "保存管理员实体",businessType= BusinessTypeEnum.INSERT)
+	@PostMapping("/save")
+	@ResponseBody
+	@RequiresPermissions("basic:manager:save")
+	public ResultData save(@ModelAttribute @ApiIgnore ManagerEntity manager, HttpServletResponse response, HttpServletRequest request) {
+		//验证管理员用户名的值是否合法
+		if(StringUtils.isBlank(manager.getManagerName())){
+			return ResultData.build().error(getResString("err.empty", this.getResString("manager.name")));
+		}
+		if(!StringUtil.checkLength(manager.getManagerName()+"", 6, 15)){
+			return ResultData.build().error(getResString("err.length", this.getResString("manager.name"), "6", "15"));
+		}
+		//用户名是否存在
+		if(managerBiz.getManagerByManagerName(manager.getManagerName())!= null){
+			return ResultData.build().error(getResString("err.exist", this.getResString("manager.name")));
+		}
+		if (!manager.getManagerName().matches("^[a-zA-Z0-9_]{6,15}$")) {
+			return ResultData.build().error(getResString("err.error", this.getResString("manager.name")));
+		}
+		//新增时不允许设置管理员标识,为了方便apifox响应校验抛出异常
+		if (StringUtils.isNotBlank(manager.getManagerAdmin())){
+			return ResultData.build().error(getResString("err.error", this.getResString("manager")));
+		}
+		manager.setManagerAdmin("");
+		//验证管理员昵称的值是否合法
+		if(StringUtils.isBlank(manager.getManagerNickName())){
+			return ResultData.build().error(getResString("err.empty", this.getResString("manager.nickname")));
+		}
+		if(!StringUtil.checkLength(manager.getManagerNickName()+"", 1, 15)){
+			return ResultData.build().error(getResString("err.length", this.getResString("manager.nickname"), "1", "15"));
+		}
+		//验证管理员密码的值是否合法
+		if(StringUtils.isBlank(manager.getManagerPassword())){
+			return ResultData.build().error(getResString("err.empty", this.getResString("manager.password")));
+		}
+		if(!StringUtil.checkLength(manager.getManagerPassword()+"", 6, 30)){
+			return ResultData.build().error(getResString("err.length", this.getResString("manager.password"), "6", "30"));
+		}
+		if (!manager.getManagerPassword().matches("(?!^(\\d+|[a-zA-Z]+|[~!@#$%^&*?]+)$)^[\\w~!@#$%^&*?]{6,30}$")) {
+			return ResultData.build().error(getResString("err.error", this.getResString("manager.password")));
+		}
+
+		manager.setManagerPassword(SecureUtil.md5(manager.getManagerPassword()));
+		managerBiz.save(manager);
+		managerBiz.updateCache();
+		return ResultData.build().success(manager);
+	}
+
+
+	@ApiOperation(value = "批量删除管理员")
+	@LogAnn(title = "批量删除管理员",businessType= BusinessTypeEnum.DELETE)
+	@PostMapping("/delete")
+	@ResponseBody
+	@RequiresPermissions("basic:manager:del")
+	public ResultData delete(@RequestBody List<ManagerEntity> managers,HttpServletResponse response, HttpServletRequest request) {
+		// 查询自己Id,不允许删除自己
+		ManagerEntity manager = BasicUtil.getManager();
+		Integer[] ids = new Integer[managers.size()];
+		for(int i = 0;i<managers.size();i++){
+			ids[i] = Integer.parseInt(managers.get(i).getId());
+		}
+		// 先查出需要删除id的信息
+		List<ManagerEntity> managerEntities = managerBiz.listByIds(Arrays.asList(ids));
+		managerEntities = managerEntities.stream().filter(managerEntity -> {
+			return ManagerAdminEnum.SUPER.toString().equals(managerEntity.getManagerAdmin()) || ManagerAdminEnum.SUPERADMIN.toString().equals(managerEntity.getManagerAdmin()) || manager.getId().equals(managerEntity.getId());
+		}).collect(Collectors.toList());
+		if (CollectionUtil.isNotEmpty(managerEntities)) {
+			LOG.error("非法操作删除超管账号或自己账号");
+			return ResultData.build().error(getResString("fail", getResString("remove")));
+		}
+		managerBiz.removeByIds(Arrays.asList(ids));
+		managerBiz.updateCache();
+		return ResultData.build().success();
+	}
+
+	@ApiOperation(value = "更新管理员信息管理员")
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "managerName", value = "帐号", required = true,paramType="query"),
+			@ApiImplicitParam(name = "managerNickName", value = "昵称", required = true,paramType="query"),
+			@ApiImplicitParam(name = "managerPassword", value = "密码", required = true,paramType="query"),
+			@ApiImplicitParam(name = "roleId", value = "角色ID", required = false,paramType="query"),
+			@ApiImplicitParam(name = "peopleId", value = "用户ID", required = false,paramType="query"),
+	})
+	@LogAnn(title = "更新管理员信息管理员",businessType= BusinessTypeEnum.UPDATE)
+	@PostMapping("/update")
+	@ResponseBody
+	@RequiresPermissions("basic:manager:update")
+	public ResultData update(@ModelAttribute @ApiIgnore ManagerEntity manager) {
+		//验证管理员用户名的值是否合法
+		if(StringUtils.isBlank(manager.getManagerName())){
+			return ResultData.build().error(getResString("err.empty", this.getResString("manager.name")));
+		}
+		if(!StringUtil.checkLength(manager.getManagerName()+"", 6, 15)){
+			return ResultData.build().error(getResString("err.length", this.getResString("manager.name"), "6", "15"));
+		}
+		managerBiz.updateCache();
+		ManagerEntity _manager = managerBiz.getManagerByManagerName(manager.getManagerName());
+		//用户名是否存在
+		if(_manager != null){
+			if(!_manager.getId().equals(manager.getId())){
+				return ResultData.build().error(getResString("err.exist", this.getResString("manager.name")));
+			}
+		}
+		_manager = managerBiz.getById(manager.getId());
+		if (_manager == null) {
+			return ResultData.build().error(getResString("err.not.exist", getResString("managerName")));
+		}
+		//修改时不允许设置管理员标识,为了方便apifox响应校验抛出异常
+		if (StringUtils.isNotBlank(manager.getManagerAdmin())){
+			return ResultData.build().error(getResString("err.error", this.getResString("manager")));
+		}
+		if (!manager.getManagerName().matches("^[a-zA-Z0-9_]{6,15}$")) {
+			return ResultData.build().error(getResString("err.error", this.getResString("manager.name")));
+		}
+		//验证管理员昵称的值是否合法
+		if(StringUtils.isBlank(manager.getManagerNickName())){
+			return ResultData.build().error(getResString("err.empty", this.getResString("manager.nickname")));
+		}
+		if(!StringUtil.checkLength(manager.getManagerNickName()+"", 1, 15)){
+			return ResultData.build().error(getResString("err.length", this.getResString("manager.nickname"), "1", "15"));
+		}
+		//验证管理员密码的值是否合法
+		if(!StringUtils.isBlank(manager.getManagerPassword())){
+			if(!StringUtil.checkLength(manager.getManagerPassword()+"", 6, 30)){
+				return ResultData.build().error(getResString("err.length", this.getResString("manager.password"), "6", "30"));
+			}
+			if (!manager.getManagerPassword().matches("(?!^(\\d+|[a-zA-Z]+|[~!@#$%^&*?]+)$)^[\\w~!@#$%^&*?]{6,30}$")) {
+				return ResultData.build().error(getResString("err.error", this.getResString("manager.password")));
+			}
+			manager.setManagerPassword(SecureUtil.md5(manager.getManagerPassword()));
+		} else {
+			manager.setManagerPassword(null);
+		}
+		managerBiz.updateById(manager);
+		return ResultData.build().success(manager);
+	}
+
+}

+ 642 - 0
src/main/java/net/mingsoft/basic/action/ModelAction.java

@@ -0,0 +1,642 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.json.JSONUtil;
+import cn.hutool.log.Log;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.BaseEntity;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.annotation.LogAnn;
+import net.mingsoft.basic.bean.EUListBean;
+import net.mingsoft.basic.biz.IManagerBiz;
+import net.mingsoft.basic.biz.IModelBiz;
+import net.mingsoft.basic.biz.IRoleModelBiz;
+import net.mingsoft.basic.constant.e.BusinessTypeEnum;
+import net.mingsoft.basic.constant.e.ModelIsMenuEnum;
+import net.mingsoft.basic.entity.ManagerEntity;
+import net.mingsoft.basic.entity.ModelEntity;
+import net.mingsoft.basic.entity.RoleModelEntity;
+import net.mingsoft.basic.exception.BusinessException;
+import net.mingsoft.basic.strategy.IModelStrategy;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.basic.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.sql.Timestamp;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 模块控制层
+ * @author 铭飞开发团队
+ * @version
+ * 版本号:200-000-000<br/>
+ * 创建日期:2014-6-29<br/>
+ * 历史修订: 新增 getModelListByManagerSession方法,
+ *          修改方法中所有ManagerSession.getRoleId()为getModelListByManagerSession
+ *          修改日期: 2022-1-5
+ * 2022-1-12 菜单结构调整,使用菜单策略,更改为超级管理员始终拥有所有菜单
+ * 2022-1-14 添加菜单排序功能
+ * 2023-1-08 优化权限标识及菜单标题校验规则,当菜单为导航链接时不允许标题重复,菜单为功能权限时不允许权限标识重复
+ */
+@Api(tags={"后端-基础接口"})
+@Controller
+@RequestMapping("/${ms.manager.path}/basic/model")
+public class ModelAction extends BaseAction {
+
+    /**
+     * 注入模块业务层
+     */
+    @Autowired
+    private IModelBiz modelBiz;
+
+    @Autowired
+    private IModelStrategy modelStrategy;
+
+    @Autowired
+    private IManagerBiz managerBiz;
+    /**
+     * 角色模块关联业务层
+     */
+    @Autowired
+    private IRoleModelBiz roleModelBiz;
+
+    /**
+     * 返回主界面index
+     */
+    @ApiIgnore
+    @GetMapping("/index")
+    @RequiresPermissions("basic:model:view")
+    public String index(HttpServletResponse response,HttpServletRequest request,ModelMap mode){
+        List<ModelEntity> parentModelList = modelStrategy.list();
+        mode.addAttribute("parentModelList", JSONUtil.toJsonStr(parentModelList));
+        return "/basic/model/index";
+    }
+
+
+    /**
+     * 查询模块表列表
+     * @param model 模块表实体
+     * <i>model参数包含字段信息参考:</i><br/>
+     * id 模块自增长id<br/>
+     * modelTitle 模块标题<br/>
+     * modelCode 模块编码<br/>
+     * modelId 模块的父模块id<br/>
+     * modelUrl 模块连接地址<br/>
+     * modelDatetime <br/>
+     * modelIcon 模块图标<br/>
+     * modelSort 模块的排序<br/>
+     * modelIsmenu 模块是否是菜单<br/>
+     * <dt><span class="strong">返回</span></dt><br/>
+     * <dd>[<br/>
+     * { <br/>
+     * id: 模块自增长id<br/>
+     * modelTitle: 模块标题<br/>
+     * modelCode: 模块编码<br/>
+     * modelId: 模块的父模块id<br/>
+     * modelUrl: 模块连接地址<br/>
+     * modelDatetime: <br/>
+     * modelIcon: 模块图标<br/>
+     * modelSort: 模块的排序<br/>
+     * modelIsmenu: 模块是否是菜单<br/>
+     * }<br/>
+     * ]</dd><br/>
+     */
+    @ApiOperation(value="菜单列表接口")
+    @GetMapping("/list")
+    @ResponseBody
+    public ResultData list(@ModelAttribute @ApiIgnore ModelEntity modelEntity, HttpServletResponse response, HttpServletRequest request, @ApiIgnore ModelMap model) {
+        List<ModelEntity> modelList = modelStrategy.list();
+        if(CollectionUtil.isEmpty(modelList)){
+            // 该角色在站点中无对应角色
+            return ResultData.build().success();
+        }
+        modelList.sort((o1, o2) -> {
+            int sort1 = o1.getModelSort() == null ? 0 : o1.getModelSort();
+            int sort2 = o2.getModelSort() == null ? 0 : o2.getModelSort();
+            return sort2 - sort1;
+        });
+        EUListBean _list = new EUListBean(modelList, modelList.size());
+        return ResultData.build().success(_list);
+    }
+
+    @ApiOperation(value="菜单子集列表")
+    @GetMapping("/childList")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "modelTitle", value = "菜单名称", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelId", value = "父级菜单编号", required = false,paramType="query")
+    })
+    @RequiresPermissions("basic:model:view")
+    @ResponseBody
+    public ResultData childList(@ModelAttribute @ApiIgnore ModelEntity modelEntity, HttpServletResponse response, HttpServletRequest request) {
+        List<ModelEntity> list = modelBiz.queryChildList(modelEntity);
+        return ResultData.build().success(list);
+    }
+
+    @ApiOperation(value="菜单导入接口")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "menuStr", value = "菜单json", required = true,paramType="query"),
+            @ApiImplicitParam(name = "modelId", value = "父级菜单编号", required = true,paramType="query")
+    })
+    @LogAnn(title = "导入菜单",businessType= BusinessTypeEnum.INSERT)
+    @PostMapping("/import")
+    @ResponseBody
+    public ResultData importMenu(String menuStr,int modelId) {
+        if(StringUtils.isBlank(menuStr)){
+            return ResultData.build().error(getResString("err.empty", this.getResString("menu")));
+        }
+        try{
+            List<ModelEntity> list = JSONUtil.toList(menuStr, ModelEntity.class);
+            ManagerEntity manager = BasicUtil.getManager();
+            assert manager != null;
+
+
+            // 检查是否有重复的菜单标题或者权限标识
+            List<String> modelUrlList = new ArrayList<>();
+            List<String> modelTitleList = new ArrayList<>();
+            // 取出菜单的标题以及非菜单的权限标识
+            this.addModelUrlAndTitleForList(list,modelUrlList,modelTitleList);
+            LambdaQueryWrapper<ModelEntity> wrapper = null;
+            // 判断是否有重复的菜单标题
+            if (CollectionUtil.isNotEmpty(modelTitleList)){
+                wrapper = new LambdaQueryWrapper<>();
+                wrapper.in(ModelEntity::getModelTitle,modelTitleList);
+                wrapper.in(ModelEntity::getModelIsMenu,ModelIsMenuEnum.MODEL_MEUN.toInt());
+                List<ModelEntity> duplicateModelTitles = modelBiz.list(wrapper);
+                if (CollectionUtil.isNotEmpty(duplicateModelTitles)){
+                    // 已存在的标题集合,方便打印日志及相应到页面
+                    List<String> collect = duplicateModelTitles.stream().map(ModelEntity::getModelUrl).collect(Collectors.toList());
+                    Log.get(ModelAction.class).error("以下标题已存在:{}",StringUtils.join(collect,","));
+                    return ResultData.build().error(getResString("err.exist",this.getResString("model.title"))+": "+StringUtils.join(collect,","));
+                }
+            }
+            // 判断是否有重复的权限标识
+            if (CollectionUtil.isNotEmpty(modelUrlList)){
+                wrapper = new LambdaQueryWrapper<>();
+                wrapper.in(ModelEntity::getModelUrl,modelUrlList);
+                List<ModelEntity> duplicateModelUrls = modelBiz.list(wrapper);
+                if (CollectionUtil.isNotEmpty(duplicateModelUrls)){
+                    // 已存在的权限标识集合,方便打印日志及相应到页面
+                    List<String> collect = duplicateModelUrls.stream().map(ModelEntity::getModelUrl).collect(Collectors.toList());
+                    Log.get(ModelAction.class).error("以下标识已存在:{}",StringUtils.join(collect,","));
+                    return ResultData.build().error(getResString("err.exist",this.getResString("model.url"))+": "+StringUtils.join(collect,","));
+                }
+            }
+            // 导入菜单
+            for (ModelEntity modelEntity : list){
+                if (modelEntity.getModelIsMenu() == 0) {
+                    return ResultData.build().error("功能权限按钮不能作为菜单导入!");
+                }
+                modelBiz.importModel(modelEntity, manager.getRoleId(), String.valueOf(modelId), modelId);
+            }
+
+        }catch (RuntimeException e){
+            e.printStackTrace();
+            return ResultData.build().error(getResString("model.title.or.json"));
+        }catch (Exception e){
+            return ResultData.build().error(getResString("err.error", this.getResString("menu")));
+        }
+        modelBiz.updateCache();
+        return ResultData.build().success();
+    }
+
+    /**
+     * 获取模块表
+     * @param model 模块表实体
+     * <i>model参数包含字段信息参考:</i><br/>
+     * id 模块自增长id<br/>
+     * modelTitle 模块标题<br/>
+     * modelCode 模块编码<br/>
+     * modelId 模块的父模块id<br/>
+     * modelUrl 模块连接地址<br/>
+     * modelDatetime <br/>
+     * modelIcon 模块图标<br/>
+     * modelSort 模块的排序<br/>
+     * modelIsmenu 模块是否是菜单<br/>
+     * <dt><span class="strong">返回</span></dt><br/>
+     * <dd>{ <br/>
+     * id: 模块自增长id<br/>
+     * modelTitle: 模块标题<br/>
+     * modelCode: 模块编码<br/>
+     * modelId: 模块的父模块id<br/>
+     * modelUrl: 模块连接地址<br/>
+     * modelDatetime: <br/>
+     * modelIcon: 模块图标<br/>
+     * modelSort: 模块的排序<br/>
+     * modelIsmenu: 模块是否是菜单<br/>
+     * }</dd><br/>
+     */
+    @ApiOperation(value = "获取模块表")
+    @ApiImplicitParam(name = "id", value = "模块的编号", required = true,paramType="query")
+    @GetMapping("/get")
+    @RequiresPermissions("basic:model:view")
+    @ResponseBody
+    public ResultData get(@ModelAttribute @ApiIgnore ModelEntity modelEntity,HttpServletResponse response, HttpServletRequest request,@ApiIgnore ModelMap model){
+        if(StringUtils.isEmpty(modelEntity.getId())) {
+            return ResultData.build().error(getResString("err.error", this.getResString("model.id")));
+        }
+        //根据父模块id查寻模块
+        ModelEntity _model = (ModelEntity)modelBiz.getEntity(Integer.parseInt(modelEntity.getId()));
+        if(_model != null){
+            Map<String, ModelEntity> mode = new HashMap<String, ModelEntity>();
+            if(_model.getModelId() != null){
+                ModelEntity parentModel = (ModelEntity) modelBiz.getEntity(_model.getModelId());
+                mode.put("parentModel", parentModel);
+            }
+            mode.put("model", _model);
+            return ResultData.build().success(mode);
+        }
+        return ResultData.build().success(_model);
+    }
+
+    /**
+     * 保存模块表实体
+     * @param model 模块表实体
+     * <i>model参数包含字段信息参考:</i><br/>
+     * id 模块自增长id<br/>
+     * modelTitle 模块标题<br/>
+     * modelCode 模块编码<br/>
+     * modelId 模块的父模块id<br/>
+     * modelUrl 模块连接地址<br/>
+     * modelDatetime <br/>
+     * modelIcon 模块图标<br/>
+     * modelSort 模块的排序<br/>
+     * modelIsmenu 模块是否是菜单<br/>
+     * <dt><span class="strong">返回</span></dt><br/>
+     * <dd>{ <br/>
+     * id: 模块自增长id<br/>
+     * modelTitle: 模块标题<br/>
+     * modelCode: 模块编码<br/>
+     * modelId: 模块的父模块id<br/>
+     * modelUrl: 模块连接地址<br/>
+     * modelDatetime: <br/>
+     * modelIcon: 模块图标<br/>
+     * modelSort: 模块的排序<br/>
+     * modelIsmenu: 模块是否是菜单<br/>
+     * }</dd><br/>
+     */
+    @ApiOperation(value = "保存模块表实体")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "modelTitle", value = "模块的标题", required = true,paramType="query"),
+            @ApiImplicitParam(name = "modelCode", value = "模块编码", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelId", value = "模块父id", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelUrl", value = "链接地址", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelDatetime", value = "发布时间", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelIcon", value = "模块图标", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelSort", value = "模块排序", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelIsMenu", value = "是否是菜单", required = false,paramType="query"),
+            @ApiImplicitParam(name = "isChild", value = "菜单类型", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelParentIds", value = "父级编号集合", required = false,paramType="query"),
+    })
+    @LogAnn(title = "保存模块表实体",businessType= BusinessTypeEnum.INSERT)
+    @PostMapping("/save")
+    @ResponseBody
+    @RequiresPermissions("basic:model:save")
+    public ResultData save(@ModelAttribute @ApiIgnore ModelEntity model, HttpServletResponse response, HttpServletRequest request) {
+        //模块标题验证
+        if(StringUtils.isBlank(model.getModelTitle())){
+            return ResultData.build().error(getResString("err.empty", this.getResString("model.title")));
+        }
+        if(!StringUtil.checkLength(model.getModelTitle()+"", 1, 10)){
+            return ResultData.build().error(getResString("err.length", this.getResString("model.title"), "1", "10"));
+        }
+        //判断菜单名称不能相同
+        if(model.getModelIsMenu() == ModelIsMenuEnum.MODEL_MEUN.toInt()){
+            LambdaQueryWrapper<ModelEntity> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(ModelEntity::getModelTitle,model.getModelTitle()).eq(ModelEntity::getModelIsMenu,ModelIsMenuEnum.MODEL_MEUN.toInt());
+            List<ModelEntity> list = modelBiz.list(wrapper);
+            if(CollectionUtil.isNotEmpty(list)){
+                return ResultData.build().error(getResString("err.exist",this.getResString("model.title")));
+            }
+        }
+        // 判断菜单url不能为空且不能相同
+        if (model.getModelIsMenu()==ModelIsMenuEnum.MODEL_NOTMENU.toInt()){//权限标识的情况下
+            //对菜单权限标识进行去空格处理
+            model.setModelUrl(model.getModelUrl().trim());
+            if (StringUtils.isBlank(model.getModelUrl()))
+            return ResultData.build().error(getResString("err.empty",this.getResString("model.url")));
+            List<ModelEntity> modelList = modelBiz.list(new LambdaQueryWrapper<ModelEntity>().eq(ModelEntity::getModelUrl, model.getModelUrl()));
+            if (CollectionUtil.isNotEmpty(modelList)){
+                return ResultData.build().error(getResString("err.exist",this.getResString("model.url")));
+            }
+        }
+
+        // 获取模块保存时间
+        model.setModelDatetime(new Timestamp(System.currentTimeMillis()));
+        //判断图标是否为空,不为空去掉,图标地址中含有的“|”
+        //空值判断
+        if(!StringUtils.isBlank(model.getModelIcon())) {
+            model.setModelIcon( model.getModelIcon().replace("|", ""));
+        }
+        //重复判断,modelCode不能重复
+        if(StringUtils.isNotBlank(model.getModelCode())){
+            ModelEntity _model = modelBiz.getEntityByModelCode(model.getModelCode());
+            if (_model != null){
+                return ResultData.build().error(getResString("err.exist",this.getResString("modelCode")));
+            }
+        }
+        if(model.getModelSort() == null){
+            model.setModelSort(0);
+        }
+
+        // 防止最顶级栏目为空时报NP异常
+        if (model.getModelId() != null){
+            // 获取到父级model实体
+            ModelEntity modelEntity = modelBiz.getById(model.getModelId());
+            // 如果父级getModelParentIds为空则必然为顶级
+            if (StringUtils.isBlank(modelEntity.getModelParentIds())) {
+                model.setModelParentIds(model.getModelId().toString());
+            }else {
+                model.setModelParentIds(modelEntity.getModelParentIds()+","+model.getModelId().toString());
+            }
+        }
+
+        modelBiz.save(model);
+        //保存成功后给当前管理就就加上对应的权限
+        if(StringUtils.isNotEmpty(model.getId())){
+            ManagerEntity manager = BasicUtil.getManager();
+            assert manager != null;
+            List<RoleModelEntity> roleModels = new ArrayList<>();
+            for (String roleId : manager.getRoleIds().split(",")) {
+                RoleModelEntity roleModel = new RoleModelEntity();
+                roleModel.setModelId(Integer.parseInt(model.getId()));
+                roleModel.setRoleId(Integer.parseInt(roleId));
+                roleModels.add(roleModel);
+            }
+
+            roleModelBiz.saveBatch(roleModels, roleModels.size());
+        }
+        modelBiz.updateCache();
+        //返回模块id到页面
+        return ResultData.build().success(model.getId());
+    }
+
+
+    @ApiOperation(value = "批量删除模块表")
+    @ApiImplicitParam(name = "ids", value = "模块编号,多个以逗号隔开", required = false,paramType="query")
+    @LogAnn(title = "批量删除模块表",businessType= BusinessTypeEnum.DELETE)
+    @PostMapping("/delete")
+    @ResponseBody
+    @RequiresPermissions("basic:model:del")
+    public ResultData delete(HttpServletResponse response, HttpServletRequest request) {
+        int[] ids = BasicUtil.getInts("ids", ",");
+        modelBiz.delete(ids);
+        return ResultData.build().success();
+    }
+
+    /**
+     * 更新模块表信息模块表
+     * @param model 模块表实体
+     * <i>model参数包含字段信息参考:</i><br/>
+     * id 模块自增长id<br/>
+     * modelTitle 模块标题<br/>
+     * modelCode 模块编码<br/>
+     * modelId 模块的父模块id<br/>
+     * modelUrl 模块连接地址<br/>
+     * modelDatetime <br/>
+     * modelIcon 模块图标<br/>
+     * modelSort 模块的排序<br/>
+     * modelIsmenu 模块是否是菜单<br/>
+     * <dt><span class="strong">返回</span></dt><br/>
+     * <dd>{ <br/>
+     * id: 模块自增长id<br/>
+     * modelTitle: 模块标题<br/>
+     * modelCode: 模块编码<br/>
+     * modelId: 模块的父模块id<br/>
+     * modelUrl: 模块连接地址<br/>
+     * modelDatetime: <br/>
+     * modelIcon: 模块图标<br/>
+     * modelSort: 模块的排序<br/>
+     * modelIsmenu: 模块是否是菜单<br/>
+     * }</dd><br/>
+     */
+    @ApiOperation(value = "更新模块表信息模块表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "模块的编号", required = true,paramType="query"),
+            @ApiImplicitParam(name = "modelTitle", value = "模块的标题", required = true,paramType="query"),
+            @ApiImplicitParam(name = "modelCode", value = "模块编码", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelId", value = "模块父id", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelUrl", value = "链接地址", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelDatetime", value = "发布时间", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelIcon", value = "模块图标", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelSort", value = "模块排序", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelIsMenu", value = "是否是菜单", required = false,paramType="query"),
+            @ApiImplicitParam(name = "isChild", value = "菜单类型", required = false,paramType="query"),
+            @ApiImplicitParam(name = "modelParentIds", value = "父级编号集合", required = false,paramType="query"),
+    })
+    @LogAnn(title = "更新模块表信息模块表",businessType= BusinessTypeEnum.UPDATE)
+    @PostMapping("/update")
+    @RequiresPermissions("basic:model:update")
+    @ResponseBody
+    public ResultData update(@ModelAttribute @ApiIgnore ModelEntity model, HttpServletResponse response,
+                             HttpServletRequest request) {
+        //模块标题验证
+        if(StringUtil.isBlank(model.getModelTitle())){
+            return ResultData.build().error(getResString("err.empty", this.getResString("model.title")));
+        }
+        if(!StringUtil.checkLength(model.getModelTitle()+"", 1, 10)){
+            return ResultData.build().error(getResString("err.length", this.getResString("model.title"), "1", "10"));
+        }
+        //判断菜单名称不能相同
+        if(model.getModelIsMenu() == ModelIsMenuEnum.MODEL_MEUN.toInt()){
+            LambdaQueryWrapper<ModelEntity> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(ModelEntity::getModelTitle,model.getModelTitle()).eq(ModelEntity::getModelIsMenu,ModelIsMenuEnum.MODEL_MEUN.toInt());
+            List<ModelEntity> list = modelBiz.list(wrapper);
+            // 查出数据不为空,且集合元素大于一个或者有一个但不是自己
+            if(CollectionUtil.isNotEmpty(list) && (list.size()>1 || !list.get(0).getId().equals(model.getId()))){
+                return ResultData.build().error(getResString("err.exist",this.getResString("model.title")));
+            }
+        }
+        //判断当前修改的菜单是否是三级菜单
+        ModelEntity _model = (ModelEntity) modelBiz.getEntity(Integer.parseInt(model.getId()));
+        if(_model.getModelIsMenu() == 1 && model.getModelIsMenu() == 0){
+            return ResultData.build().error(this.getResString("model.is.menu"));
+        }
+        // 判断菜单url不能为空且不能相同
+        if (model.getModelIsMenu()==ModelIsMenuEnum.MODEL_NOTMENU.toInt()){
+            //对菜单权限标识进行去空格处理
+            model.setModelUrl(model.getModelUrl().trim());
+            if (StringUtils.isBlank(model.getModelUrl()))
+                return ResultData.build().error(getResString("err.empty",this.getResString("model.url")));
+            List<ModelEntity> modelList = modelBiz.list(new LambdaQueryWrapper<ModelEntity>().eq(ModelEntity::getModelUrl, model.getModelUrl()));
+            if (CollectionUtil.isNotEmpty(modelList) && !modelList.get(0).getId().equals(model.getId())){
+                return ResultData.build().error(getResString("err.exist",this.getResString("model.url")));
+            }
+        }
+        //判断图标是否为空,不为空去掉,图标地址中含有的“|”
+        //空值判断
+        if(!StringUtil.isBlank(model.getModelIcon())) {
+            model.setModelIcon( model.getModelIcon().replace("|", ""));
+        }
+        modelBiz.updateEntity(model);
+        return ResultData.build().success(model.getId());
+    }
+
+    /**
+     * 根据管理员ID查询模块集合
+     * @param managerId 管理员id
+     * @param request 请求对象
+     * @param response 响应对象
+     */
+    @ApiOperation(value = "根据管理员ID查询模块集合")
+    @ApiImplicitParam(name = "managerId", value = "管理员id", required = true,paramType="path")
+    @GetMapping("/{managerId}/queryModelByRoleId")
+    @ResponseBody
+    public ResultData queryModelByRoleId(@PathVariable @ApiIgnore int managerId,HttpServletRequest request, HttpServletResponse response) {
+        ManagerEntity manager =(ManagerEntity) managerBiz.getEntity(managerId);
+        if(manager==null){
+            return ResultData.build().error();
+        }
+        HashSet<ModelEntity> modelSet = new HashSet<>();
+        for (String roleId : manager.getRoleIds().split(",")) {
+            modelSet.addAll(modelBiz.queryModelByRoleId(Integer.parseInt(roleId)));
+        }
+        List<ModelEntity> modelList = new ArrayList<>(modelSet);
+        return ResultData.build().success(modelList);
+    }
+
+    /**
+     * 查询模块表列表
+     * @param model 模块表实体
+     * <i>model参数包含字段信息参考:</i><br/>
+     * id 模块自增长id<br/>
+     * modelTitle 模块标题<br/>
+     * modelCode 模块编码<br/>
+     * modelId 模块的父模块id<br/>
+     * modelUrl 模块连接地址<br/>
+     * modelDatetime <br/>
+     * modelIcon 模块图标<br/>
+     * modelSort 模块的排序<br/>
+     * modelIsmenu 模块是否是菜单<br/>
+     * <dt><span class="strong">返回</span></dt><br/>
+     * <dd>[<br/>
+     * { <br/>
+     * id: 模块自增长id<br/>
+     * modelTitle: 模块标题<br/>
+     * modelCode: 模块编码<br/>
+     * modelId: 模块的父模块id<br/>
+     * modelUrl: 模块连接地址<br/>
+     * modelDatetime: <br/>
+     * modelIcon: 模块图标<br/>
+     * modelSort: 模块的排序<br/>
+     * modelIsmenu: 模块是否是菜单<br/>
+     * }<br/>
+     * ]</dd><br/>
+     */
+    @ApiOperation(value = "查询模块表列表")
+    @ApiImplicitParam(name = "roleId", value = "角色编号", required = true,paramType="query")
+    @GetMapping("/modelList")
+    @ResponseBody
+    public ResultData modelList(@ModelAttribute @ApiIgnore ModelEntity modelEntity,HttpServletResponse response, HttpServletRequest request,@ApiIgnore ModelMap model) {
+        int roleId = BasicUtil.getInt("roleId");
+        ManagerEntity managerSession = BasicUtil.getManager();
+        boolean updateFlag = roleId != 0;
+        //新增角色roleId为0,默认当前管理员的roleId
+        List<ModelEntity> modelList = modelStrategy.list();
+
+        List<ModelEntity> _modelList = new ArrayList<>();
+        List<RoleModelEntity> roleModelList = new ArrayList<>();
+        if(roleId>0){
+            roleModelList = roleModelBiz.queryByRoleId(roleId);
+        }else {
+            HashSet<RoleModelEntity> roleSet = new HashSet<>();
+            for (String id : managerSession.getRoleIds().split(",")) {
+                roleSet.addAll(roleModelBiz.queryByRoleId(Integer.parseInt(id)));
+            }
+            roleModelList.addAll(roleSet);
+        }
+        List<ModelEntity> childModelList = new ArrayList<>();
+        //将菜单和功能区分开
+        for(BaseEntity base : modelList){
+            ModelEntity _model = (ModelEntity) base;
+            if(_model.getModelIsMenu() == 1){
+                _model.setModelChildList(new ArrayList<ModelEntity>());
+                _modelList.add(_model);
+            }else if(_model.getModelIsMenu() == 0){
+                childModelList.add(_model);
+            }
+        }
+        //菜单和功能一一匹配
+        for(ModelEntity _modelEntity : _modelList){
+            for(ModelEntity childModel : childModelList){
+                if(childModel.getModelId() == Integer.parseInt(_modelEntity.getId())){
+                    _modelEntity.getModelChildList().add(childModel);
+                    //选中状态
+                    for(RoleModelEntity roleModelEntity : roleModelList){
+                        if(roleModelEntity.getModelId() == Integer.parseInt(childModel.getId()) && updateFlag){
+                            childModel.setChick(1);
+                        }
+                    }
+
+                }
+            }
+        }
+        EUListBean _list = new EUListBean(_modelList, _modelList.size());
+        return ResultData.build().success(_list);
+    }
+
+
+    /**
+     * 递归遍历菜单实体集合,将菜单标题及非菜单的权限标识分别添加至modelTitleList及modelUrlList
+     * 递归的执行条件为 当前遍历到的实体子菜单集合不为空
+     * @param modelEntityList 菜单实体集合 不允许为空
+     * @param modelUrlList 菜单权限标识集合 不允许为空
+     * @param modelTitleList 菜单标题集合 不允许为空
+     * @throws BusinessException 实体标题长度不合格,或者实体不是菜单且实体的权限标识为空
+     */
+    private void addModelUrlAndTitleForList(List<ModelEntity> modelEntityList,List<String> modelUrlList,List<String> modelTitleList){
+        // 空判断,集合中没有元素则直接返回
+        if (CollectionUtil.isEmpty(modelEntityList) || modelUrlList == null || modelTitleList == null){
+            return;
+        }
+        // 遍历菜单集合
+        for (ModelEntity model : modelEntityList) {
+            // 不合规的标题直接抛出异常
+            if (!StringUtil.checkLength(model.getModelTitle()+"", 1, 20)){
+                throw new BusinessException(getResString("err.length", this.getResString("model.title"), "1", "20"));
+            }
+            // 当实体不为菜单且权限标识不为空,则向modelUrlList添加一条记录;实体为菜单则向modelTitleList添加一条记录
+            if (model.getModelIsMenu()==ModelIsMenuEnum.MODEL_NOTMENU.toInt()){
+                if (StringUtils.isBlank(model.getModelUrl())){
+                    throw new BusinessException(getResString("err.empty", this.getResString("model.url")));
+                }
+                //对菜单权限标识进行去空格处理
+                model.setModelUrl(model.getModelUrl().trim());
+                modelUrlList.add(model.getModelUrl());
+            }else {
+                modelTitleList.add(model.getModelTitle());
+            }
+            // 当前实体有子菜单,则递归执行
+            if (CollectionUtil.isNotEmpty(model.getModelChildList())){
+                this.addModelUrlAndTitleForList(model.getModelChildList(),modelUrlList,modelTitleList);
+            }
+        }
+    }
+
+}

+ 228 - 0
src/main/java/net/mingsoft/basic/action/RoleAction.java

@@ -0,0 +1,228 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.annotation.LogAnn;
+import net.mingsoft.basic.bean.EUListBean;
+import net.mingsoft.basic.bean.RoleBean;
+import net.mingsoft.basic.biz.IModelBiz;
+import net.mingsoft.basic.biz.IRoleBiz;
+import net.mingsoft.basic.biz.IRoleModelBiz;
+import net.mingsoft.basic.constant.e.BusinessTypeEnum;
+import net.mingsoft.basic.entity.ManagerEntity;
+import net.mingsoft.basic.entity.RoleEntity;
+import net.mingsoft.basic.entity.RoleModelEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.authz.annotation.Logical;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 角色管理控制层
+ * @author 铭飞开发团队
+ * @version
+ * 版本号:1.0<br/>
+ * 创建日期:2017-8-24 23:40:55<br/>
+ * 历史修订:<br/>
+ */
+@Api(tags={"后端-基础接口"})
+@Controller
+@RequestMapping("/${ms.manager.path}/basic/role")
+public class RoleAction extends BaseAction{
+
+	/**
+	 * 注入角色业务层
+	 */
+	@Autowired
+	private IRoleBiz roleBiz;
+	/**
+	 * 模块业务层
+	 */
+	@Autowired
+	private IModelBiz modelBiz;
+	/**
+	 * 角色模块关联业务层
+	 */
+	@Autowired
+	private IRoleModelBiz roleModelBiz;
+
+	/**
+	 * 返回主界面index
+	 */
+	@ApiIgnore
+	@GetMapping("/index")
+	@RequiresPermissions("basic:role:view")
+	public String index(HttpServletResponse response,HttpServletRequest request){
+		return "/basic/role/index";
+	}
+
+	/**
+	 * 返回编辑界面role_form
+	 */
+	@ApiOperation(value = "返回编辑界面role_form")
+	@ApiImplicitParam(name = "id", value = "角色ID", required = true,paramType="query")
+	@GetMapping("/form")
+	@RequiresPermissions("basic:role:view")
+	public String form(@ModelAttribute @ApiIgnore RoleEntity role,HttpServletResponse response,HttpServletRequest request,@ApiIgnore ModelMap model){
+		if(StringUtils.isNotEmpty(role.getId())){
+			RoleEntity roleEntity = roleBiz.getById(role.getId());
+			model.addAttribute("roleEntity",roleEntity);
+		}
+		return "/basic/role/form";
+	}
+
+	@ApiOperation(value = "查询角色列表")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "roleName", value = "角色名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "managerId", value = "该角色的创建者ID", required = false,paramType="query"),
+	})
+	@GetMapping("/list")
+	//@RequiresPermissions("role:view") 此处权限在栏目权限管理等其他功能被调用,需放行
+	@ResponseBody
+	public ResultData list(@ModelAttribute @ApiIgnore RoleEntity role,HttpServletResponse response, HttpServletRequest request,@ApiIgnore ModelMap model) {
+		BasicUtil.startPage();
+		List roleList = roleBiz.query(role);
+		return ResultData.build().success(new EUListBean(roleList,(int)BasicUtil.endPage(roleList).getTotal()));
+	}
+
+	@ApiOperation(value = "根据角色ID查询模块集合")
+	@ApiImplicitParam(name = "roleId", value = "角色ID", required = true,paramType="path")
+	@GetMapping("/{roleId}/queryByRole")
+	@ResponseBody
+	public ResultData queryByRole(@PathVariable @ApiIgnore int roleId, HttpServletResponse response){
+		List models = modelBiz.queryModelByRoleId(roleId);
+		return ResultData.build().success(models);
+	}
+
+	@ApiOperation(value = "查询所有角色列表")
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "roleName", value = "角色名称", required = false,paramType="query"),
+			@ApiImplicitParam(name = "managerId", value = "该角色的创建者ID", required = false,paramType="query"),
+	})
+	@GetMapping("/all")
+	@ResponseBody
+	public ResultData all(@ModelAttribute @ApiIgnore RoleEntity role,HttpServletResponse response, HttpServletRequest request,@ApiIgnore ModelMap model) {
+		BasicUtil.startPage();
+		List roleList = roleBiz.query(role);
+		return ResultData.build().success(new EUListBean(roleList,(int)BasicUtil.endPage(roleList).getTotal()));
+	}
+
+	@ApiOperation(value = "获取角色")
+	@ApiImplicitParam(name = "id", value = "角色ID", required = true,paramType="query")
+	@GetMapping("/get")
+	@RequiresPermissions("basic:role:view")
+	@ResponseBody
+	public ResultData get(@ModelAttribute @ApiIgnore RoleEntity role,HttpServletResponse response, HttpServletRequest request,@ApiIgnore ModelMap model){
+		if(StringUtils.isEmpty(role.getId())) {
+			return ResultData.build().error(getResString("err.error", this.getResString("role.id")));
+		}
+		RoleEntity _role = (RoleEntity)roleBiz.getEntity(Integer.parseInt(role.getId()));
+		return ResultData.build().success(_role);
+	}
+
+
+	@ApiOperation(value = "保存角色实体")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "roleName", value = "角色名称", required = true,paramType="query"),
+		@ApiImplicitParam(name = "managerId", value = "该角色的创建者ID", required = false,paramType="query"),
+		@ApiImplicitParam(name = "ids", value = "功能权限id", required = true,paramType="query"),
+	})
+	@LogAnn(title = "保存角色实体",businessType= BusinessTypeEnum.UPDATE)
+	@PostMapping("/saveOrUpdateRole")
+	@ResponseBody
+	@RequiresPermissions(value = {"basic:role:save","basic:role:update"}, logical = Logical.OR)
+	public ResultData saveOrUpdateRole(@ModelAttribute @ApiIgnore RoleBean role, HttpServletResponse response, HttpServletRequest request) {
+		//组织角色属性,并对角色进行保存
+		RoleBean _role = new RoleBean();
+		_role.setRoleName(role.getRoleName());
+		//获取管理员id
+		if(StringUtils.isEmpty(role.getRoleName())){
+			return ResultData.build().error(getResString("err.empty", this.getResString("roleName")));
+		}
+		RoleBean roleBean = (RoleBean) roleBiz.getEntity(_role);
+		//通过角色id判断是保存还是修改
+		if(StringUtils.isNotEmpty(role.getId())){
+			//若为更新角色,数据库中存在该角色名称且当前名称不为更改前的名称,则属于重名
+			if(roleBean != null && !roleBean.getId().equals(role.getId())){
+				return ResultData.build().error(getResString("roleName.exist"));
+			}
+			role.setUpdateBy(BasicUtil.getManager().getId());
+			role.setUpdateDate(new Date());
+			role.setCreateBy(null);
+			roleBiz.updateById(role);
+		}else{
+			//判断角色名是否重复
+			if(roleBean != null){
+				return ResultData.build().error(getResString("roleName.exist"));
+			}
+			role.setCreateBy(BasicUtil.getManager().getId());
+			role.setCreateDate(new Date());
+			//获取管理员id
+			roleBiz.save(role);
+			roleBiz.updateCache();
+		}
+		//开始保存相应的关联数据。组织角色模块的列表。
+		List<RoleModelEntity> roleModelList = new ArrayList<>();
+		if(!StringUtils.isEmpty(role.getIds())){
+			for(String id : role.getIds().split(",")){
+				RoleModelEntity roleModel = new RoleModelEntity();
+				roleModel.setRoleId(Integer.parseInt(role.getId()));
+				roleModel.setModelId(Integer.parseInt(id));
+				roleModelList.add(roleModel);
+			}
+			//先删除当前的角色关联菜单,然后重新添加。
+			roleModelBiz.deleteByRoleId(Integer.parseInt(role.getId()));
+			modelBiz.updateCache();
+
+			//加上数量参数用于区分IBaseBiz的重名方法
+			roleModelBiz.saveBatch(roleModelList, roleModelList.size());
+		}else{
+			roleModelBiz.deleteByRoleId(Integer.parseInt(role.getId()));
+		}
+		roleBiz.updateCache();
+		return ResultData.build().success(role);
+	}
+
+
+	@ApiOperation(value = "批量删除角色")
+	@PostMapping("/delete")
+	@ResponseBody
+	@RequiresPermissions("basic:role:del")
+	@LogAnn(title = "删除角色", businessType = BusinessTypeEnum.DELETE)
+	public ResultData delete(@RequestBody List<RoleEntity> roles,HttpServletResponse response, HttpServletRequest request) {
+		//获取当前登录管理员的所属角色信息
+		ManagerEntity managerSession = BasicUtil.getManager();
+
+		if (roleBiz.deleteRoleByRoles(roles,managerSession)){
+			return ResultData.build().success("删除成功",null);
+		}
+		return ResultData.build().success("删除成功,已过滤当前不可删除角色",null);
+	}
+}

+ 118 - 0
src/main/java/net/mingsoft/basic/action/SystemAction.java

@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+package net.mingsoft.basic.action;
+
+import cn.hutool.system.oshi.CpuInfo;
+import cn.hutool.system.oshi.OshiUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.ResultData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Properties;
+
+/**
+ * 系统信息
+ * @author 铭飞开发团队
+ * @version
+ * 版本号:1.0<br/>
+ * 创建日期:2022-8-24 23:40:55<br/>
+ * 历史修订:<br/>
+ */
+@Api(tags={"后端-系统信息"})
+@Controller
+@RequestMapping("/${ms.manager.path}/basic/system")
+public class SystemAction extends BaseAction{
+
+    @Autowired
+    private DataSource dataSource;
+    /**
+     * 系统信息
+     * @param request
+     * @return 表单页面地址
+     */
+    @ApiIgnore
+    @ApiOperation(value = "加载UI的表单页面")
+    @GetMapping("/index")
+    public String index(HttpServletRequest request) {
+        return "/basic/system/index";
+    }
+
+    /**
+     * 获取系统配置信息
+     * @param request 请求对象
+     * @return true退出成功
+     */
+    @ApiOperation(value = "获取系统配置信息")
+    @PostMapping("/info")
+    @ResponseBody
+    public ResultData info(HttpServletResponse response, HttpServletRequest request) {
+
+        Properties props = System.getProperties();// 获取当前的系统属性
+        HashMap<String, Object> map = new HashMap<>();
+        map.put("CPU核数", String.valueOf(Runtime.getRuntime().availableProcessors()));
+
+        // 单位B 转换为M
+        map.put("虚拟机内存总量", String.valueOf(Runtime.getRuntime().totalMemory() / 1048576));
+        map.put("虚拟机空闲内存量", String.valueOf(Runtime.getRuntime().freeMemory() / 1048576));
+        map.put("虚拟机使用最大内存量", String.valueOf(Runtime.getRuntime().maxMemory() / 1048576));
+
+        map.put("系统名称", props.getProperty("os.name"));
+        map.put("系统构架", props.getProperty("os.arch"));
+        map.put("系统版本", props.getProperty("os.version"));
+
+        map.put("Java版本", props.getProperty("java.version"));
+        map.put("Java安装路径", props.getProperty("java.home"));
+
+        CpuInfo cpu = OshiUtil.getCpuInfo();
+        map.put("cpu信息", cpu.getCpuModel() + "" + cpu.getCpuNum());
+        map.put("内存总量", OshiUtil.getMemory().getTotal() / 1048576);
+        map.put("内存可用", OshiUtil.getMemory().getAvailable() / 1048576);
+
+        //数据库
+        Connection connection = null;
+        try {
+            connection = dataSource.getConnection();
+            DatabaseMetaData mtdt = connection.getMetaData();
+            map.put("数据库链接", mtdt.getURL());
+            map.put("数据库",mtdt.getDatabaseProductName());
+            map.put("数据库版本",mtdt.getDatabaseProductVersion());
+
+        } catch (SQLException throwables) {
+            throwables.printStackTrace();
+        } finally {
+            if(connection != null) {
+                try {
+                    connection.close();
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        ServletContext context = request.getServletContext();
+        map.put("web容器",context.getServerInfo());
+        map.put("发布路径",context.getRealPath(""));
+//
+        return ResultData.build().success(map);
+    }
+
+}

+ 482 - 0
src/main/java/net/mingsoft/basic/action/TemplateAction.java

@@ -0,0 +1,482 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action;
+
+import cn.hutool.core.io.FileTypeUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.file.FileReader;
+import cn.hutool.core.io.file.FileWriter;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.annotation.LogAnn;
+import net.mingsoft.basic.biz.IAppBiz;
+import net.mingsoft.basic.constant.e.BusinessTypeEnum;
+import net.mingsoft.basic.constant.e.CookieConstEnum;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.config.MSProperties;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author 铭软开发团队
+ * @ClassName: TemplateAction
+ * @Description: TODO(模板控制层)
+ * @date 2020年7月2日
+ */
+@Api(tags={"后端-基础接口"})
+@Controller("/basicTemplate")
+@RequestMapping("/${ms.manager.path}/basic/template")
+public class TemplateAction extends BaseAction {
+
+    /**
+     * 站点业务层
+     */
+    @Autowired
+    private IAppBiz appBiz;
+
+
+    /**
+     * 返回主界面index
+     */
+    @ApiIgnore
+    @GetMapping("/index")
+    @RequiresPermissions("basic:template:view")
+    public String index(HttpServletResponse response, HttpServletRequest request) {
+        return "/basic/template/index";
+    }
+
+    /**
+     * 返回模板编辑
+     */
+    @ApiIgnore
+    @GetMapping("/form")
+    @RequiresPermissions("basic:template:view")
+    public String form(HttpServletResponse response, HttpServletRequest request) {
+        return "/basic/template/form";
+    }
+
+    /**
+     * 返回模板编辑页面
+     */
+    @ApiIgnore
+    @GetMapping("/edit")
+    @RequiresPermissions("basic:template:view")
+    public String edit(HttpServletResponse response, HttpServletRequest request) {
+        return "/basic/template/edit";
+    }
+
+    /**
+     * 点击模板管理,获取所有的模板文件名
+     *
+     * @param response 响应
+     * @param request  请求
+     * @return 返回模板文件名集合
+     */
+    @ApiOperation(value = "点击模板管理,获取所有的模板文件名")
+    @ApiImplicitParam(name = "pageNo", value = "pageNo", required = true, paramType = "query")
+    @GetMapping("/queryTemplateSkin")
+    @RequiresPermissions("basic:template:view")
+    @ResponseBody
+    protected ResultData queryTemplateSkin(HttpServletResponse response, HttpServletRequest request) {
+        String pageNo = request.getParameter("pageNo");
+        if (!NumberUtils.isNumber(pageNo)) {
+            pageNo = "1";
+        }
+        List<String> folderNameList = this.queryTemplateFile();
+        Map<String, Object> map = new HashMap<>(3);
+        map.put("folderNameList", folderNameList);
+        map.put("websiteId", BasicUtil.getApp().getAppId());
+        map.put("pageNo", pageNo);
+        BasicUtil.setCookie(response, CookieConstEnum.PAGENO_COOKIE, pageNo);
+        return ResultData.build().success(map);
+    }
+
+
+
+    /**
+     * http://localhost:5118/ms/file/uploadTemplate.do
+     * 写入模板文件内容
+     *
+     * @param model
+     * @param request  请求
+     * @param response 响应
+     * @throws IOException
+     */
+    @ApiOperation(value = "写入模板文件内容")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "fileName", value = "文件名称", required = true, paramType = "query"),
+            @ApiImplicitParam(name = "fileContent", value = "文件内容", required = true, paramType = "query"),
+    })
+    @LogAnn(title = "写入模板文件内容", businessType = BusinessTypeEnum.UPDATE)
+    @PostMapping("/writeFileContent")
+    @ResponseBody
+    public ResultData writeFileContent(@ApiIgnore ModelMap model, HttpServletRequest request, HttpServletResponse response)
+            throws IOException {
+        LOG.debug("ready modify template");
+        String fileName = BasicUtil.getString("fileName");
+        String uploadTemplatePath = MSProperties.upload.template;
+        if (StringUtils.isEmpty(fileName) || !fileName.startsWith(uploadTemplatePath)){
+            return ResultData.build().error(getResString("err.error",this.getResString("file.name")));
+        }
+        // 文件路径
+        String templets = BasicUtil.getRealTemplatePath(fileName);
+        if (!FileUtil.exist(templets)) {
+            return ResultData.build().error(this.getResString("failed.to.edit.a.template"));
+        }
+        //校验后缀文件名
+        if (!checkFileType(fileName)) {
+            return ResultData.build().error(this.getResString("failed.to.edit.a.template"));
+        }
+
+        String fileContent = BasicUtil.getString("fileContent");
+        if (!StringUtils.isEmpty(fileName)) {
+            FileWriter.create(new File(templets)).write(fileContent);
+            LOG.debug("edit template file:{} success!",fileName);
+            return ResultData.build().success();
+        }
+        return ResultData.build().error();
+    }
+
+
+    /**
+     * 删除模版
+     * <p>
+     * 模版名称
+     *
+     * @param request 响应
+     */
+    @ApiOperation(value = "删除模版")
+    @ApiImplicitParam(name = "fileName", value = "模版名称", required = true, paramType = "query")
+    @LogAnn(title = "删除模版", businessType = BusinessTypeEnum.DELETE)
+    @PostMapping("/delete")
+    @ResponseBody
+    @RequiresPermissions("basic:template:del")
+    public ResultData delete(HttpServletRequest request) {
+        String uploadTemplatePath = MSProperties.upload.template;
+        String fileName = request.getParameter("fileName");
+        if (fileName != null && (fileName.contains("..") || fileName.contains("../") || fileName.contains("..\\"))) {
+            return ResultData.build().error("非法路径");
+        }
+        String path = BasicUtil.getRealTemplatePath(uploadTemplatePath + File.separator
+                + BasicUtil.getApp().getAppId() + File.separator + fileName);
+        try {
+            FileUtils.deleteDirectory(new File(path));
+            return ResultData.build().success();
+        } catch (Exception e) {
+            return ResultData.build().error();
+        }
+    }
+
+
+    /**
+     * 显示子文件和子文件夹
+     *
+     * @param response 响应
+     * @param request  请求
+     * @return 返回文件名集合
+     */
+    @ApiOperation(value = "显示子文件和子文件夹")
+    @ApiImplicitParam(name = "skinFolderName", value = "skinFolderName", required = true, paramType = "query")
+    @GetMapping("/showChildFileAndFolder")
+    @ResponseBody
+    public ResultData showChildFileAndFolder(HttpServletResponse response, HttpServletRequest request) {
+        String uploadTemplatePath = MSProperties.upload.template;
+        List<String> folderNameList = null;
+        String skinFolderName = request.getParameter("skinFolderName");
+        String uploadFileUrl = skinFolderName;
+        String filter = BasicUtil.getRealTemplatePath(
+                uploadTemplatePath + File.separator + BasicUtil.getApp().getAppId());
+        LOG.debug("过滤路径" + filter);
+        //非法路径过滤
+        if (skinFolderName != null && (skinFolderName.contains("../") || skinFolderName.contains("..\\"))) {
+            return ResultData.build().error("非法路径");
+        }
+
+        uploadFileUrl = uploadTemplatePath + File.separator + skinFolderName;
+        File files[] = new File(BasicUtil.getRealTemplatePath(uploadFileUrl)).listFiles();
+        Map<String, Object> map = new HashMap<>();
+        if (files != null) {
+            folderNameList = new ArrayList<String>();
+            List<String> fileNameList = new ArrayList<String>();
+            for (int i = 0; i < files.length; i++) {
+                File currFile = files[i];
+
+                String temp = currFile.getPath();
+                //以当前系统分隔符作判断,将不是当前系统的分隔符替换为当前系统的
+
+                temp = temp.replace(File.separator.equals("\\") ? "/" : "\\", File.separator).replace(filter, "");
+                if (currFile.isDirectory()) {
+                    folderNameList.add(temp);
+                } else {
+                    fileNameList.add(temp);
+                }
+            }
+
+            //记录文件夹数量
+            map.put("folderNum", folderNameList.size());
+            folderNameList.addAll(fileNameList);
+            map.put("fileNameList", folderNameList);
+        }
+        map.put("uploadFileUrl", uploadFileUrl);
+        map.put("websiteId", BasicUtil.getApp().getAppId());
+        return ResultData.build().success(map);
+    }
+
+    /**
+     * 读取模版文件内容
+     *
+     * @param model
+     * @param request 请求
+     * @return 返回文件内容
+     */
+    @ApiOperation(value = "读取模版文件内容")
+    @ApiImplicitParam(name = "fileName", value = "文件名称", required = true, paramType = "query")
+    @GetMapping("/readFileContent")
+    @ResponseBody
+    @RequiresPermissions("basic:template:update")
+    public ResultData readFileContent(@ApiIgnore ModelMap model, HttpServletRequest request) {
+        String fileName = request.getParameter("fileName");
+        String filePath = fileName;
+        String uploadTemplatePath = MSProperties.upload.template;
+        //非法路径过滤
+        if (filePath != null && (filePath.contains("../") || filePath.contains("..\\"))) {
+            return ResultData.build().error("非法路径");
+        }
+        fileName = uploadTemplatePath + File.separator + filePath;
+        Map<String, Object> map = new HashMap<>();
+        if (!StringUtils.isEmpty(fileName)) {
+            map.put("fileContent", FileReader.create(new File(BasicUtil.getRealTemplatePath(fileName))).readString());
+        }
+
+        map.put("name", new File(BasicUtil.getRealTemplatePath(fileName)).getName());
+        map.put("fileName", fileName);
+        map.put("fileNamePrefix", fileName.substring(0, fileName.lastIndexOf(File.separator) + 1));
+        return ResultData.build().success(map);
+    }
+
+    /**
+     * 删除模版文件
+     * <p>
+     * 文件名称
+     *
+     * @param request 请求
+     */
+    @ApiOperation(value = "删除模版文件")
+    @ApiImplicitParam(name = "fileName", value = "文件名称", required = true, paramType = "query")
+    @LogAnn(title = "删除模版文件", businessType = BusinessTypeEnum.DELETE)
+    @PostMapping("/deleteTemplateFile")
+    @ResponseBody
+    public ResultData deleteTemplateFile(HttpServletRequest request) {
+        String uploadTemplatePath = MSProperties.upload.template;
+        String fileName = request.getParameter("fileName");
+        //非法路径过滤
+        if (fileName != null && (fileName.contains("../") || fileName.contains("..\\"))) {
+            return ResultData.build().error("非法路径");
+        }
+        fileName = uploadTemplatePath + File.separator
+                + BasicUtil.getApp().getAppId() + File.separator + fileName;
+        FileUtil.del(BasicUtil.getRealTemplatePath(fileName));
+        return ResultData.build().success();
+    }
+
+    /**
+     * 递归获取所有的html\htm文件
+     *
+     * @param list    最终返回列表集合
+     * @param fileDir 模版文件夹
+     * @param style   风格
+     */
+    private void files(List list, File fileDir, String style) {
+        if (fileDir.isDirectory()) {
+            File files[] = fileDir.listFiles();
+            for (int i = 0; i < files.length; i++) {
+                File currFile = files[i];
+                if (currFile.isFile()) {
+                    String ex = currFile.getName();
+                    if (ex.endsWith("htm") || ex.endsWith("html")) {
+                        String _pathName = new String();
+                        _pathName = files(currFile, style, _pathName);
+                        list.add(_pathName + currFile.getName());
+                    }
+                } else if (currFile.isDirectory()) {
+                    files(list, currFile, style);
+                }
+            }
+        }
+    }
+
+    /**
+     * 递归获取当前风格下所有的文件路径名称
+     *
+     * @param file
+     * @param style
+     * @param pathName
+     * @return
+     */
+    private String files(File file, String style, String pathName) {
+        if (!file.getParentFile().getName().equals(style)) {
+            pathName = file.getParentFile().getName() + "/" + pathName;
+            pathName = files(file.getParentFile(), style, pathName);
+        }
+        return pathName;
+    }
+
+
+    /**
+     * 获取当前应用的所有的模版文件夹列表
+     *
+     * @return 文件夹名称
+     */
+    private List<String> queryTemplateFile() {
+        String uploadTemplatePath = MSProperties.upload.template;
+        List<String> folderNameList = null;
+        String _path = uploadTemplatePath + File.separator
+                + BasicUtil.getApp().getAppId() + File.separator;
+        LOG.debug("当前站点:{}" , BasicUtil.getApp().getAppName() );
+        LOG.debug("当前站点模板路径_path:{}",_path);
+        String templates = BasicUtil.getRealTemplatePath(_path);
+        LOG.debug("当前站点模板路径:{}",templates);
+        File file = new File(templates);
+        LOG.debug("是否存在:{}",file.exists());
+        String[] str = file.list();
+        if (str != null) {
+            folderNameList = new ArrayList<String>();
+            for (int i = 0; i < str.length; i++) {
+                // 避免不为文件夹的文件显示
+                if (str[i].indexOf(".") < 0) {
+                    folderNameList.add(str[i]);
+                }
+            }
+        }
+        return folderNameList;
+    }
+
+    /**
+     * 校验文件后缀名是否符合要求
+     *
+     * @param fileName 文件名
+     * @return false 不合法 true 符合
+     */
+    protected boolean checkFileType(String fileName) {
+        String uploadFileDenied = MSProperties.upload.denied;
+        //校验后缀文件名
+        String[] errorType = uploadFileDenied.split(",");
+        String fileType = FileUtil.getSuffix(fileName);
+        if (StringUtils.isBlank(fileType)){
+            return false;
+        }
+        for (String type : errorType) {
+            //校验禁止上传的文件后缀名(忽略大小写)
+            if ((fileType).equalsIgnoreCase(type)) {
+                LOG.info("文件类型被拒绝:{}", fileName);
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+    /**
+     * 接口:获取当前应用下的模版文件夹列表,提供给应用设置页面调用
+     *
+     * @param request 请求
+     * @return 模版文件集合
+     */
+    @ApiOperation(value = "查询模版风格供站点选择")
+    @GetMapping("/queryAppTemplateSkin")
+    @ResponseBody
+    public ResultData queryAppTemplateSkin(HttpServletRequest request) {
+        List<String> folderNameList = this.queryTemplateFile();
+        Map map = new HashMap();
+        if (folderNameList != null) {
+            map.put("appTemplates", folderNameList);
+        }
+        return ResultData.build().success(map);
+    }
+
+
+    /**
+     * 接口:获取指定模下面所有的模版文件
+     *
+     * @param request
+     * @return
+     */
+    @ApiOperation(value = "查询模版文件供栏目选择,可指定模板名称,不传查询应用设置中选择的模板")
+    @GetMapping("/queryTemplateFileForColumn")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "appStyle", value = "可选,可以指定template下的文件夹名称", required = false, paramType = "query"),
+    })
+    @ResponseBody
+    public ResultData queryTemplateFileForColumn(HttpServletRequest request) {
+        String uploadTemplatePath = MSProperties.upload.template;
+        //优先 appStyle 接口传递过来的 模版风格
+        String appStyle = BasicUtil.getString("appStyle", BasicUtil.getApp().getAppStyle());
+        if (StringUtils.isBlank(appStyle)){
+            return ResultData.build().error();
+        }
+        String path = BasicUtil.getRealTemplatePath(uploadTemplatePath + File.separator + BasicUtil.getApp().getAppId() + File.separator);
+
+        List<File> list = FileUtil.loopFiles(path + appStyle, new FileFilter() {
+            @Override
+            public boolean accept(File pathname) {
+
+                //遇到文件乱码,获取类型会失败,需要进行异常捕获
+                try {
+                    if (FileTypeUtil.getType(pathname).equalsIgnoreCase("html") || FileTypeUtil.getType(pathname).equalsIgnoreCase("htm")) {
+                        return true;
+                    } else {
+                        return false;
+                    }
+                } catch (Exception e){
+                    return false;
+                }
+
+            }
+        });
+
+        List<String> collect = list.stream().map(file -> {
+            return file.getPath().replaceAll("\\\\","/").replace(path.replaceAll("\\\\","/"), "").substring(appStyle.length() + 1);
+        }).collect(Collectors.toList());
+
+        return ResultData.build().success(collect);
+    }
+
+
+
+}

+ 109 - 0
src/main/java/net/mingsoft/basic/action/web/CityAction.java

@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action.web;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.action.BaseAction;
+import net.mingsoft.basic.bean.CityBean;
+import net.mingsoft.basic.biz.ICityBiz;
+import net.mingsoft.basic.entity.CityEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 省市县镇村数据管理控制层
+ * @author 铭飞开发团队
+ * @version
+ * 版本号:100<br/>
+ * 创建日期:2017-7-27 14:47:29<br/>
+ * 历史修订:<br/>
+ */
+@Api(tags={"前端-基础接口"})
+@Controller("webCityAction")
+@RequestMapping("/basic/city")
+public class CityAction extends BaseAction{
+
+	/**
+	 * 注入省市县镇村数据业务层
+	 */
+	@Autowired
+	private ICityBiz cityBiz;
+
+
+	@ApiOperation(value = "查询省市县镇村数据列表")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "provinceId", value = "省/直辖市/自治区级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "provinceName", value = "省/直辖市/自治区级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityId", value = "市级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityName", value = "市级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "cityPy", value = "城市拼音首字母", required = false,paramType="query"),
+		@ApiImplicitParam(name = "countyId", value = "县/区级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "countyName", value = "县/区级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "townId", value = "街道/镇级id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "townName", value = "街道/镇级名称", required = false,paramType="query"),
+		@ApiImplicitParam(name = "villageId", value = "村委会id", required = false,paramType="query"),
+		@ApiImplicitParam(name = "villageName", value = "村委会名称", required = false,paramType="query"),
+	})
+	@RequestMapping(value ="/list",method = {RequestMethod.GET,RequestMethod.POST})
+	@ResponseBody
+	public ResultData list(@ModelAttribute @ApiIgnore CityEntity city,HttpServletResponse response, HttpServletRequest request,ModelMap model) {
+		BasicUtil.startPage();
+		List cityList = cityBiz.query(city);
+		BasicUtil.endPage(cityList);
+		return ResultData.build().success(cityList);
+	}
+
+
+	@ApiOperation(value = "获取省市县镇村数据")
+	@ApiImplicitParam(name = "id", value = "城市主键编号", required = true,paramType="query")
+	@GetMapping("/get")
+	@ResponseBody
+	public ResultData get(@ModelAttribute @ApiIgnore CityEntity city, HttpServletResponse response, HttpServletRequest request, @ApiIgnore ModelMap model){
+		if(StringUtils.isEmpty(city.getId())) {
+			return ResultData.build().error( getResString("err.error", this.getResString("id")));
+		}
+		CityEntity _city = (CityEntity)cityBiz.getEntity(Integer.parseInt(city.getId()));
+		return ResultData.build().success( _city);
+	}
+
+
+	@ApiOperation(value = "获取省市县镇村数据树形列表")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "level", value = "省市县层级,默认为3", required = false, paramType = "query",dataType = "int"),
+		@ApiImplicitParam(name = "type", value = "结构类型,默认为tree", required = false, paramType = "query")
+	})
+	@GetMapping("/query")
+	@ResponseBody
+	public ResultData query(HttpServletResponse response,HttpServletRequest request) {
+		int level = BasicUtil.getInt("level",3);//默认3级
+		String type = BasicUtil.getString("type","tree"); //默认为树形结构
+		List<CityBean> cityList = (List<CityBean>) cityBiz.queryForTree(level,type);
+		return ResultData.build().success(cityList);
+	}
+
+
+}

+ 88 - 0
src/main/java/net/mingsoft/basic/action/web/CodeAction.java

@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action.web;
+
+import cn.hutool.captcha.CaptchaUtil;
+import cn.hutool.captcha.CircleCaptcha;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.basic.constant.e.SessionConstEnum;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+
+/**
+ * 图片验证码
+ * @author by 铭软开发团队
+ * @Description TODO
+ * @date 2020/1/10 8:39
+ */
+@Api(tags={"前端-基础接口"})
+@Controller("codeAction")
+@RequestMapping("code")
+public class CodeAction {
+
+    /**
+     * 图片默认宽度
+     */
+    private int imgWidth = 100;
+
+    /**
+     * 图片默认高度
+     */
+    private int imgHeight = 50;
+
+    /**
+     * 验证码长度
+     */
+    @Value("${ms.rand-code.length:4}")
+    private int length;
+
+    /**
+     * 验证码干扰数量
+     */
+    @Value("${ms.rand-code.circle:8}")
+    private int circle;
+
+    /**
+     * 返回验证码图片
+     *
+     * @param req
+     *            HttpServletRequest对象
+     * @param res
+     *            HttpServletResponse 对象
+     * @throws ServletException
+     *             异常处理
+     * @throws IOException
+     *             异常处理
+     */
+    @ApiOperation(value = "返回验证码图片")
+    @GetMapping(produces = MediaType.IMAGE_JPEG_VALUE)
+    @ResponseBody
+    public byte[] index(HttpServletRequest req, HttpServletResponse res, HttpSession session) throws IOException {
+        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(imgWidth, imgHeight, length, circle);
+        // 将认证码存入SESSION
+        session.setAttribute(SessionConstEnum.CODE_SESSION.toString(),  captcha.getCode());
+        return captcha.getImageBytes();
+    }
+}

+ 86 - 0
src/main/java/net/mingsoft/basic/action/web/EditorAction.java

@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action.web;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.json.JSONUtil;
+import com.mingsoft.ueditor.MsUeditorActionEnter;
+import net.mingsoft.base.constant.Const;
+import net.mingsoft.base.exception.BusinessException;
+import net.mingsoft.base.util.BundleUtil;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.config.MSProperties;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 百度编辑器上传
+ *
+ * @author 铭软开发团队
+ * @date 2019年7月16日
+ * 历史修订 2022-1-21 新增normalize(),
+ * editor()方法过滤非法上传路径
+ */
+@ApiIgnore
+@Controller("ueAction")
+@RequestMapping("/static/plugins/ueditor/{version}/jsp")
+public class EditorAction {
+
+    @ResponseBody
+    @RequestMapping(value = "editor", method = {RequestMethod.GET, RequestMethod.POST})
+    public String editor(HttpServletRequest request, HttpServletResponse response, String jsonConfig) {
+        String uploadFolderPath = MSProperties.upload.path;
+        boolean enableWeb = MSProperties.upload.enableWeb;
+        if (!enableWeb) {
+            HashMap<String, String> map = new HashMap<>();
+            map.put("state","yml没有配置允许前端上传文件");
+            return JSONUtil.toJsonStr(map);
+        }
+        String rootPath = BasicUtil.getRealPath(uploadFolderPath);
+        jsonConfig = jsonConfig.replace("{ms.upload}", "/" + uploadFolderPath);
+        Map<String, Object> map = (Map<String, Object>) JSONUtil.toBean(jsonConfig,Map.class);
+        String imagePathFormat = (String) map.get("imagePathFormat");
+        imagePathFormat = FileUtil.normalize(imagePathFormat);
+
+        String filePathFormat = (String) map.get("filePathFormat");
+        filePathFormat = FileUtil.normalize(filePathFormat);
+
+        String videoPathFormat = (String) map.get("videoPathFormat");
+        videoPathFormat = FileUtil.normalize(videoPathFormat);
+
+        map.put("imagePathFormat", imagePathFormat);
+        map.put("filePathFormat", filePathFormat);
+        map.put("videoPathFormat", videoPathFormat);
+
+        jsonConfig = JSONUtil.toJsonStr(map);
+        //过滤非法上传路径
+        if (jsonConfig != null && (jsonConfig.contains("../") || jsonConfig.contains("..\\"))) {
+            throw new BusinessException(BundleUtil.getString(Const.RESOURCES,"err.error",BundleUtil.getString(net.mingsoft.basic.constant.Const.RESOURCES,"file.path")));
+        }
+        MsUeditorActionEnter actionEnter = new MsUeditorActionEnter(request, rootPath, jsonConfig, BasicUtil.getRealPath(""));
+        String json = actionEnter.exec();
+        Map jsonMap = JSONUtil.toBean(json,Map.class);
+        jsonMap.put("url","/".concat(uploadFolderPath).concat(jsonMap.get("url")+""));
+        return JSONUtil.toJsonStr(jsonMap);
+    }
+
+}

+ 73 - 0
src/main/java/net/mingsoft/basic/action/web/FileAction.java

@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action.web;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.action.BaseFileAction;
+import net.mingsoft.basic.bean.UploadConfigBean;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.config.MSProperties;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * 上传文件
+ */
+@Api(tags={"前端-基础接口"})
+@Controller
+@RequestMapping("/file")
+public class FileAction extends BaseFileAction {
+
+	@ApiOperation(value = "处理post请求上传文件")
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "uploadPath", value = "上传文件夹地址", required =false,paramType="form"),
+			@ApiImplicitParam(name = "file", value = "文件流", dataType="__file",required =false,paramType="form"),
+			@ApiImplicitParam(name = "rename", value = "是否重命名", required =false,paramType="form",defaultValue="true"),
+			@ApiImplicitParam(name = "appId", value = "上传路径是否需要拼接appId", required =false,paramType="form",defaultValue="false"),
+	})
+	@PostMapping(value = "/upload")
+	@ResponseBody
+	public ResultData upload(@ApiIgnore UploadConfigBean bean, HttpServletRequest req, HttpServletResponse res) throws IOException {
+		boolean uploadEnable = MSProperties.upload.enableWeb;
+
+		if(uploadEnable){
+			//非法路径过滤
+			if(bean.getUploadPath()!=null&&(bean.getUploadPath().contains("../")||bean.getUploadPath().contains("..\\"))){
+				return ResultData.build().error(getResString("err.error", new String[]{getResString("file.path")}));
+			}
+			// 是否需要拼接appId
+			if(bean.isAppId()){
+				bean.setUploadPath(BasicUtil.getApp().getAppId()+ File.separator+ bean.getUploadPath()) ;
+			}
+			UploadConfigBean config = new UploadConfigBean(bean.getUploadPath(),bean.getFile(),null,false,bean.isRename());
+			return this.upload(config);
+		}else {
+			return ResultData.build().error(getResString("insufficient.permissions"));
+		}
+
+	}
+
+}

+ 92 - 0
src/main/java/net/mingsoft/basic/action/web/IndexAction.java

@@ -0,0 +1,92 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action.web;
+
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.action.BaseAction;
+import net.mingsoft.basic.biz.IAppBiz;
+import net.mingsoft.basic.entity.AppEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.basic.util.SpringUtil;
+import net.mingsoft.config.MSProperties;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author by 铭软开发团队
+ * @Description TODO
+ * @date 2020/1/10 8:39
+ */
+@ApiIgnore
+@Controller("indexAction")
+public class IndexAction extends BaseAction {
+
+    private static String  INDEX = "index.html", DEFAULT = "default.html";
+    /**
+     * 注入站点业务层
+     */
+    private IAppBiz appBiz;
+
+    /**
+     * 访问站点主页
+     *
+     * @param req
+     *            HttpServletRequest对象
+     * @param res
+     *            HttpServletResponse 对象
+     * @throws ServletException
+     *             异常处理
+     * @throws IOException
+     *             异常处理
+     */
+    @ApiOperation(value = "访问站点主页")
+    @GetMapping("/msIndex")
+    public String index( HttpServletRequest req, HttpServletResponse res) throws IOException {
+        String htmlDir = MSProperties.diy.htmlDir;
+        LOG.debug("basic index");
+        // 获取用户所请求的域名地址
+
+        appBiz = SpringUtil.getBean(IAppBiz.class);
+        // 查询数据库获取域名对应Id
+        String dir = "";
+        AppEntity website = BasicUtil.getApp();
+        if (website != null) {
+            dir = StringUtils.isNotBlank(website.getAppDir())? website.getAppDir() : "";
+        } else {
+            return "";
+        }
+
+        String defaultHtmlPath = BasicUtil.getRealPath(htmlDir + File.separator + dir + File.separator + DEFAULT);
+        LOG.debug("defaultHtmlPath {}",defaultHtmlPath);
+        File file = new File(defaultHtmlPath);
+        String url = htmlDir + "/" +dir ;
+        String indexPosition = url + "/" + INDEX;
+        if (file.exists()) {
+            indexPosition = url + "/" + DEFAULT;
+        }
+        LOG.debug("indexPosition {}",indexPosition);
+
+        return "forward:"+indexPosition;
+    }
+}

+ 142 - 0
src/main/java/net/mingsoft/basic/action/web/LoginAction.java

@@ -0,0 +1,142 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.action.web;
+
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.action.BaseAction;
+import net.mingsoft.basic.biz.IAppBiz;
+import net.mingsoft.basic.biz.IManagerBiz;
+import net.mingsoft.basic.entity.ManagerEntity;
+import net.mingsoft.basic.strategy.ILoginStrategy;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.config.MSProperties;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+
+/**
+ *
+ * @ClassName: LoginAction
+ * @Description:TODO(登录的基础应用层)
+ * @author: 铭飞开发团队
+ * @date: 2015年1月27日 下午3:21:47
+ *
+ * @Copyright: 2018 www.mingsoft.net Inc. All rights reserved.
+ */
+@Api(tags={"前端-基础接口"})
+@Controller
+@RequestMapping("/${ms.manager.path}")
+public class LoginAction extends BaseAction {
+
+    /**
+     * 站点业务层
+     */
+    @Autowired
+    private IAppBiz appBiz;
+
+    @Autowired
+    private ILoginStrategy loginStrategy;
+
+
+    /**
+     * 注入管理员业务层
+     */
+    @Autowired
+    private IManagerBiz managerBiz;
+
+
+    /**
+     * 加载管理员登录界面
+     *
+     * @param request
+     *            请求对象
+     * @return 管理员登录界面地址
+     */
+    @ApiOperation(value = "加载管理员登录界面")
+    @SuppressWarnings("resource")
+    @GetMapping("/login")
+    public String login(HttpServletRequest request) {
+        String managerPath = MSProperties.manager.path;
+        Subject currentSubject = SecurityUtils.getSubject();
+        ManagerEntity user = (ManagerEntity) currentSubject.getPrincipal();
+        if (user != null && currentSubject.isAuthenticated()) {
+            return "redirect:" + managerPath + "/index.do";
+        }
+        request.setAttribute("app", BasicUtil.getApp());
+        return "/login";
+    }
+
+    /**
+     * 验证登录
+     *
+     * @param manager
+     *            管理员实体
+     * @param request
+     *            请求
+     * @param response
+     *            响应
+     */
+    @ApiOperation(value = "验证登录")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "managerName", value = "帐号", required = true, paramType = "query"),
+            @ApiImplicitParam(name = "managerPassword", value = "密码", required = true, paramType = "query"),
+    })
+    @PostMapping("/login")
+    @ResponseBody
+    public ResultData login(@ModelAttribute @ApiIgnore ManagerEntity manager, HttpServletRequest request, HttpServletResponse response) {
+        LOG.debug("basic checkLogin");
+
+        //验证码
+        if (!(checkRandCode())) {
+            return ResultData.build().error(getResString("err.error", this.getResString("rand.code")));
+        }
+        if(loginStrategy.login(manager)){
+            return ResultData.build().success().data( SecurityUtils.getSubject().getSession().getId());
+        }else {
+            return ResultData.build().error(getResString("err.error", this.getResString("manager.name.or.password")));
+        }
+
+    }
+
+    @ApiOperation(value="验证当前是否已经登录管理员")
+    @GetMapping("/checkLogin")
+    @ResponseBody
+    public ResultData checkLogin(HttpServletResponse response, HttpServletRequest request){
+        ManagerEntity managerEntity;
+        ManagerEntity manager =  BasicUtil.getManager();
+        if (manager == null || !SecurityUtils.getSubject().isAuthenticated()) {
+            return ResultData.build().error("管理员已失效!");
+        }
+        managerEntity = managerBiz.getById(manager.getId());
+        if (managerEntity != null){
+            managerEntity.setManagerPassword("");
+        }
+        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(managerEntity);
+        stringObjectMap.put("sessionId",SecurityUtils.getSubject().getSession().getId());
+        return ResultData.build().success(stringObjectMap);
+    }
+}

+ 60 - 0
src/main/java/net/mingsoft/basic/annotation/LogAnn.java

@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.annotation;
+
+import net.mingsoft.basic.constant.e.BusinessTypeEnum;
+import net.mingsoft.basic.constant.e.OperatorTypeEnum;
+
+import java.lang.annotation.*;
+
+/**
+ * 日志注解
+ * @author by 铭软开发团队
+ * @Description TODO
+ * @date 2019/11/20 9:58
+ */
+@Target({ElementType.PARAMETER, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface LogAnn {
+    /**
+     * 日志标题
+     * @return
+     */
+    String title() default "";
+
+    /**
+     * 业务类型
+     * @return
+     */
+    BusinessTypeEnum businessType() default BusinessTypeEnum.OTHER;
+
+    /**
+     * 操作人员类型
+     * @return
+     */
+    OperatorTypeEnum operatorType() default OperatorTypeEnum.MANAGE;
+
+    /**
+     * 是否保存请求的参数,如果data不需要可以设置false减少日志表的内容
+     * @return
+     */
+    boolean saveRequestData() default true;
+
+    /**
+     * 是否保存业务id,会拦截实体的getId内容
+     * @return
+     */
+    boolean saveId() default false;
+}

+ 102 - 0
src/main/java/net/mingsoft/basic/aop/BaseAop.java

@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.aop;
+
+import com.mchange.v1.util.ArrayUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+/**
+ * 切面基础
+ *
+ * @author ms dev group
+ * @version 版本号:100-000-000<br/>
+ *          创建日期:2012-03-15<br/>
+ *          历史修订:<br/>
+ */
+public abstract class BaseAop {
+    /*
+     * log4j日志记录
+     */
+    protected final Logger LOG = LoggerFactory.getLogger(this.getClass());
+
+    /**
+     * 获取切面中的class 类
+     * @param jp 拦截对象
+     * @param clazz class 类名
+     * @return 类存在则返回类否则为null
+     */
+    protected final <T> T getType(JoinPoint jp, Class<T> clazz) {
+        Object[] objs = jp.getArgs();
+        for (Object obj : objs) {
+            if (obj!= null && obj.getClass() == clazz) {
+                return (T) obj;
+            }
+        }
+        return null;
+    }
+
+    protected final <T> T getType(JoinPoint jp, Class<T> clazz, boolean hasParent) {
+        Object[] objs = jp.getArgs();
+        for (Object obj : objs) {
+            if (obj!= null && (obj.getClass() == clazz || obj.getClass().getSuperclass() == clazz)) {
+                return (T) obj;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取aop请求中所有请求参数
+     * @param jp
+     * @return
+     */
+    protected final Object getJsonParam(JoinPoint jp) {
+        Signature signature = jp.getSignature();
+        MethodSignature methodSignature = (MethodSignature) signature;
+        Method method = methodSignature.getMethod();
+		Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+		for (Annotation[] parameterAnnotation : parameterAnnotations) {
+            int paramIndex = ArrayUtils.indexOf(parameterAnnotations, parameterAnnotation);
+            for (Annotation annotation : parameterAnnotation) {
+                if (annotation instanceof RequestBody) {
+                    return jp.getArgs()[paramIndex];
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 是否存在注解,如果存在就获取
+     */
+    protected final <T extends Annotation> T getAnnotation(JoinPoint jp, Class<T> an) {
+        Signature signature = jp.getSignature();
+        MethodSignature methodSignature = (MethodSignature) signature;
+        Method method = methodSignature.getMethod();
+
+        if (method != null) {
+            return method.getAnnotation(an);
+        }
+        return null;
+    }
+}

+ 216 - 0
src/main/java/net/mingsoft/basic/aop/BaseLogAop.java

@@ -0,0 +1,216 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.aop;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.lang.Filter;
+import cn.hutool.core.lang.mutable.MutablePair;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import net.mingsoft.base.entity.BaseEntity;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.basic.annotation.LogAnn;
+import net.mingsoft.basic.biz.ILogBiz;
+import net.mingsoft.basic.constant.e.BusinessTypeEnum;
+import net.mingsoft.basic.entity.LogEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.basic.util.SpringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * @author by 铭软开发团队
+ * @Description TODO
+ * @date 2019/11/20 12:04
+ */
+@Aspect
+public abstract class BaseLogAop extends BaseAop{
+
+    /**
+     * 获取用户名
+     * @return
+     */
+    public abstract String getUserName();
+
+    /**
+     * 是否切面
+     * @return
+     */
+    public abstract boolean isCut(LogAnn log);
+
+    /**
+     * 切入点
+     */
+    @Pointcut("@annotation(net.mingsoft.basic.annotation.LogAnn)")
+    public void logPointCut()
+    { }
+
+    /**
+     * 处理完请求后执行
+     *
+     * @param joinPoint 切点
+     */
+    @AfterReturning(pointcut = "logPointCut()", returning = "result")
+    public void doAfterReturning(JoinPoint joinPoint, Object result)
+    {
+        handleLog(joinPoint, null, result);
+    }
+
+    /**
+     * 拦截异常操作
+     *
+     * @param joinPoint 切点
+     * @param e 异常
+     */
+    @AfterThrowing(value = "logPointCut()", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, Exception e)
+    {
+        handleLog(joinPoint, e, null);
+    }
+    /**
+     * 成功状态
+     */
+    private static final String SUCCESS="success";
+    /**
+     * 失败状态
+     */
+    private static final String ERROR="error";
+
+    /**
+     * 日志业务层
+     */
+    @Autowired
+    private ILogBiz logBiz;
+
+    private static final Logger LOG = LoggerFactory.getLogger(SystemLogAop.class);
+
+    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object result) {
+        try{
+            // 获得注解
+            LogAnn controllerLog = getAnnotation(joinPoint, LogAnn.class);
+            if (controllerLog == null){
+                return;
+            }
+            if(!isCut(controllerLog)){
+                return;
+            }
+
+            LogEntity logEntity = new LogEntity();
+            //是否保存业务id
+            if (controllerLog.saveId()){
+                BaseEntity baseEntity = getType(joinPoint, BaseEntity.class,true);
+                if (baseEntity != null){
+                    logEntity.setBusinessId(baseEntity.getId());
+                } else {// 批量操作的情况
+                    ArrayList baseEntities = getType(joinPoint, ArrayList.class);
+                    if (CollectionUtil.isNotEmpty(baseEntities)) {
+                        List<String> ids = (List<String>) baseEntities.stream().map(entity -> {
+                            if (entity instanceof BaseEntity) {
+                                return ((BaseEntity) entity).getId();
+                            }
+                            return null;
+                        }).collect(Collectors.toList());
+                        ids.remove(null);
+                        logEntity.setBusinessId(StrUtil.join(",",ids));
+                    }
+                }
+            }
+            logEntity.setLogUser(getUserName());
+            logEntity.setLogStatus(SUCCESS);
+            // 请求的地址
+            String ip = BasicUtil.getIp();
+            //设置IP
+            logEntity.setLogIp(ip);
+
+            //设置返回参数
+            logEntity.setLogResult(JSONUtil.parseObj(result).toJSONString(0, new Filter<MutablePair<Object, Object>>() {
+                @Override
+                public boolean accept(MutablePair<Object, Object> objectObjectMutablePair) {
+                    return !objectObjectMutablePair.getKey().toString().equalsIgnoreCase("id");
+                }
+            }));
+            //设置请求地址
+            logEntity.setLogUrl(SpringUtil.getRequest().getRequestURI());
+
+            if (e != null){
+                logEntity.setLogStatus(ERROR);
+                logEntity.setLogErrorMsg(StringUtils.substring(e.getMessage(), 0, 4000));
+            }
+
+            // 登录失败特殊处理
+            if (BusinessTypeEnum.LOGIN.getLabel().equalsIgnoreCase(controllerLog.title())){
+                ResultData resultData = (ResultData) result;
+                if (!BooleanUtil.toBoolean(resultData.get("result").toString())){
+                    logEntity.setLogStatus(ERROR);
+                    logEntity.setLogErrorMsg(String.valueOf(resultData.get("msg")));
+                }
+            }
+
+            // 设置方法名称
+            String className = joinPoint.getTarget().getClass().getName();
+            String methodName = joinPoint.getSignature().getName();
+            logEntity.setLogMethod(className + "." + methodName + "()");
+            // 设置请求方式
+            logEntity.setLogRequestMethod(SpringUtil.getRequest().getMethod());
+
+            // 设置action动作
+            logEntity.setLogBusinessType(controllerLog.businessType().name().toLowerCase());
+            // 设置标题
+            logEntity.setLogTitle(controllerLog.title());
+            // 设置操作人类别
+            logEntity.setLogUserType(controllerLog.operatorType().name().toLowerCase());
+            // 是否需要保存request,参数和值
+            if (controllerLog.saveRequestData()){
+                // 获取参数的信息,传入到数据库中。
+                boolean isJson =StringUtils.isNotBlank(SpringUtil.getRequest().getContentType())&&MediaType.valueOf(SpringUtil.getRequest().getContentType()).includes(MediaType.APPLICATION_JSON);
+              //如果是json请求参数需要获取方法体上的参数
+               if(isJson){
+                   Object jsonParam = getJsonParam(joinPoint);
+                   if(ObjectUtil.isNotNull(jsonParam)){
+                       String jsonString = JSONUtil.toJsonPrettyStr(jsonParam);
+                       logEntity.setLogParam(jsonString);
+                   }
+               }else {
+                   Map<String, String[]> map = SpringUtil.getRequest().getParameterMap();
+                   String params = JSONUtil.toJsonPrettyStr(map);
+                   logEntity.setLogParam(params);
+               }
+            }
+            logEntity.setCreateDate(new Date());
+            logBiz.saveData(logEntity);
+        }
+        catch (Exception exp){
+            LOG.error("日志记录错误:{}", exp.getMessage());
+            exp.printStackTrace();
+        }
+    }
+
+}

+ 218 - 0
src/main/java/net/mingsoft/basic/aop/FileVerifyAop.java

@@ -0,0 +1,218 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+package net.mingsoft.basic.aop;
+
+import cn.hutool.core.io.FileTypeUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.file.FileNameUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import net.mingsoft.base.constant.Const;
+import net.mingsoft.base.entity.ResultData;
+import net.mingsoft.base.exception.BusinessException;
+import net.mingsoft.base.util.BundleUtil;
+import net.mingsoft.basic.bean.UploadConfigBean;
+import net.mingsoft.basic.util.BasicUtil;
+import net.mingsoft.config.MSProperties;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
+import org.apache.commons.compress.utils.IOUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 验证zip是否合法的aop
+ * 重写basic增加自定义配置
+ */
+@Component
+@Aspect
+public class FileVerifyAop extends BaseAop{
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(FileVerifyAop.class);
+
+
+    /**
+     * 切入点
+     */
+    @Pointcut("execution(* net.mingsoft.basic.action.ManageFileAction.upload(..)) || " +
+            "execution(* net.mingsoft.basic.action.ManageFileAction.uploadTemplate(..))")
+    public void uploadPointCut(){}
+
+
+    /**
+     * 后台上传文件的时候,将验证zip里的文件
+     * @param joinPoint
+     * @return
+     * @throws Throwable
+     */
+    @Around("uploadPointCut()")
+    public Object uploadAop(ProceedingJoinPoint joinPoint) throws Throwable {
+        UploadConfigBean bean = super.getType(joinPoint, UploadConfigBean.class);
+        //检查文件类型
+        String uploadFileName = FileNameUtil.cleanInvalid(bean.getFile().getOriginalFilename());
+        if (StringUtils.isBlank(uploadFileName)) {
+            return ResultData.build().error("文件名不能为空!");
+        }
+        InputStream inputStream = bean.getFile().getInputStream();
+
+        //文件的真实类型
+        String mimeType = BasicUtil.getMimeType(inputStream,uploadFileName);
+
+        //校验压缩包里的文件
+        if ("zip".equalsIgnoreCase(mimeType)){
+            try {
+                checkZip(bean.getFile(),false);
+            } catch (Exception e) {
+                return ResultData.build().error(e.getMessage());
+            }
+        }
+        return joinPoint.proceed();
+    }
+
+    /**
+     * web上传文件的时候,将验证zip里的文件
+     * @param joinPoint
+     * @return
+     * @throws Throwable
+     */
+    @Around("execution(* net.mingsoft.basic.action.web.FileAction.upload(..))")
+    public Object WebUploadAop(ProceedingJoinPoint joinPoint) throws Throwable {
+        UploadConfigBean bean = super.getType(joinPoint, UploadConfigBean.class);
+        //检查文件类型
+        String uploadFileName = FileNameUtil.cleanInvalid(bean.getFile().getOriginalFilename());
+        if (StringUtils.isBlank(uploadFileName)) {
+            return ResultData.build().error("文件名不能为空!");
+        }
+        InputStream inputStream = bean.getFile().getInputStream();
+
+        //文件的真实类型
+        String mimeType = BasicUtil.getMimeType(inputStream,uploadFileName);
+
+        //校验压缩包里的文件
+        if ("zip".equalsIgnoreCase(mimeType)){
+            try {
+                checkZip(bean.getFile(),true);
+            } catch (Exception e) {
+                return ResultData.build().error(e.getMessage());
+            }
+        }
+        return joinPoint.proceed();
+    }
+
+
+    /**
+     * 检查压缩包
+     */
+    private void checkZip(MultipartFile multipartFile, boolean isWeb) throws Exception{
+        //创建临时解压文件夹
+        File tempFilePath = FileUtil.mkdir(FileUtil.getTmpDirPath()+"/Zip"+IdUtil.simpleUUID());
+        File zipFile = FileUtil.file(tempFilePath.getAbsolutePath() + "/" + IdUtil.simpleUUID() +".zip");
+        InputStream inputStream = multipartFile.getInputStream();
+        FileUtils.copyInputStreamToFile(inputStream, zipFile);
+
+        try {
+            unzip(zipFile,tempFilePath.getAbsolutePath());
+            //获取文件夹下所有文件
+            List<File> files = FileUtil.loopFiles(tempFilePath);
+            //移除压缩包自身
+            files.remove(zipFile);
+            //禁止上传的格式
+            List<String> deniedList = Arrays.stream(MSProperties.upload.denied.split(",")).map(String::toLowerCase).collect(Collectors.toList());
+            for (File file : files) {
+                FileInputStream fileInputStream = new FileInputStream(file);
+                //文件的类型 受文件幻数影响
+                String fileType = FileTypeUtil.getType(file).toLowerCase();
+                // 文件后缀名
+                String fileSuffixName = FileUtil.getSuffix(file);
+                //通过yml的配置检查文件格式是否合法
+                if (deniedList.contains(fileSuffixName)){
+                    IOUtils.closeQuietly(fileInputStream);
+                    throw new RuntimeException(StrUtil.format("压缩包内文件{}后缀{}禁止上传",file.getName(),fileSuffixName));
+                }else if (deniedList.contains(fileType)){
+                        IOUtils.closeQuietly(fileInputStream);
+                        throw new RuntimeException(StrUtil.format("压缩包内文件{}的类型{}禁止上传",file.getName(),fileType));
+
+                }
+
+               IOUtils.closeQuietly(fileInputStream);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            FileUtil.del(tempFilePath);
+        }
+
+    }
+
+
+    /**
+     * 解压压缩包
+     * @param file
+     * @param descDir
+     * @throws IOException
+     */
+    private  void unzip(File file, String descDir) throws IOException {
+        ZipArchiveInputStream inputStream = new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(file)));
+        File pathFile = new File(descDir);
+        if (!pathFile.exists()) {
+            pathFile.mkdirs();
+        }
+        ZipArchiveEntry entry = null;
+        while ((entry = inputStream.getNextZipEntry()) != null) {
+            if (entry.getName() == null && (entry.getName().contains("../") || entry.getName().contains("..\\"))) {
+                throw new BusinessException(BundleUtil.getString(Const.RESOURCES,"err.error",BundleUtil.getString(net.mingsoft.basic.constant.Const.RESOURCES,"file.name")));
+            }
+            String[] dirs = entry.getName().split("/");
+            String tempDir = descDir;
+            for(String dir:dirs) {
+                if(dir.indexOf(".")==-1) {
+                    tempDir += File.separator.concat(dir);
+                    FileUtil.mkdir(tempDir);
+                }
+            }
+            if (entry.isDirectory()) {
+                File directory = new File(descDir, entry.getName());
+                directory.mkdirs();
+            } else {
+                OutputStream os = null;
+                try {
+                    LOGGER.debug("file name => {}",entry.getName());
+                    try {
+                        os = new BufferedOutputStream(new FileOutputStream(new File(descDir, entry.getName())));
+                        //输出文件路径信息
+                        IOUtils.copy(inputStream, os);
+                    } catch (FileNotFoundException e) {
+                        LOGGER.error("解压{}不存在",entry.getName());
+                        e.printStackTrace();
+
+                    }
+                } finally {
+                    IOUtils.closeQuietly(os);
+                }
+            }
+        }
+        IOUtils.closeQuietly(inputStream);
+    }
+}

+ 59 - 0
src/main/java/net/mingsoft/basic/aop/ManagerPasswordAop.java

@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+package net.mingsoft.basic.aop;
+
+import cn.hutool.crypto.SecureUtil;
+import net.mingsoft.basic.bean.ManagerModifyPwdBean;
+import net.mingsoft.basic.biz.IManagerBiz;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * @Author: xierz
+ * @Description:
+ * @Date: Create in 2021/03/13 8:40
+ */
+@Component
+@Aspect
+public class ManagerPasswordAop extends BaseAop {
+
+
+    @Resource
+    IManagerBiz managerBiz;
+
+    @Pointcut("execution(* net.mingsoft.basic.action.MainAction.updatePassword(..))")
+    public void updatePassword() {
+    }
+
+    /**
+     * 修改密码时候,将密码md5处理
+     * @param joinPoint
+     * @return
+     * @throws Throwable
+     */
+    @Around("updatePassword()")
+    public Object updatePassword(ProceedingJoinPoint joinPoint) throws Throwable {
+        LOG.debug("basic ManagerPasswordAop 修改密码为md5");
+        ManagerModifyPwdBean managerModifyPwdBean = super.getType(joinPoint, ManagerModifyPwdBean.class);
+        managerModifyPwdBean.setOldManagerPassword(SecureUtil.md5(managerModifyPwdBean.getOldManagerPassword()));
+        return joinPoint.proceed();
+    }
+
+
+
+}

+ 89 - 0
src/main/java/net/mingsoft/basic/aop/SaveOrUpdateAop.java

@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.aop;
+
+import cn.hutool.core.util.ObjectUtil;
+import net.mingsoft.basic.entity.ManagerEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Field;
+import java.util.Date;
+
+/**
+ * 拦截保存更新方法,设置操作人和时间
+ * @author by Administrator
+ * @Description TODO
+ * @date 2019/11/12 10:14
+ */
+@Component
+@Aspect
+public class SaveOrUpdateAop extends BaseAop {
+
+    @Pointcut("execution(* net.mingsoft..*Action.save(..))")
+    public void save() {
+
+    }
+
+    @Pointcut("execution(* net.mingsoft..*Action.update(..))")
+    public void update() {
+    }
+
+    @Before("save()")
+    public void save(JoinPoint jp) { setField(jp, "createDate", new Date());
+        setField(jp, "updateDate", new Date());
+        ManagerEntity manager = BasicUtil.getManager();
+        if (manager != null) {
+            setField(jp, "createBy", manager.getId());
+        }
+
+    }
+
+
+    @Before("update()")
+    public void update(JoinPoint jp) {
+        setField(jp, "updateDate", new Date());
+        ManagerEntity manager = BasicUtil.getManager();
+        if (manager != null) {
+            setField(jp, "updateBy", manager.getId());
+        }
+    }
+
+
+    private void setField(JoinPoint jp, String name, Object obj) {
+        try {
+            Object[] objs = jp.getArgs();
+            if (objs.length == 0 || ObjectUtil.isNull(objs[0])) {
+                return;
+            }
+            //获取对象所有字段
+            Field[] allFields = BasicUtil.getAllFields(objs[0]);
+            for (Field field : allFields) {
+                //判断是否存在
+                if (name.equals(field.getName())) {
+                    field.setAccessible(true);
+                    //设置时间
+                    field.set(objs[0], obj);
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Aop错误:", e);
+        }
+    }
+
+}

+ 47 - 0
src/main/java/net/mingsoft/basic/aop/SystemLogAop.java

@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.aop;
+
+import net.mingsoft.basic.annotation.LogAnn;
+import net.mingsoft.basic.constant.e.OperatorTypeEnum;
+import net.mingsoft.basic.entity.ManagerEntity;
+import net.mingsoft.basic.util.BasicUtil;
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * @author by 铭软开发团队
+ * @Description TODO
+ * @date 2019/11/20 10:28
+ */
+@Component
+public class SystemLogAop extends BaseLogAop{
+
+
+    @Override
+    public String getUserName() {
+        //后台用户获取用户名
+        ManagerEntity managerSession = BasicUtil.getManager();
+        if(managerSession==null) {
+            return "";
+        }
+        return managerSession.getManagerName();
+    }
+
+    @Override
+    public boolean isCut(LogAnn log) {
+        //只有后台用户操作才走这个AOP
+        return log.operatorType() == OperatorTypeEnum.MANAGE;
+    }
+}

+ 80 - 0
src/main/java/net/mingsoft/basic/bean/CityBean.java

@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.bean;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 城市数据格式bean
+ * @author qiu
+ *
+ */
+
+public class CityBean implements Serializable {
+
+
+	/**
+	 * 城市id
+	 */
+	private Long id;
+
+	/**
+	 * 城市名称
+	 */
+	private String name;
+
+	/**
+	 * 父级id
+	 */
+	private Long parentId;
+
+	/**
+	 * 子城市数据集合
+	 */
+	private List<CityBean> childrensList;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Long getParentId() {
+		return parentId;
+	}
+
+	public void setParentId(Long parentId) {
+		this.parentId = parentId;
+	}
+
+	public List<CityBean> getChildrensList() {
+		return childrensList;
+	}
+
+	public void setChildrensList(List<CityBean> childrensList) {
+		this.childrensList = childrensList;
+	}
+
+}

+ 64 - 0
src/main/java/net/mingsoft/basic/bean/EUListBean.java

@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.bean;
+
+import java.util.List;
+
+/**
+ *
+ * 给返回json对象,支持分页
+ *
+ * @author 铭飞团队
+ * @version 版本号:<br/>
+ *          创建日期:2016年6月2日<br/>
+ *          历史修订:<br/>
+ */
+public class EUListBean {
+
+	private int total;
+
+	private List rows;
+
+	// 需要一个空的构造器防止fastJson初始化报错
+	public EUListBean() {
+
+	}
+
+	public EUListBean(List rows, int total) {
+		this.total = total;
+		this.rows = rows;
+	}
+
+
+	public int getTotal() {
+		return total;
+	}
+
+
+	public void setTotal(int total) {
+		this.total = total;
+	}
+
+
+	public List getRows() {
+		return rows;
+	}
+
+
+	public void setRows(List rows) {
+		this.rows = rows;
+	}
+
+}

+ 61 - 0
src/main/java/net/mingsoft/basic/bean/ListBean.java

@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2012-present 铭软科技(mingsoft.net)
+ * 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
+ * 遵循 铭软科技《服务协议》中的《保密条款》
+ */
+
+
+
+
+
+
+
+
+
+package net.mingsoft.basic.bean;
+
+import com.github.pagehelper.PageInfo;
+
+import java.util.List;
+
+/**
+ * 
+ * 给返回json对象,支持分页
+ * 
+ * @author 铭飞团队
+ * @version 版本号:<br/>
+ *          创建日期:2016年6月2日<br/>
+ *          历史修订:<br/>
+ */
+public class ListBean {
+
+	private PageInfo page;
+
+	private List list;
+
+	public ListBean(List list) {
+		this.list = list;
+	}
+
+	public ListBean(List list, PageInfo page) {
+		this.page = page;
+		this.list = list;
+	}
+
+	public PageInfo getPage() {
+		return page;
+	}
+
+	public void setPage(PageInfo page) {
+		this.page = page;
+	}
+
+	public List getList() {
+		return list;
+	}
+
+	public void setList(List list) {
+		this.list = list;
+	}
+
+}

+ 0 - 0
src/main/java/net/mingsoft/basic/bean/LogBean.java


Some files were not shown because too many files changed in this diff