From 09e6dc3fb7266620fafb5e341808a8eb36e080a1 Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期六, 13 十二月 2025 22:51:52 +0800
Subject: [PATCH] feat:增加企业微信消息提醒

---
 ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java |  155 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 139 insertions(+), 16 deletions(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java
index 5b3e6e8..9a34103 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java
@@ -4,7 +4,7 @@
 import com.alibaba.fastjson2.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.web.client.RestTemplate;
+import com.ruoyi.common.utils.http.HttpUtils;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -18,7 +18,8 @@
     
     private static final Logger log = LoggerFactory.getLogger(WechatUtils.class);
     
-    private static final String WECHAT_API_BASE_URL = "https://api.weixin.qq.com";
+    private static final String WECHAT_API_BASE_URL = "https://open.weixin.qq.com";
+    private static final String WECHAT_API_BASE_URL_SERVER = "https://api.weixin.qq.com";
     
     /**
      * 鑾峰彇寰俊Access Token
@@ -29,10 +30,10 @@
      */
     public static String getAccessToken(String appId, String appSecret) {
         try {
-            String url = WECHAT_API_BASE_URL + "/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
+            String url = WECHAT_API_BASE_URL_SERVER + "/cgi-bin/token";
+            String param = "grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
             
-            RestTemplate restTemplate = new RestTemplate();
-            String response = restTemplate.getForObject(url, String.class);
+            String response = HttpUtils.sendGet(url, param);
             
             JSONObject jsonObject = JSON.parseObject(response);
             if (jsonObject.containsKey("access_token")) {
@@ -56,10 +57,10 @@
      */
     public static JSONObject getWechatUserInfo(String accessToken, String openid) {
         try {
-            String url = WECHAT_API_BASE_URL + "/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
+            String url = WECHAT_API_BASE_URL_SERVER + "/cgi-bin/user/info";
+            String param = "access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
             
-            RestTemplate restTemplate = new RestTemplate();
-            String response = restTemplate.getForObject(url, String.class);
+            String response = HttpUtils.sendGet(url, param);
             
             JSONObject jsonObject = JSON.parseObject(response);
             if (jsonObject.containsKey("openid")) {
@@ -84,10 +85,10 @@
      */
     public static JSONObject getWebAccessToken(String appId, String appSecret, String code) {
         try {
-            String url = WECHAT_API_BASE_URL + "/sns/oauth2/access_token?appid=" + appId + "&secret=" + appSecret + "&code=" + code + "&grant_type=authorization_code";
+            String url = WECHAT_API_BASE_URL_SERVER + "/sns/oauth2/access_token";
+            String param = "appid=" + appId + "&secret=" + appSecret + "&code=" + code + "&grant_type=authorization_code";
             
-            RestTemplate restTemplate = new RestTemplate();
-            String response = restTemplate.getForObject(url, String.class);
+            String response = HttpUtils.sendGet(url, param);
             
             JSONObject jsonObject = JSON.parseObject(response);
             if (jsonObject.containsKey("access_token")) {
@@ -111,10 +112,10 @@
      */
     public static JSONObject getWebUserInfo(String accessToken, String openid) {
         try {
-            String url = WECHAT_API_BASE_URL + "/sns/userinfo?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
+            String url = WECHAT_API_BASE_URL_SERVER + "/sns/userinfo";
+            String param = "access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
             
-            RestTemplate restTemplate = new RestTemplate();
-            String response = restTemplate.getForObject(url, String.class);
+            String response = HttpUtils.sendGet(url, param);
             
             JSONObject jsonObject = JSON.parseObject(response);
             if (jsonObject.containsKey("openid")) {
@@ -140,11 +141,50 @@
      */
     public static String generateAuthUrl(String appId, String redirectUri, String scope, String state) {
         try {
-            String encodedRedirectUri = java.net.URLEncoder.encode(redirectUri, "UTF-8");
-            return WECHAT_API_BASE_URL + "/connect/oauth2/authorize?appid=" + appId + "&redirect_uri=" + encodedRedirectUri + "&response_type=code&scope=" + scope + "&state=" + state + "#wechat_redirect";
+            // 娓呯悊鍜岄獙璇乺edirectUri
+            String cleanRedirectUri = cleanRedirectUri(redirectUri);
+            
+            // URL缂栫爜
+            String encodedRedirectUri = java.net.URLEncoder.encode(cleanRedirectUri, "UTF-8");
+            
+            return WECHAT_API_BASE_URL + "/connect/oauth2/authorize?appid=" + appId + 
+                   "&redirect_uri=" + encodedRedirectUri + 
+                   "&response_type=code&scope=" + scope + 
+                   "&state=" + state + "#wechat_redirect";
         } catch (Exception e) {
             log.error("鐢熸垚寰俊鎺堟潈URL寮傚父: {}", e.getMessage());
             return null;
+        }
+    }
+    
+    /**
+     * 娓呯悊鍜岄獙璇乺edirectUri
+     * 
+     * @param redirectUri 鍘熷鍥炶皟鍦板潃
+     * @return 娓呯悊鍚庣殑鍥炶皟鍦板潃
+     */
+    private static String cleanRedirectUri(String redirectUri) {
+        if (StringUtils.isEmpty(redirectUri)) {
+            return redirectUri;
+        }
+        
+        try {
+            // 绉婚櫎绔彛鍙凤紙寰俊鎺堟潈涓嶆敮鎸佺鍙e彿锛�
+            if (redirectUri.contains(":81") || redirectUri.contains(":8080") || redirectUri.contains(":3000")) {
+                redirectUri = redirectUri.replaceAll(":(81|8080|3000|8081|8082|8083|8084|8085|8086|8087|8088|8089|8090)", "");
+                log.warn("妫�娴嬪埌绔彛鍙凤紝宸茶嚜鍔ㄧЩ闄�: {}", redirectUri);
+            }
+            
+            // 纭繚浣跨敤HTTPS锛堢敓浜х幆澧冿級
+            if (redirectUri.startsWith("http://") && !redirectUri.contains("localhost") && !redirectUri.contains("127.0.0.1")) {
+                redirectUri = redirectUri.replace("http://", "https://");
+                log.warn("鐢熶骇鐜寤鸿浣跨敤HTTPS锛屽凡鑷姩杞崲: {}", redirectUri);
+            }
+            
+            return redirectUri;
+        } catch (Exception e) {
+            log.error("娓呯悊redirectUri寮傚父: {}", e.getMessage());
+            return redirectUri;
         }
     }
     
@@ -160,4 +200,87 @@
         }
         return userAgent.toLowerCase().contains("micromessenger");
     }
+
+    /**
+     * 鎴柇thing绫诲瀷瀛楁锛屽井淇¤闃呮秷鎭痶hing绫诲瀷鏈�闀�20涓瓧绗�
+     * 
+     * @param value 鍘熷瀛楃涓�
+     * @return 鎴柇鍚庣殑瀛楃涓诧紙鏈�闀�20瀛楃锛�
+     */
+    public static String truncateThingValue(String value) {
+        if (StringUtils.isEmpty(value)) {
+            return value;
+        }
+        
+        // 寰俊thing绫诲瀷鏈�闀�20涓瓧绗�
+        final int MAX_THING_LENGTH = 20;
+        
+        if (value.length() <= MAX_THING_LENGTH) {
+            return value;
+        }
+        
+        // 鎴柇骞舵坊鍔犵渷鐣ュ彿锛岀‘淇濇�婚暱搴︿笉瓒呰繃20
+        return value.substring(0, MAX_THING_LENGTH - 1) + "鈥�";
+    }
+
+    /**
+     * 鍙戦�佸皬绋嬪簭璁㈤槄娑堟伅
+     *
+     * @param accessToken 寰俊鎺ュ彛璋冪敤鍑瘉
+     * @param touser 鎺ユ敹浜簅penId
+     * @param templateId 妯℃澘ID
+     * @param page 灏忕▼搴忚烦杞〉闈�
+     * @param data 妯℃澘鏁版嵁锛宬ey涓哄瓧娈靛悕(濡倀hing1銆乼ime27)锛寁alue涓哄瓧娈靛��
+     * @return 寰俊杩斿洖缁撴灉JSON
+     */
+    public static JSONObject sendSubscribeMessage(String accessToken,
+                                                  String touser,
+                                                  String templateId,
+                                                  String page,
+                                                  Map<String, String> data) {
+        try {
+            if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(touser) || StringUtils.isEmpty(templateId)) {
+                log.error("鍙戦�佽闃呮秷鎭弬鏁颁笉瀹屾暣锛宎ccessToken={}, touser={}, templateId={}", accessToken, touser, templateId);
+                return null;
+            }
+
+            String url = WECHAT_API_BASE_URL_SERVER + "/cgi-bin/message/subscribe/send?access_token=" + accessToken;
+
+            Map<String, Object> body = new HashMap<>();
+            body.put("touser", touser);
+            body.put("template_id", templateId);
+            if (StringUtils.isNotEmpty(page)) {
+                body.put("page", page);
+            }
+             body.put("miniprogram_state", "formal");
+
+            Map<String, Object> dataNode = new HashMap<>();
+            if (data != null && !data.isEmpty()) {
+                for (Map.Entry<String, String> entry : data.entrySet()) {
+                    Map<String, String> valueNode = new HashMap<>();
+                    valueNode.put("value", entry.getValue());
+                    dataNode.put(entry.getKey(), valueNode);
+                }
+            }
+            body.put("data", dataNode);
+
+            String jsonBody = JSON.toJSONString(body);
+            String response = HttpUtils.sendPost(url, jsonBody);
+
+            JSONObject jsonObject = JSON.parseObject(response);
+            if (jsonObject == null) {
+                log.error("鍙戦�佽闃呮秷鎭繑鍥炰负绌�");
+                return null;
+            }
+            if (jsonObject.getIntValue("errcode") != 0) {
+                log.error("鍙戦�佽闃呮秷鎭け璐�: {}", jsonObject.toJSONString());
+            } else {
+                log.info("鍙戦�佽闃呮秷鎭垚鍔燂紝touser={}, templateId={}", touser, templateId);
+            }
+            return jsonObject;
+        } catch (Exception e) {
+            log.error("鍙戦�佽闃呮秷鎭紓甯�: {}", e.getMessage(), e);
+            return null;
+        }
+    }
 }

--
Gitblit v1.9.1