From 4c0da4f99ca97d2cfcaa00fd5cd9c3d69d089bfa Mon Sep 17 00:00:00 2001
From: liusheng <337615773@qq.com>
Date: 星期三, 22 四月 2026 19:39:04 +0800
Subject: [PATCH] 获取subid

---
 ruoyi-common/src/main/java/com/ruoyi/common/utils/AesUtils.java  |  129 +++++++++++++++++++++
 ruoyi-common/src/main/java/com/ruoyi/common/utils/WxMpUtils.java |  175 +++++++++++++++++++++++++++++
 2 files changed, 304 insertions(+), 0 deletions(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/AesUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/AesUtils.java
new file mode 100644
index 0000000..902650d
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/AesUtils.java
@@ -0,0 +1,129 @@
+package com.ruoyi.common.utils;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * AES 鍔犺В瀵嗗伐鍏风被
+ * 绠楁硶锛欰ES/CBC/PKCS5Padding锛堢瓑鏁� PKCS7锛�128 浣嶆暟鎹潡锛�
+ * 杈撳嚭锛欻EX 澶у啓瀛楃涓�
+ * 瀛楃闆嗭細UTF-8
+ */
+public class AesUtils {
+
+    /** 绠楁硶/妯″紡/濉厖 */
+    private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
+
+    /** 榛樿 Key锛圚EX锛�32瀛楄妭鈫�256浣嶅瘑閽ワ級 */
+    private static final String DEFAULT_KEY = "0F471C56362408AF8DB929C38EDFD23C";
+
+    /** 榛樿 IV锛圚EX锛�16瀛楄妭鈫�128浣嶅亸绉婚噺锛� */
+    private static final String DEFAULT_IV = "11BEE6E35B881A33CF1649607295D1A7";
+
+    private AesUtils() {
+    }
+
+    // -------------------------------------------------------------------------
+    // 鍏叡 API
+    // -------------------------------------------------------------------------
+
+    /**
+     * 浣跨敤榛樿 Key / IV 鍔犲瘑
+     *
+     * @param plainText 鏄庢枃
+     * @return HEX 澶у啓瀵嗘枃
+     */
+    public static String encrypt(String plainText) {
+        return encrypt(plainText, DEFAULT_KEY, DEFAULT_IV);
+    }
+
+    /**
+     * 浣跨敤榛樿 Key / IV 瑙e瘑
+     *
+     * @param hexCipherText HEX 澶у啓瀵嗘枃
+     * @return 鏄庢枃
+     */
+    public static String decrypt(String hexCipherText) {
+        return decrypt(hexCipherText, DEFAULT_KEY, DEFAULT_IV);
+    }
+
+    /**
+     * AES-CBC 鍔犲瘑
+     *
+     * @param plainText  鏄庢枃
+     * @param hexKey     HEX 鏍煎紡鐨勫瘑閽ワ紙16/24/32瀛楄妭瀵瑰簲128/192/256浣嶏級
+     * @param hexIv      HEX 鏍煎紡鐨勫亸绉婚噺锛�16瀛楄妭锛�
+     * @return HEX 澶у啓瀵嗘枃
+     */
+    public static String encrypt(String plainText, String hexKey, String hexIv) {
+        try {
+            byte[] keyBytes = hexToBytes(hexKey);
+            byte[] ivBytes = hexToBytes(hexIv);
+            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
+            IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
+            byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
+            return bytesToHex(encrypted).toUpperCase();
+        } catch (Exception e) {
+            throw new RuntimeException("AES 鍔犲瘑澶辫触", e);
+        }
+    }
+
+    /**
+     * AES-CBC 瑙e瘑
+     *
+     * @param hexCipherText HEX 澶у啓瀵嗘枃
+     * @param hexKey        HEX 鏍煎紡鐨勫瘑閽�
+     * @param hexIv         HEX 鏍煎紡鐨勫亸绉婚噺
+     * @return 鏄庢枃
+     */
+    public static String decrypt(String hexCipherText, String hexKey, String hexIv) {
+        try {
+            byte[] keyBytes = hexToBytes(hexKey);
+            byte[] ivBytes = hexToBytes(hexIv);
+            byte[] cipherBytes = hexToBytes(hexCipherText);
+            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
+            IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
+            byte[] decrypted = cipher.doFinal(cipherBytes);
+            return new String(decrypted, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            throw new RuntimeException("AES 瑙e瘑澶辫触", e);
+        }
+    }
+
+    // -------------------------------------------------------------------------
+    // 绉佹湁杈呭姪鏂规硶
+    // -------------------------------------------------------------------------
+
+    /**
+     * HEX 瀛楃涓茶浆瀛楄妭鏁扮粍锛堝ぇ灏忓啓鍧囧彲锛�
+     */
+    private static byte[] hexToBytes(String hex) {
+        if (hex == null || hex.length() % 2 != 0) {
+            throw new IllegalArgumentException("闈炴硶 HEX 瀛楃涓诧細" + hex);
+        }
+        int len = hex.length();
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
+                    + Character.digit(hex.charAt(i + 1), 16));
+        }
+        return data;
+    }
+
+    /**
+     * 瀛楄妭鏁扮粍杞� HEX 瀛楃涓诧紙灏忓啓锛岃皟鐢ㄦ柟缁熶竴杞ぇ鍐欙級
+     */
+    private static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder(bytes.length * 2);
+        for (byte b : bytes) {
+            sb.append(String.format("%02x", b));
+        }
+        return sb.toString();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxMpUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxMpUtils.java
new file mode 100644
index 0000000..89cc4ef
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxMpUtils.java
@@ -0,0 +1,175 @@
+package com.ruoyi.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.exception.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
+import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
+import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
+import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
+
+import java.util.Map;
+
+/**
+ * 寰俊鍏紬鍙锋秷鎭彂閫佸伐鍏风被
+ * 鏀寔锛氭枃鏈鏈嶆秷鎭�佹ā鏉挎秷鎭�
+ */
+@Slf4j
+public class WxMpUtils {
+
+    private final WxMpService wxMpService;
+
+    /**
+     * 鏋勯�犳柟娉曪紝閫氳繃 appId 鍜� appSecret 鍒濆鍖栧井淇″叕浼楀彿鏈嶅姟
+     *
+     * @param appId     寰俊鍏紬鍙� AppID
+     * @param appSecret 寰俊鍏紬鍙� AppSecret
+     */
+    public WxMpUtils(String appId, String appSecret) {
+        WxMpInMemoryConfigStorage configStorage = new WxMpInMemoryConfigStorage();
+        configStorage.setAppId(appId);
+        configStorage.setSecret(appSecret);
+        wxMpService = new WxMpServiceImpl();
+        wxMpService.setWxMpConfigStorage(configStorage);
+    }
+
+    // -------------------------------------------------------------------------
+    // 鏂囨湰瀹㈡湇娑堟伅
+    // -------------------------------------------------------------------------
+
+    /**
+     * 鍚戞寚瀹� openid 鐨勭敤鎴峰彂閫佹枃鏈鏈嶆秷鎭�
+     * 娉ㄦ剰锛氱敤鎴烽渶鍦�48灏忔椂鍐呬笌鍏紬鍙锋湁杩囦氦浜掓墠鍙彂閫�
+     *
+     * @param openid  鐢ㄦ埛鐨勫井淇� openid
+     * @param content 娑堟伅鍐呭
+     * @return 鍙戦�佹垚鍔熻繑鍥� true锛屽け璐ヨ繑鍥� false
+     */
+    public boolean sendTextMessage(String openid, String content) {
+        if (StringUtils.isEmpty(openid)) {
+            log.warn("銆怶xMpUtils銆憇endTextMessage 澶辫触锛歰penid 涓虹┖");
+            return false;
+        }
+        if (StringUtils.isEmpty(content)) {
+            log.warn("銆怶xMpUtils銆憇endTextMessage 澶辫触锛歝ontent 涓虹┖");
+            return false;
+        }
+        try {
+            WxMpKefuMessage message = WxMpKefuMessage.TEXT()
+                    .toUser(openid)
+                    .content(content)
+                    .build();
+            boolean result = wxMpService.getKefuService().sendKefuMessage(message);
+            log.info("銆怶xMpUtils銆戞枃鏈鏈嶆秷鎭彂閫亄}锛宱penid锛歿}", result ? "鎴愬姛" : "澶辫触", openid);
+            return result;
+        } catch (WxErrorException e) {
+            log.error("銆怶xMpUtils銆戞枃鏈鏈嶆秷鎭彂閫佸紓甯革紝openid锛歿}锛岄敊璇細{}", openid, e.getError(), e);
+            return false;
+        }
+    }
+
+    // -------------------------------------------------------------------------
+    // 妯℃澘娑堟伅
+    // -------------------------------------------------------------------------
+
+    /**
+     * 鍚戞寚瀹� openid 鐨勭敤鎴峰彂閫佹ā鏉挎秷鎭紙鍚烦杞琔RL锛�
+     *
+     * @param openid     鐢ㄦ埛鐨勫井淇� openid
+     * @param templateId 妯℃澘娑堟伅 ID锛堝湪寰俊鍏紬骞冲彴閰嶇疆锛�
+     * @param url        鐐瑰嚮娑堟伅鍚庣殑璺宠浆 URL锛屼笉闇�瑕佽烦杞彲浼� null
+     * @param dataMap    妯℃澘鏁版嵁锛宬ey 涓烘ā鏉垮瓧娈靛悕锛寁alue 涓� WxMpTemplateData锛堝惈鍊煎拰棰滆壊锛�
+     *                   绀轰緥锛歿"first": new WxMpTemplateData("first", "浣犲ソ", "#173177"), ...}
+     * @return 鍙戦�佹垚鍔熻繑鍥炲井淇¤繑鍥炵殑 msgid锛屽け璐ヨ繑鍥� null
+     */
+    public String sendTemplateMessage(String openid, String templateId, String url,
+                                      Map<String, WxMpTemplateData> dataMap) {
+        if (StringUtils.isEmpty(openid)) {
+            log.warn("銆怶xMpUtils銆憇endTemplateMessage 澶辫触锛歰penid 涓虹┖");
+            return null;
+        }
+        if (StringUtils.isEmpty(templateId)) {
+            log.warn("銆怶xMpUtils銆憇endTemplateMessage 澶辫触锛歵emplateId 涓虹┖");
+            return null;
+        }
+        try {
+            WxMpTemplateMessage templateMessage = new WxMpTemplateMessage();
+            templateMessage.setToUser(openid);
+            templateMessage.setTemplateId(templateId);
+            if (StringUtils.isNotEmpty(url)) {
+                templateMessage.setUrl(url);
+            }
+            if (dataMap != null) {
+                for (WxMpTemplateData data : dataMap.values()) {
+                    templateMessage.addData(data);
+                }
+            }
+            String msgId = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
+            log.info("銆怶xMpUtils銆戞ā鏉挎秷鎭彂閫佹垚鍔燂紝openid锛歿}锛宮sgId锛歿}", openid, msgId);
+            return msgId;
+        } catch (WxErrorException e) {
+            log.error("銆怶xMpUtils銆戞ā鏉挎秷鎭彂閫佸紓甯革紝openid锛歿}锛宼emplateId锛歿}锛岄敊璇細{}",
+                    openid, templateId, e.getError(), e);
+            return null;
+        }
+    }
+
+    /**
+     * 鍚戞寚瀹� openid 鐨勭敤鎴峰彂閫佹ā鏉挎秷鎭紙绠�鍖栫増锛寁alue 涓嶈缃鑹诧級
+     *
+     * @param openid     鐢ㄦ埛鐨勫井淇� openid
+     * @param templateId 妯℃澘娑堟伅 ID
+     * @param url        鐐瑰嚮娑堟伅鍚庣殑璺宠浆 URL锛屼笉闇�瑕佽烦杞彲浼� null
+     * @param dataMap    妯℃澘鏁版嵁锛宬ey 涓烘ā鏉垮瓧娈靛悕锛寁alue 涓哄瓧娈垫樉绀虹殑鏂囨湰鍐呭
+     *                   绀轰緥锛歿"first": "浣犲ソ", "keyword1": "2024-01-01", "remark": "鎰熻阿浣跨敤"}
+     * @return 鍙戦�佹垚鍔熻繑鍥炲井淇¤繑鍥炵殑 msgid锛屽け璐ヨ繑鍥� null
+     */
+    public String sendTemplateMessage(String openid, String templateId, String url,
+                                      Map<String, String> dataMap, String defaultColor) {
+        if (StringUtils.isEmpty(openid)) {
+            log.warn("銆怶xMpUtils銆憇endTemplateMessage 澶辫触锛歰penid 涓虹┖");
+            return null;
+        }
+        if (StringUtils.isEmpty(templateId)) {
+            log.warn("銆怶xMpUtils銆憇endTemplateMessage 澶辫触锛歵emplateId 涓虹┖");
+            return null;
+        }
+        try {
+            WxMpTemplateMessage templateMessage = new WxMpTemplateMessage();
+            templateMessage.setToUser(openid);
+            templateMessage.setTemplateId(templateId);
+            if (StringUtils.isNotEmpty(url)) {
+                templateMessage.setUrl(url);
+            }
+            if (dataMap != null) {
+                String color = StringUtils.isEmpty(defaultColor) ? "#173177" : defaultColor;
+                for (Map.Entry<String, String> entry : dataMap.entrySet()) {
+                    templateMessage.addData(new WxMpTemplateData(entry.getKey(), entry.getValue(), color));
+                }
+            }
+            String msgId = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
+            log.info("銆怶xMpUtils銆戞ā鏉挎秷鎭彂閫佹垚鍔燂紝openid锛歿}锛宮sgId锛歿}", openid, msgId);
+            return msgId;
+        } catch (WxErrorException e) {
+            log.error("銆怶xMpUtils銆戞ā鏉挎秷鎭彂閫佸紓甯革紝openid锛歿}锛宼emplateId锛歿}锛岄敊璇細{}",
+                    openid, templateId, e.getError(), e);
+            return null;
+        }
+    }
+
+    // -------------------------------------------------------------------------
+    // 闈欐�佸伐鍘傛柟娉曪紙蹇�熸瀯閫狅級
+    // -------------------------------------------------------------------------
+
+    /**
+     * 蹇�熷垱寤� WxMpUtils 瀹炰緥
+     *
+     * @param appId     寰俊鍏紬鍙� AppID
+     * @param appSecret 寰俊鍏紬鍙� AppSecret
+     * @return WxMpUtils 瀹炰緥
+     */
+    public static WxMpUtils of(String appId, String appSecret) {
+        return new WxMpUtils(appId, appSecret);
+    }
+}

--
Gitblit v1.9.3