huangxiao hace 1 mes
padre
commit
2309ca8e67

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 9
doc/backup.json


+ 0 - 0
doc/client.txt


+ 0 - 22
src/test/java/mingsoft/Info.java

@@ -1,22 +0,0 @@
-package mingsoft;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-@Getter
-@AllArgsConstructor
-public enum Info {
-    BOOTH("展位", "BOOTH"),
-    EXHIBITION("展会", "EXHIBITION"),
-    EXHIBITOR("展商", "EXHIBITOR"),
-    PEOPLE_INFO("扩展会员信息", "PEOPLE_INFO"),
-    ENTERPRISE("企业管理", "ENTERPRISE"),
-    ANNOUNCEMENT("公告管理", "ANNOUNCEMENT"),
-    INVESTMENT_PROMOTION("招商管理", "INVESTMENT_PROMOTION"),
-    RECRUITMENT("人才招聘", "RECRUITMENT"),
-    RECRUITMENT_SUBMISSION("招聘投递", "RECRUITMENT_SUBMISSION"),
-    MESSAGE("留言", "MESSAGE");
-
-    private final String name;
-    private final String table;
-}

+ 26 - 17
src/test/java/mingsoft/Main.java

@@ -1,24 +1,33 @@
 package mingsoft;
 
-import java.util.Map;
-
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.ZipUtil;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Optional;
+
+/**
+ * 对<a href="https://code.mingsoft.net/">低代码平台</a>的伪破解
+ *
+ * @author hosea
+ * @date 2025-12-24
+ */
 public class Main {
-    private static final Map<Info, MingsoftData> BACKUP = MingsoftClient.loadBackup("D:\\idea\\hosea\\tf\\MCMS\\doc\\backup.json");
-    private static final MingsoftClient CLIENT = new MingsoftClient("token", "session");
+    private static final File doc = Optional.ofNullable(Main.class.getResource("/"))
+            .map(URL::getFile)
+            .map(File::new)
+            .map(File::getParentFile)
+            .map(File::getParentFile)
+            .map(file -> new File(file, "doc"))
+            .orElseThrow();
+    private static final MingsoftService service = MingsoftService.of(FileUtil.getCanonicalPath(new File(doc, "client.txt")), FileUtil.getCanonicalPath(new File(doc, "backup.json"))).orElseThrow();
 
     public static void main(String[] args) {
-    }
-
-    /**
-     * 把现有的某个,还原到最后一个
-     */
-    public static boolean restore(Info old) {
-        MingsoftData back = BACKUP.get(old).clone();
-        back.setId("16094");
-        return CLIENT.update(back);
+        File zip = new File(doc, "tf.zip");
+        File unzip = new File(doc, "unzip");
+        FileUtil.del(zip);
+        FileUtil.del(unzip);
+        service.saveDownloadCode(zip).ifPresent(file -> ZipUtil.unzip(file, unzip));
     }
 }
-
-
-
-

+ 0 - 103
src/test/java/mingsoft/MingsoftClient.java

@@ -1,103 +0,0 @@
-package mingsoft;
-
-import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.EnumUtil;
-import cn.hutool.http.HttpResponse;
-import cn.hutool.http.HttpUtil;
-import cn.hutool.http.Method;
-import cn.hutool.json.JSONArray;
-import cn.hutool.json.JSONObject;
-import lombok.AllArgsConstructor;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
-@AllArgsConstructor
-public class MingsoftClient {
-    private final String token;
-    private final String sessionId;
-
-    /**
-     * 查列表
-     *
-     * @return
-     */
-    public Map<Info, MingsoftData> list() {
-        String url = "https://code.mingsoft.net/code-proxy/people/mcode/projectModelObject/list.do?projectId=1980198434053410817";
-        try (HttpResponse response = HttpUtil.createRequest(Method.GET, url).addHeaders(createHeaders()).execute()) {
-            JSONObject json = new JSONObject(response.body());
-            if (json.isEmpty()) {
-                return null;
-            }
-            if (json.getInt("code") != 200) {
-                System.err.println(json);
-                return null;
-            }
-            return from(json.getJSONArray("data"));
-        }
-    }
-
-    /**
-     * 加载备份
-     */
-    public static Map<Info, MingsoftData> loadBackup(String jsonFile) {
-        String json = FileUtil.readUtf8String(jsonFile);
-        return from(new JSONObject(json).getJSONArray("data"));
-    }
-
-    /**
-     * 修改
-     */
-    public boolean update(MingsoftData data) {
-        String url = "https://code.mingsoft.net/code-proxy/people/mcode/projectModelObject/update.do";
-        Map<String, Object> param = new HashMap<>();
-        data.setPmoDatetime(null);
-        BeanUtil.beanToMap(data, param, false, true);
-        Map<String, String> headers = createHeaders();
-        headers.put("Content-Type", "application/x-www-form-urlencoded");
-        try (HttpResponse response = HttpUtil.createRequest(Method.POST, url)
-                .addHeaders(headers)
-                .form(param)
-                .execute()) {
-            JSONObject json = new JSONObject(response.body());
-            if (json.isEmpty()) {
-                return false;
-            }
-            if (json.getInt("code") != 200) {
-                System.err.println(json);
-                return false;
-            }
-            return true;
-        }
-    }
-
-    private static Map<Info, MingsoftData> from(JSONArray array) {
-        return StreamSupport.stream(array.jsonIter().spliterator(), false)
-                .map(item -> item.toBean(MingsoftData.class))
-                .collect(Collectors.toMap(mingsoftData -> EnumUtil.fromStringQuietly(Info.class, mingsoftData.getPmoTableName().toUpperCase()), v -> v));
-    }
-
-    private Map<String, String> createHeaders() {
-        Map<String, String> headers = new HashMap<>();
-        headers.put("Accept", "application/json, text/plain, */*");
-        headers.put("Accept-Encoding", "gzip, deflate, br, zstd");
-        headers.put("Accept-Language", "zh-CN,zh;q=0.9");
-        headers.put("Cache-Control", "no-cache");
-        headers.put("Connection", "keep-alive");
-        headers.put("Cookie", "token=" + token + "; JSESSIONID=" + sessionId);
-        headers.put("Pragma", "no-cache");
-        headers.put("Referer", "https://code.mingsoft.net/");
-        headers.put("Sec-Fetch-Dest", "empty");
-        headers.put("Sec-Fetch-Mode", "cors");
-        headers.put("Sec-Fetch-Site", "same-origin");
-        headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36");
-        headers.put("X-Requested-With", "XMLHttpRequest");
-        headers.put("sec-ch-ua", "\"Chromium\";v=\"142\", \"Google Chrome\";v=\"142\", \"Not_A Brand\";v=\"99\"");
-        headers.put("sec-ch-ua-mobile", "?0");
-        headers.put("sec-ch-ua-platform", "\"Windows\"");
-        return headers;
-    }
-}

+ 212 - 0
src/test/java/mingsoft/MingsoftService.java

@@ -0,0 +1,212 @@
+package mingsoft;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.EnumUtil;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import mingsoft.client.Info;
+import mingsoft.client.MingsoftClient;
+import mingsoft.client.MingsoftData;
+import mingsoft.client.MingsoftPreView;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * 操作封装
+ *
+ * @param client 客户端
+ * @param codes  本地代码备份
+ * @author hosea
+ * @date 2025-12-24
+ */
+public record MingsoftService(MingsoftClient client, Map<Info, MingsoftData> codes) {
+    public MingsoftService {
+        Assert.notNull(client, "客户端不能为空");
+    }
+
+    /**
+     * 创建
+     *
+     * @param config   客户端配置
+     * @param jsonFile 本地代码备份
+     */
+    public static Optional<MingsoftService> of(String config, String jsonFile) {
+        return MingsoftClient.of(config)
+                .flatMap(client -> of(client, jsonFile));
+    }
+
+    /**
+     * 创建
+     *
+     * @param client   客户端
+     * @param jsonFile 本地代码备份
+     */
+    public static Optional<MingsoftService> of(MingsoftClient client, String jsonFile) {
+        return loadLocalCodeBackup(jsonFile)
+                .map(codes -> new MingsoftService(client, codes));
+    }
+
+    /**
+     * 加载本地代码备份
+     *
+     * @param jsonFile 备份代码的JSON文件
+     */
+    public static Optional<Map<Info, MingsoftData>> loadLocalCodeBackup(String jsonFile) {
+        return Optional.ofNullable(jsonFile)
+                .map(FileUtil::readUtf8String)
+                .map(JSONObject::new)
+                .map(json -> json.getJSONArray("data"))
+                .map(MingsoftService::from);
+    }
+
+    /**
+     * 查服务器上的代码
+     */
+    public Optional<Map<Info, MingsoftData>> queryCodes() {
+        return client.list().map(MingsoftService::from);
+    }
+
+    /**
+     * 复制代码,永远还原到{@link Info#FORM_ID}这个表单ID
+     * <p>
+     * {@link #copy(Info, Info, String)}
+     *
+     * @param old  旧的
+     * @param news 新的
+     */
+    public boolean copy(Info old, Info news) {
+        return copy(old, news, Info.FORM_ID);
+    }
+
+    /**
+     * 复制代码
+     * <p>
+     * 从{@link #codes}备份中取是旧的代码
+     * <p>
+     * 然后设置新的信息进去
+     * <p>
+     * 还原到服务器上指定ID的表单
+     *
+     * @param old  旧的
+     * @param news 新的
+     * @param id   表单ID
+     */
+    public boolean copy(Info old, Info news, String id) {
+        return update(id, codes.get(old).clone().info(news));
+    }
+
+    /**
+     * 还原代码,永远还原到{@link Info#FORM_ID}这个表单ID
+     * <p>
+     * {@link #restore(Info, String)}
+     *
+     * @param old 旧的
+     */
+    public boolean restore(Info old) {
+        return restore(old, Info.FORM_ID);
+    }
+
+    /**
+     * 还原代码
+     * <p>
+     * 从{@link #codes}备份中取是旧的代码
+     * <p>
+     * 还原到服务器上指定ID的表单
+     *
+     * @param old 旧的
+     * @param id  表单ID
+     */
+    public boolean restore(Info old, String id) {
+        return update(id, codes.get(old));
+    }
+
+    /**
+     * 修改指定表单ID的代码
+     *
+     * @param id   表单ID
+     * @param code 代码
+     */
+    public boolean update(String id, MingsoftData code) {
+        return client.update(code.clone().setId(id)).isPresent();
+    }
+
+    /**
+     * 下载{@link Info#FORM_ID}代码
+     */
+    public Optional<byte[]> downloadCode() {
+        return downloadCode(Info.FORM_ID);
+    }
+
+    /**
+     * 下载代码
+     *
+     * @param ids 表单ID
+     */
+    public Optional<byte[]> downloadCode(String... ids) {
+        return Optional.ofNullable(ids)
+                .filter(ArrayUtil::isNotEmpty)
+                .flatMap(client::download);
+    }
+
+    /**
+     * 保存下载{@link Info#FORM_ID}代码
+     *
+     * @param saveFile 保存的文件,如果已经存在,则不会保存
+     */
+    public Optional<File> saveDownloadCode(File saveFile) {
+        return saveDownloadCode(saveFile, Info.FORM_ID);
+    }
+
+    /**
+     * 保存下载代码
+     *
+     * @param saveFile 保存的文件,如果已经存在,则不会保存
+     * @param ids      表单ID
+     */
+    public Optional<File> saveDownloadCode(File saveFile, String... ids) {
+        return Optional.ofNullable(saveFile)
+                .filter(file -> !file.exists())
+                .map(file -> {
+                    FileUtil.mkParentDirs(file);
+                    return file;
+                })
+                .flatMap(file -> downloadCode(ids).map(bytes -> FileUtil.writeBytes(bytes, file)));
+    }
+
+    /**
+     * 预览{@link Info#FORM_ID}代码
+     */
+    public Stream<MingsoftPreView> previewCode() {
+        return previewCode(Info.FORM_ID);
+    }
+
+    /**
+     * 预览代码
+     *
+     * @param id 表单ID
+     */
+    public Stream<MingsoftPreView> previewCode(String id) {
+        return client.preview(id)
+                .stream()
+                .map(JSONArray::jsonIter)
+                .map(Iterable::spliterator)
+                .flatMap(iter -> StreamSupport.stream(iter, false))
+                .map(item -> item.toBean(MingsoftPreView.class));
+    }
+
+    /**
+     * 把JSON格式化转实体
+     */
+    private static Map<Info, MingsoftData> from(JSONArray array) {
+        return StreamSupport.stream(array.jsonIter().spliterator(), false)
+                .map(item -> item.toBean(MingsoftData.class))
+                .collect(Collectors.toMap(mingsoftData -> EnumUtil.fromStringQuietly(Info.class, mingsoftData.getPmoTableName().toUpperCase()), v -> v));
+    }
+}

+ 58 - 0
src/test/java/mingsoft/client/Info.java

@@ -0,0 +1,58 @@
+package mingsoft.client;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 业务信息
+ *
+ * @author hosea
+ * @date 2025-12-24
+ */
+@Getter
+@AllArgsConstructor
+public enum Info {
+    BOOTH("展位", "BOOTH", "15957"),
+    EXHIBITION("展会", "EXHIBITION", "15958"),
+    EXHIBITOR("展商", "EXHIBITOR", "15959"),
+    PEOPLE_INFO("扩展会员信息", "PEOPLE_INFO", "15962"),
+    ENTERPRISE("企业管理", "ENTERPRISE"),
+    ANNOUNCEMENT("公告管理", "ANNOUNCEMENT"),
+    INVESTMENT_PROMOTION("招商管理", "INVESTMENT_PROMOTION"),
+    RECRUITMENT("人才招聘", "RECRUITMENT"),
+    RECRUITMENT_SUBMISSION("招聘投递", "RECRUITMENT_SUBMISSION"),
+    MESSAGE("留言", "MESSAGE");
+
+    Info(String name, String table) {
+        this(name, table, null);
+    }
+
+    /**
+     * 固定表单ID
+     */
+    public final static String FORM_ID = "16094";
+    /**
+     * 项目
+     */
+    public final static String PROJECT_ID = "1980198434053410817";
+    /**
+     * 用户
+     */
+    public final static String PEOPLE_ID = "1980170321679396866";
+    /**
+     * 框架ID
+     */
+    public final static String CTG_ID = "1783050531725975553";
+    /**
+     * 名称
+     */
+    private final String name;
+    /**
+     * 表名
+     */
+    private final String table;
+    /**
+     * 表单ID
+     */
+    private final String id;
+}

+ 150 - 0
src/test/java/mingsoft/client/MingsoftClient.java

@@ -0,0 +1,150 @@
+package mingsoft.client;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpStatus;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.http.Method;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * 客户端操作
+ *
+ * @param token 登录标识
+ * @author hosea
+ * @date 2025-12-24
+ */
+public record MingsoftClient(String token) {
+    public MingsoftClient {
+        Assert.notBlank(token, "登录标识不能为空");
+    }
+
+    /**
+     * 读取配置文件,初始化客户端
+     */
+    public static Optional<MingsoftClient> of(String config) {
+        return Optional.ofNullable(config)
+                .map(FileUtil::readUtf8String)
+                .map(MingsoftClient::new);
+    }
+
+    /**
+     * 查列表
+     */
+    public Optional<JSONArray> list() {
+        String url = "https://code.mingsoft.net/code-proxy/people/mcode/projectModelObject/list.do?projectId=" + Info.PROJECT_ID;
+        try (HttpResponse response = HttpUtil.createRequest(Method.GET, url).addHeaders(createHeaders()).execute()) {
+            return getResponseData(response);
+        }
+    }
+
+    /**
+     * 修改
+     */
+    public Optional<JSONObject> update(MingsoftData data) {
+        String url = "https://code.mingsoft.net/code-proxy/people/mcode/projectModelObject/update.do";
+        Map<String, Object> param = new HashMap<>();
+        data.setPmoDatetime(null);
+        BeanUtil.beanToMap(data, param, false, true);
+        Map<String, String> headers = createHeaders();
+        headers.put("Content-Type", "application/x-www-form-urlencoded");
+        try (HttpResponse response = HttpUtil.createRequest(Method.POST, url)
+                .addHeaders(headers)
+                .form(param)
+                .execute()) {
+            return checkResponse(response);
+        }
+    }
+
+    /**
+     * 下载
+     */
+    public Optional<byte[]> download(String... ids) {
+        String url = "https://code.mingsoft.net/code-proxy/people/download.do";
+        Map<String, Object> param = new HashMap<>();
+        param.put("projectModelIds", String.join(",", ids));
+        param.put("id", Info.PROJECT_ID);
+        param.put("ctgId", Info.CTG_ID);
+        try (HttpResponse response = HttpUtil.createRequest(Method.GET, url)
+                .addHeaders(createHeaders())
+                .form(param)
+                .execute()) {
+            if (response.getStatus() == HttpStatus.HTTP_CREATED) {
+                return Optional.ofNullable(response.bodyBytes());
+            }
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * 预览
+     */
+    public Optional<JSONArray> preview(String id) {
+        String url = "https://code.mingsoft.net/code-proxy/people/mcode/project/view.do";
+        Map<String, Object> param = new HashMap<>();
+        param.put("projectModelObjectId", id);
+        param.put("id", Info.PROJECT_ID);
+        param.put("ctgId", Info.CTG_ID);
+        try (HttpResponse response = HttpUtil.createRequest(Method.POST, url)
+                .addHeaders(createHeaders())
+                .form(param)
+                .execute()) {
+            return getResponseData(response);
+        }
+    }
+
+    /**
+     * 获得响应数据
+     */
+    private Optional<JSONArray> getResponseData(HttpResponse response) {
+        return checkResponse(response).map(json -> json.getJSONArray("data"));
+    }
+
+    /**
+     * 检查响应
+     */
+    private Optional<JSONObject> checkResponse(HttpResponse response) {
+        return Optional.ofNullable(response.body())
+                .map(JSONObject::new)
+                .filter(MapUtil::isNotEmpty)
+                .filter(json -> {
+                    if (json.getInt("code") == HttpStatus.HTTP_OK) {
+                        return true;
+                    }
+                    System.err.println(json);
+                    return false;
+                });
+    }
+
+    /**
+     * 创建请求头
+     */
+    private Map<String, String> createHeaders() {
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Accept", "application/json, text/plain, */*");
+        headers.put("Accept-Encoding", "gzip, deflate, br, zstd");
+        headers.put("Accept-Language", "zh-CN,zh;q=0.9");
+        headers.put("Cache-Control", "no-cache");
+        headers.put("Connection", "keep-alive");
+        headers.put("Cookie", "token=" + token);
+        headers.put("Pragma", "no-cache");
+        headers.put("Referer", "https://code.mingsoft.net/");
+        headers.put("Sec-Fetch-Dest", "empty");
+        headers.put("Sec-Fetch-Mode", "cors");
+        headers.put("Sec-Fetch-Site", "same-origin");
+        headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36");
+        headers.put("X-Requested-With", "XMLHttpRequest");
+        headers.put("sec-ch-ua", "\"Chromium\";v=\"142\", \"Google Chrome\";v=\"142\", \"Not_A Brand\";v=\"99\"");
+        headers.put("sec-ch-ua-mobile", "?0");
+        headers.put("sec-ch-ua-platform", "\"Windows\"");
+        return headers;
+    }
+}

+ 22 - 5
src/test/java/mingsoft/MingsoftData.java → src/test/java/mingsoft/client/MingsoftData.java

@@ -1,13 +1,21 @@
-package mingsoft;
+package mingsoft.client;
 
 import lombok.Data;
 import lombok.SneakyThrows;
+import lombok.experimental.Accessors;
 
+/**
+ * 实体类
+ *
+ * @author hosea
+ * @date 2025-12-24
+ */
 @Data
+@Accessors(chain = true)
 public class MingsoftData implements Cloneable {
     private String id;
-    private String projectId = "1980198434053410817";
-    private String peopleId = "1980170321679396866";
+    private String projectId = Info.PROJECT_ID;
+    private String peopleId = Info.PEOPLE_ID;
     private String pmoName;
     private String pmoObjectName;
     private String pmoTableName;
@@ -28,19 +36,28 @@ public class MingsoftData implements Cloneable {
     private String createDate;
     private String updateDate;
 
+    /**
+     * 克隆
+     */
     @Override
     @SneakyThrows
     public MingsoftData clone() {
         return (MingsoftData) super.clone();
     }
 
-    public void info(Info info) {
+    /**
+     * 设置业务信息
+     * <p>
+     * 不会设置ID
+     */
+    public MingsoftData info(Info info) {
         if (info == null) {
-            return;
+            return this;
         }
         setPmoName(info.getName());
         setPmoDescription(info.getName());
         setPmoObjectName(info.getTable());
         setPmoTableName(info.getTable());
+        return this;
     }
 }

+ 21 - 0
src/test/java/mingsoft/client/MingsoftPreView.java

@@ -0,0 +1,21 @@
+package mingsoft.client;
+
+import lombok.Data;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+
+/**
+ * 实体类
+ *
+ * @author hosea
+ * @date 2025-12-24
+ */
+@Data
+@Accessors(chain = true)
+public class MingsoftPreView {
+    @ToString.Exclude
+    private String code;
+    private String ctMode;
+    private String name;
+    private Integer sort;
+}

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio