浏览代码

云联学生信息同步接口

Guos 1 天之前
父节点
当前提交
da29edba0b

+ 22 - 0
fs-service/src/main/java/com/fs/tulin/JsonSortUtils.java

@@ -0,0 +1,22 @@
+package com.fs.tulin;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/10/22 上午9:59
+ */
+public class JsonSortUtils {
+
+    private static final ObjectMapper mapper = new ObjectMapper();
+
+    public static String toSortedJson(Object obj) {
+        try {
+            return mapper.writeValueAsString(obj); // 自动应用@JsonPropertyOrder
+        } catch (Exception e) {
+            throw new RuntimeException("JSON序列化失败", e);
+        }
+    }
+
+}

+ 49 - 0
fs-service/src/main/java/com/fs/tulin/PharmacyEnum.java

@@ -0,0 +1,49 @@
+package com.fs.tulin;
+
+/**
+ * @description: 这个后面要放到数据库去方便动态添加
+ * @author: Guos
+ * @time: 2025/10/22 上午9:41
+ */
+public enum PharmacyEnum {
+
+
+    YJKQS("药济康強昇专卖店"	,"ab0017b8-4961-4230-877e-e86fc1e96b3b", "prod"),
+
+    YJKJS("药济康匀善专卖店"	,"cbcdec50-ea88-448f-810d-3f2f1b809915", "prod"),
+
+    YJKYSY("药济康益寿缘专卖店","a8392536-7554-4e0a-9d12-20f856c94c55", "prod"),
+
+    YJKKM("药济康凯蒙专卖店"	,"517d85c4-e4d4-4a36-af7f-57097b59c650", "prod"),
+
+    YJKKMEB("药济康凯蒙二部专卖店","48e79523-3563-4252-a4a7-fdbcf4af4f34", "prod"),
+
+    YJKSST("药济康盛世堂专卖店","69cdae19-fbe6-4976-b9c2-611f9414440a", "prod"),
+
+    BDHD("保定弘德专卖店"	,"611edbf5-1e75-4f48-8171-533d60d50019", "prod"),
+
+    DEVCS("测试店铺"	,"26ee29ce-35aa-46c8-9650-3fe46014690c", "dev");
+
+    private String pharmacyName;
+
+    private String pharmacyId;
+
+    private String useEnvironment;
+
+    PharmacyEnum(String pharmacyName, String pharmacyId, String useEnvironment){
+        this.pharmacyName = pharmacyName;
+        this.pharmacyId = pharmacyId;
+        this.useEnvironment = useEnvironment;
+    }
+    public String getPharmacyId() {
+        return this.pharmacyId;
+    }
+
+    public String getPharmacyName() {
+        return this.pharmacyName;
+    }
+
+    public String getUseEnvironment() {
+        return this.useEnvironment;
+    }
+}

+ 83 - 0
fs-service/src/main/java/com/fs/tulin/StudentInfo.java

@@ -0,0 +1,83 @@
+package com.fs.tulin;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/10/22 上午9:15
+ */
+@Setter
+@Getter
+@Builder
+@ToString
+@JsonPropertyOrder(alphabetic = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class StudentInfo {
+
+     /**
+      * 必填 union_id
+      * 小程序union_id
+      */
+     private String union_id;
+
+     /**
+      * 必填 open_id
+      * 小程序open_id
+      */
+     private String open_id;
+
+     /**
+      * 必填 appid
+      * 微信小程序appid
+      */
+     private String appid;
+
+     /**
+      * 必填 nickname
+      * 昵称
+      */
+     private String nickname;
+
+     /**
+      * 必填 column_name
+      * 栏目名称
+      */
+     private String column_name;
+
+     /**
+      * 必填 pharmacy_id
+      * 药店ID
+      */
+     private String pharmacy_id;
+
+     /**
+      * 必填 service_phone
+      * 客服手机号
+      */
+     private String service_phone;
+
+     /**
+      * 可选 period_name
+      * 学员所属期名称(可选)
+      */
+     private String period_name;
+
+     /**
+      * 可选 name
+      * 学员名称(可选)
+      */
+     private String name;
+
+     /**
+      * 可选 avatar
+      * 学员头像 (可选)
+      */
+     private String avatar;
+
+}

+ 182 - 0
fs-service/src/main/java/com/fs/tulin/SyncStudentInfoService.java

@@ -0,0 +1,182 @@
+package com.fs.tulin;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+import java.util.logging.Logger;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/10/21 下午3:40
+ */
+public class SyncStudentInfoService {
+
+
+    private static final Logger logger = Logger.getLogger(SyncStudentInfoService.class.getName());
+    /**
+     * 密钥
+     */
+    private static final String SECRET_KEY = "xysync_dLsSaheCzK7RU9gd";
+
+    /**
+     * 测试药店ID
+     */
+    private static final String PHARMACY_ID = "26ee29ce-35aa-46c8-9650-3fe46014690c";
+
+    /**
+     * 测试企业ID
+     */
+    private static final String CORP_ID = "PNBnO6MajM0tAd8t";
+
+
+    public static void main(String[] args) throws JsonProcessingException {
+//第一种方式
+//        Map<String, Object> requestBody = new HashMap<>();
+//        requestBody.put("corp_id", "PNBnO6MajM0tAd8t");
+//        List<Map<String, Object>> dataList = new ArrayList<>();
+//        Map<String, Object> dataItem = new HashMap<>();
+//        dataItem.put("union_id", "oLH_O648dcNgoZdQT4CN2Qft8i7k");
+//        dataItem.put("open_id", "ozzk-19AxQC5D3X9Wqpb-I3_Y3EQ");
+//        dataItem.put("appid", "wx6688e6b9b6fb8700");
+//        dataItem.put("nickname", "@冰阔落");
+//        dataItem.put("column_name", "测试栏目0921");
+//        dataItem.put("pharmacy_id", "26ee29ce-35aa-46c8-9650-3fe46014690c");
+//        dataItem.put("service_phone", "13760648472");
+//        dataList.add(dataItem);
+//        String sort = sortRequestBody(dataItem);
+//        requestBody.put("data", dataList);
+//      // 生成签名
+//        long timestamp = generateTimestamp();
+//        String sign = generateSign("PNBnO6MajM0tAd8t", sort, timestamp);
+//        System.out.println("时间戳: " + timestamp);
+//        System.out.println("签名: " + sign);
+//        // 构建完整的请求URL          "https://api.xiangyue.life/api/v1/mp/sync/student
+//        String url = String.format("https://api.xiangyue.life/api/v1/mp/sync/student?sign=%s&t=%d", sign, timestamp);
+//        HttpRequest httpRequest = HttpUtil.createPost(url);
+//        httpRequest.header("Content-Type", "application/json");
+//        System.out.println("url: " + url);
+//        System.out.println("排序后的"+sortRequestBody(requestBody));
+//        httpRequest.body(sortRequestBody(requestBody));
+//        HttpResponse execute = httpRequest.execute();
+//        String body = execute.body();
+//        System.out.println("响应结果: " + body);
+//第二种方式
+//        StudentInfo student = StudentInfo.builder()
+//                .union_id("oLH_O648dcNgoZdQT4CN2Qft8i7k")
+//                .open_id("ozzk-19AxQC5D3X9Wqpb-I3_Y3EQ")
+//                .appid("wx6688e6b9b6fb8700")
+//                .nickname("@冰阔落")
+//                .column_name("测试栏目0921")
+//                .pharmacy_id(PHARMACY_ID).service_phone("13760648472").build();
+//        //排序
+//        String sortedJson = JsonSortUtils.toSortedJson(student);
+//        long timestamp = generateTimestamp();
+//        String sign = generateSign(CORP_ID, sortedJson, timestamp);
+//        String url = String.format("https://api.xiangyue.life/api/v1/mp/sync/student?sign=%s&t=%d", sign, timestamp);
+//        Map<String, Object> request = new HashMap<>();
+//        request.put("corp_id", CORP_ID);
+//        request.put("data", Collections.singletonList(student));
+//        String jsonBody = mapper.writeValueAsString(request);
+//        System.out.println("正确JSON:");
+//        System.out.println(jsonBody);
+//        sendHttpPost(url, jsonBody);
+
+        StudentInfo student = StudentInfo.builder()
+                .union_id("oLH_O648dcNgoZdQT4CN2Qft8i7k")
+                .open_id("ozzk-19AxQC5D3X9Wqpb-I3_Y3EQ")
+                .appid("wx6688e6b9b6fb8700")
+                .nickname("@冰阔落")
+                .column_name("测试栏目0921")
+                .pharmacy_id(PHARMACY_ID).service_phone("13760648472").build();
+        String result = send(CORP_ID, student);
+    }
+
+    /**
+     * @param corpId 企业ID
+     * @param studentInfo 学生信息对象
+     * @return 请求结果
+     * @throws JsonProcessingException
+     */
+    public static String send(String corpId, StudentInfo studentInfo) throws JsonProcessingException {
+        String sortedJson = JsonSortUtils.toSortedJson(studentInfo);
+        long timestamp = generateTimestamp();
+        String sign = generateSign(corpId, sortedJson, timestamp);
+        String url = String.format("https://api.xiangyue.life/api/v1/mp/sync/student?sign=%s&t=%d", sign, timestamp);
+        Map<String, Object> request = new HashMap<>();
+        request.put("corp_id", corpId);
+        request.put("data", Collections.singletonList(studentInfo));
+        String jsonBody = JsonSortUtils.toSortedJson(request);
+        return sendHttpPost(url, jsonBody);
+    }
+
+    /**
+     * 发送HTTP POST请求
+     * @param url 请求URL
+     * @param jsonBody 请求体JSON字符串
+     * @return 响应结果
+     */
+    private static String sendHttpPost(String url, String jsonBody) {
+        logger.info("云联学生信息同步接口");
+        logger.info("请求URL:"+ url);
+        logger.info("请求Body:"+ jsonBody);
+        HttpRequest httpRequest = HttpUtil.createPost(url);
+        httpRequest.header("Content-Type", "application/json");
+        httpRequest.body(jsonBody);
+        HttpResponse execute = httpRequest.execute();
+        String result = execute.body();
+        logger.info("请求结果:"+ result);
+        return result;
+    }
+
+    /**
+     * 生成签名,在这里去组装成数组的样子,然后进行MD5加密
+     * @param corpId 企业ID
+     * @param sortStr 请求体对象
+     * @param timestamp 时间戳(秒级)
+     * @return 32位小写MD5签名
+     */
+    private static String generateSign(String corpId, Object sortStr, long timestamp) {
+        try {
+            String signString = SECRET_KEY + corpId + "["+sortStr+"]" + timestamp;
+            return generateMD5(signString);
+        } catch (Exception e) {
+            throw new RuntimeException("生成签名失败", e);
+        }
+    }
+
+    /**
+     * 生成MD5哈希值
+     */
+    private static String generateMD5(String input) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] hash = md.digest(input.getBytes());
+            // 转换为16进制小写字符串
+            StringBuilder hexString = new StringBuilder();
+            for (byte b : hash) {
+                String hex = Integer.toHexString(0xff & b);
+                if (hex.length() == 1) {
+                    hexString.append('0');
+                }
+                hexString.append(hex);
+            }
+            return hexString.toString();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("MD5算法不可用", e);
+        }
+    }
+
+    /**
+     * 生成当前时间戳(秒级)
+     */
+    private static long generateTimestamp() {
+        return System.currentTimeMillis() / 1000;
+    }
+
+}