From 9b27e22beac4f247f0a703f1e8a8bb661dbc31f3 Mon Sep 17 00:00:00 2001
From: 陈昶聿 <chychen@nbjetron.com>
Date: 星期五, 30 十月 2026 11:13:07 +0800
Subject: [PATCH] 【丽水】patItem筛选当前执行方式

---
 ruoyi-common/src/main/java/com/ruoyi/common/utils/sms/SmsUtils.java |  575 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 575 insertions(+), 0 deletions(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sms/SmsUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sms/SmsUtils.java
index ae2c286..5390759 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sms/SmsUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sms/SmsUtils.java
@@ -1,6 +1,7 @@
 package com.ruoyi.common.utils.sms;
 
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.annotation.JSONField;
 import com.ruoyi.common.utils.HttpUtil;
@@ -10,11 +11,20 @@
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * 鐭俊鍙戦�佸伐鍏风被
@@ -333,4 +343,569 @@
         }
         return sendMsg;
     }
+
+    /**
+     * 涓芥按寰俊 app-api 鍓嶇紑
+     */
+    private static final String LS_WX_APP_PREFIX = "/app-api";
+
+    /**
+     * 涓芥按寰俊寮�鏀炬帴鍙e墠缂�
+     */
+    private static final String LS_WX_API_PREFIX = LS_WX_APP_PREFIX + "/cross/open-api";
+
+    /**
+     * 鑾峰彇璁块棶浠ょ墝
+     */
+    private static final String LS_WX_TOKEN_PATH = "/token";
+
+    /**
+     * 鑾峰彇娑堟伅妯℃澘
+     */
+    private static final String LS_WX_TEMPLATE_PATH = "/getTemplate";
+
+    /**
+     * 鍙戦�佹秷鎭�
+     */
+    private static final String LS_WX_SEND_PATH = "/sendMessage";
+
+    /**
+     * 璁块棶浠ょ墝璇锋眰澶�
+     */
+    private static final String LS_WX_TOKEN_HEADER = "openApiToken";
+
+    /**
+     * 浠ょ墝缂撳瓨锛坘ey锛歜aseUrl|appId锛�
+     */
+    private static final Map<String, LsWxToken> LS_WX_TOKEN_CACHE = new ConcurrentHashMap<>();
+
+    /**
+     * 浠ょ墝鎻愬墠鍒锋柊鐨勭鏁帮紝閬垮厤涓寸晫杩囨湡
+     */
+    private static final long LS_WX_TOKEN_REFRESH_AHEAD_SECONDS = 60L;
+
+    /**
+     * 涓芥按寰俊鎺ュ彛閰嶇疆
+     */
+    @Data
+    public static class LsWxConfig {
+        /**
+         * 搴旂敤鍚嶇О
+         */
+        private String appName;
+        /**
+         * 鎺ュ彛鏍瑰湴鍧�锛屽 http://127.0.0.1:8080
+         * <p>
+         * 鍙互鍙~ scheme://host:port锛屼篃鍙互濉埌 /app-api 鎴� /app-api/cross/open-api銆�
+         */
+        private String baseUrl;
+        /**
+         * 搴旂敤ID
+         */
+        private String appId;
+        /**
+         * 搴旂敤瀵嗛挜
+         */
+        private String appSecret;
+        /**
+         * 榛樿娑堟伅妯℃澘ID锛屾秷鎭噷鏈寚瀹氭椂浣跨敤
+         */
+        private Long templateId;
+        /**
+         * 榛樿娑堟伅妯℃澘鍚嶇О锛屾湭閰嶇疆妯℃澘ID鏃堕�氳繃 getTemplate 鎸夊悕绉版煡鎵�
+         */
+        private String templateName;
+        /**
+         * 杩炴帴瓒呮椂锛屽崟浣嶏細姣
+         */
+        private Integer connectTimeout = 5000;
+        /**
+         * 璇诲彇瓒呮椂锛屽崟浣嶏細姣
+         */
+        private Integer readTimeout = 10000;
+
+        /**
+         * 涓芥按榛樿閰嶇疆
+         */
+        public static LsWxConfig defaultLishui() {
+            LsWxConfig config = new LsWxConfig();
+            config.setAppName("鎮h�呴殢璁�");
+            config.setBaseUrl("https://wmini.lsfby.com.cn/app-api");
+            config.setAppId("kpzEHgZSteCO4lz74");
+            config.setAppSecret("HKUDVMJSVTKQADIXV7XXRLNBQM8HNNL7");
+            // 娑堟伅妯℃澘锛氳瘖鍚庨殢璁挎彁閱掞紙鏈寚瀹氭ā鏉縄D鏃舵寜鍚嶇О浠� getTemplate 鏌ヨ锛�
+            config.setTemplateName("璇婂悗闅忚鎻愰啋");
+            return config;
+        }
+
+        /**
+         * 鏍规嵁閰嶇疆鍐呭锛坖son锛夋瀯寤猴紝鏈厤缃殑瀛楁娌跨敤榛樿鍊�
+         *
+         * @param configJson 褰㈠
+         *                   {"appName":"鎮h�呴殢璁�","baseUrl":"https://wmini.lsfby.com.cn/app-api","appId":"...","appSecret":"...","templateId":16,"templateName":"璇婂悗闅忚鎻愰啋"}
+         */
+        public static LsWxConfig of(String configJson) {
+            LsWxConfig config = defaultLishui();
+            if (StringUtils.isEmpty(configJson)) {
+                return config;
+            }
+            JSONObject json;
+            try {
+                json = JSON.parseObject(configJson);
+            } catch (Exception e) {
+                log.error("銆愪附姘村井淇°�戦厤缃В鏋愬け璐ワ紝浣跨敤榛樿閰嶇疆锛岄厤缃唴瀹癸細{}", configJson, e);
+                return config;
+            }
+            if (json == null) {
+                return config;
+            }
+            if (StringUtils.isNotEmpty(json.getString("appName"))) {
+                config.setAppName(json.getString("appName"));
+            }
+            if (StringUtils.isNotEmpty(json.getString("baseUrl"))) {
+                config.setBaseUrl(json.getString("baseUrl"));
+            } else if (StringUtils.isNotEmpty(json.getString("url"))) {
+                config.setBaseUrl(json.getString("url"));
+            } else if (StringUtils.isNotEmpty(json.getString("address"))) {
+                config.setBaseUrl(json.getString("address"));
+            }
+            if (StringUtils.isNotEmpty(json.getString("appId"))) {
+                config.setAppId(json.getString("appId"));
+            }
+            if (StringUtils.isNotEmpty(json.getString("appSecret"))) {
+                config.setAppSecret(json.getString("appSecret"));
+            }
+            if (json.containsKey("templateId")) {
+                config.setTemplateId(json.getLong("templateId"));
+            } else if (json.containsKey("id")) {
+                config.setTemplateId(json.getLong("id"));
+            }
+            if (StringUtils.isNotEmpty(json.getString("templateName"))) {
+                config.setTemplateName(json.getString("templateName"));
+            } else if (StringUtils.isNotEmpty(json.getString("tmpName"))) {
+                config.setTemplateName(json.getString("tmpName"));
+            }
+            if (json.containsKey("connectTimeout")) {
+                config.setConnectTimeout(json.getInteger("connectTimeout"));
+            }
+            if (json.containsKey("readTimeout")) {
+                config.setReadTimeout(json.getInteger("readTimeout"));
+            }
+            return config;
+        }
+
+        /**
+         * 鍏抽敭鍙傛暟鏄惁榻愬叏
+         */
+        public boolean isValid() {
+            return StringUtils.isNotEmpty(baseUrl) && StringUtils.isNotEmpty(appId)
+                    && StringUtils.isNotEmpty(appSecret);
+        }
+
+        /**
+         * 鎷兼帴寮�鏀炬帴鍙e湴鍧�
+         */
+        private String url(String path) {
+            String prefix = baseUrl == null ? "" : baseUrl.trim();
+            while (prefix.endsWith("/")) {
+                prefix = prefix.substring(0, prefix.length() - 1);
+            }
+            if (prefix.endsWith(LS_WX_API_PREFIX)) {
+                return prefix + path;
+            }
+            if (prefix.endsWith(LS_WX_APP_PREFIX)) {
+                return prefix + "/cross/open-api" + path;
+            }
+            return prefix + LS_WX_API_PREFIX + path;
+        }
+    }
+
+    /**
+     * 涓芥按寰俊娑堟伅鍙傛暟锛屽瓧娈典笌 sendMessage 鎺ュ彛涓�鑷�
+     */
+    @Data
+    public static class LsWxMessage {
+        /**
+         * 娑堟伅妯℃澘ID锛屼负绌烘椂浣跨敤閰嶇疆涓殑妯℃澘
+         */
+        private Long id;
+        /**
+         * 鎮h�呯紪鍙�
+         */
+        private String patientId;
+        /**
+         * 鎮h�呭鍚�
+         */
+        private String patientName;
+        /**
+         * 璇佷欢鍙�
+         */
+        private String idCard;
+        /**
+         * 鎵嬫満鍙风爜
+         */
+        private String mobile;
+        /**
+         * 灏辫瘖鍗″彿
+         */
+        private String medCardNo;
+        /**
+         * 閫氱煡鏍囬
+         */
+        private String titleName;
+        /**
+         * 閫氱煡鍐呭
+         */
+        private String content;
+        /**
+         * 閾炬帴鍦板潃
+         */
+        private String url;
+    }
+
+    /**
+     * 璁块棶浠ょ墝缂撳瓨瀵硅薄
+     */
+    private static class LsWxToken {
+        private final String token;
+        private final long expireAt;
+
+        private LsWxToken(String token, long expireAt) {
+            this.token = token;
+            this.expireAt = expireAt;
+        }
+
+        private String getToken() {
+            return token;
+        }
+
+        private long getExpireAt() {
+            return expireAt;
+        }
+    }
+
+    /**
+     * 涓芥按寰俊娑堟伅鍙戦�侊紙鍏堣幏鍙�/澶嶇敤璁块棶浠ょ墝锛屽啀璋冪敤 sendMessage锛�
+     * <p>
+     * 鎺ュ彛娴佺▼锛�
+     * <ol>
+     *     <li>GET /app-api/cross/open-api/token?appId=...&appSecret=... 鑾峰彇 openApiToken</li>
+     *     <li>POST /app-api/cross/open-api/sendMessage锛岃姹傚ご鎼哄甫 openApiToken</li>
+     * </ol>
+     *
+     * @param config  涓芥按寰俊閰嶇疆
+     * @param message 娑堟伅鍙傛暟
+     * @return 鎺ュ彛鍘熷鍝嶅簲锛涙湰鍦版牎楠屽け璐ユ椂杩斿洖 {"code":-1,"msg":"澶辫触鍘熷洜"}
+     */
+    public static String sendChatLs(LsWxConfig config, LsWxMessage message) {
+        if (config == null || !config.isValid()) {
+            return lsWxFail("涓芥按寰俊閰嶇疆涓嶅畬鏁达紝璇烽厤缃� baseUrl銆乤ppId銆乤ppSecret");
+        }
+        if (message == null) {
+            return lsWxFail("涓芥按寰俊娑堟伅鍙傛暟涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isEmpty(message.getMobile()) && StringUtils.isEmpty(message.getIdCard())
+                && StringUtils.isEmpty(message.getPatientId()) && StringUtils.isEmpty(message.getMedCardNo())) {
+            return lsWxFail("鎵嬫満鍙风爜銆佽瘉浠跺彿銆佹偅鑰呯紪鍙枫�佸氨璇婂崱鍙蜂笉鑳藉叏閮ㄤ负绌�");
+        }
+        try {
+            String token = getLsWxToken(config);
+            if (StringUtils.isEmpty(token)) {
+                return lsWxFail("鑾峰彇涓芥按寰俊璁块棶浠ょ墝澶辫触");
+            }
+
+            // 妯℃澘浼樺厛绾э細娑堟伅鎸囧畾 > 閰嶇疆鎸囧畾 > 鎸夋ā鏉垮悕绉版煡璇�
+            Long templateId = message.getId();
+            if (templateId == null) {
+                templateId = config.getTemplateId();
+            }
+            if (templateId == null) {
+                templateId = findLsWxTemplateId(config, token, config.getTemplateName());
+                if (templateId == null && StringUtils.isNotEmpty(config.getTemplateName())) {
+                    // 鍙兘鏄紦瀛樼殑浠ょ墝宸插け鏁堬紝鍒锋柊浠ょ墝鍚庨噸璇曚竴娆�
+                    LS_WX_TOKEN_CACHE.remove(tokenCacheKey(config));
+                    token = getLsWxToken(config);
+                    if (StringUtils.isNotEmpty(token)) {
+                        templateId = findLsWxTemplateId(config, token, config.getTemplateName());
+                    }
+                }
+            }
+            if (templateId == null) {
+                return lsWxFail("鏈壘鍒颁附姘村井淇℃秷鎭ā鏉匡紝璇锋寚瀹氭秷鎭ā鏉縄D鎴栨ā鏉垮悕绉�");
+            }
+
+            JSONObject body = new JSONObject(true);
+            body.put("id", templateId);
+            body.put("patientId", nvl(message.getPatientId()));
+            body.put("patientName", nvl(message.getPatientName()));
+            body.put("idCard", nvl(message.getIdCard()));
+            body.put("mobile", message.getMobile());
+            body.put("medCardNo", nvl(message.getMedCardNo()));
+            body.put("titleName", nvl(message.getTitleName()));
+            body.put("content", nvl(message.getContent()));
+            body.put("url", nvl(message.getUrl()));
+            String requestBody = body.toJSONString();
+
+            Map<String, String> headers = new HashMap<>(2);
+            headers.put(LS_WX_TOKEN_HEADER, token);
+            String sendUrl = config.url(LS_WX_SEND_PATH);
+            log.info("銆愪附姘村井淇°�戝彂閫佹秷鎭紝鍦板潃锛歿}锛屽弬鏁帮細{}", sendUrl, requestBody);
+            String resp = lsWxRequest("POST", sendUrl, requestBody, headers, config);
+            log.info("銆愪附姘村井淇°�戝彂閫佺粨鏋滐細{}", resp);
+
+            // 浠ょ墝澶辨晥鏃舵竻闄ょ紦瀛樺苟閲嶈瘯涓�娆�
+            if (isLsWxTokenInvalid(resp)) {
+                LS_WX_TOKEN_CACHE.remove(tokenCacheKey(config));
+                token = getLsWxToken(config);
+                if (StringUtils.isNotEmpty(token)) {
+                    headers.put(LS_WX_TOKEN_HEADER, token);
+                    resp = lsWxRequest("POST", sendUrl, requestBody, headers, config);
+                    log.info("銆愪附姘村井淇°�戜护鐗屽け鏁堥噸璇曠粨鏋滐細{}", resp);
+                }
+            }
+            return resp;
+        } catch (Exception e) {
+            log.error("銆愪附姘村井淇°�戝彂閫佸紓甯革紝鎵嬫満鍙凤細{}锛屽師鍥狅細{}", message.getMobile(), e.getMessage(), e);
+            return lsWxFail("涓芥按寰俊鍙戦�佸紓甯革細" + e.getMessage());
+        }
+    }
+
+    /**
+     * 涓芥按寰俊娑堟伅鍙戦�侊紙甯哥敤闅忚鍙傛暟锛�
+     *
+     * @param config      涓芥按寰俊閰嶇疆
+     * @param mobile      鎵嬫満鍙风爜
+     * @param idCard      璇佷欢鍙�
+     * @param patientName 鎮h�呭鍚�
+     * @param titleName   閫氱煡鏍囬
+     * @param content     閫氱煡鍐呭
+     * @param url         閾炬帴鍦板潃
+     * @return 鎺ュ彛鍘熷鍝嶅簲锛涙湰鍦版牎楠屽け璐ユ椂杩斿洖 {"code":-1,"msg":"澶辫触鍘熷洜"}
+     */
+    public static String sendChatLs(LsWxConfig config, String mobile, String idCard, String patientName,
+                                    String titleName, String content, String url) {
+        LsWxMessage message = new LsWxMessage();
+        message.setMobile(mobile);
+        message.setIdCard(idCard);
+        message.setPatientName(patientName);
+        message.setTitleName(titleName);
+        message.setContent(content);
+        message.setUrl(url);
+        return sendChatLs(config, message);
+    }
+
+    /**
+     * 涓芥按寰俊娑堟伅鍙戦�侊紙閰嶇疆鐩存帴浼� sys_config 涓殑 json锛�
+     *
+     * @param configJson  涓芥按寰俊閰嶇疆 json
+     * @param mobile      鎵嬫満鍙风爜
+     * @param idCard      璇佷欢鍙�
+     * @param patientName 鎮h�呭鍚�
+     * @param titleName   閫氱煡鏍囬
+     * @param content     閫氱煡鍐呭
+     * @param url         閾炬帴鍦板潃
+     * @return 鎺ュ彛鍘熷鍝嶅簲锛涙湰鍦版牎楠屽け璐ユ椂杩斿洖 {"code":-1,"msg":"澶辫触鍘熷洜"}
+     */
+    public static String sendChatLs(String configJson, String mobile, String idCard, String patientName,
+                                    String titleName, String content, String url) {
+        return sendChatLs(LsWxConfig.of(configJson), mobile, idCard, patientName, titleName, content, url);
+    }
+
+    /**
+     * 鑾峰彇涓芥按寰俊璁块棶浠ょ墝锛屼紭鍏堜娇鐢ㄧ紦瀛�
+     */
+    private static String getLsWxToken(LsWxConfig config) throws IOException {
+        String cacheKey = tokenCacheKey(config);
+        long now = System.currentTimeMillis();
+        LsWxToken cached = LS_WX_TOKEN_CACHE.get(cacheKey);
+        if (cached != null && cached.getExpireAt() > now) {
+            return cached.getToken();
+        }
+
+        String url = config.url(LS_WX_TOKEN_PATH)
+                + "?appId=" + encode(config.getAppId())
+                + "&appSecret=" + encode(config.getAppSecret());
+        String resp = lsWxRequest("GET", url, null, null, config);
+        log.info("銆愪附姘村井淇°�戣幏鍙杢oken鍝嶅簲锛歿}", resp);
+        if (StringUtils.isEmpty(resp)) {
+            return null;
+        }
+        JSONObject json = JSON.parseObject(resp);
+        if (json == null || json.getIntValue("code") != 0) {
+            log.error("銆愪附姘村井淇°�戣幏鍙杢oken澶辫触锛歿}", resp);
+            return null;
+        }
+        JSONObject data = json.getJSONObject("data");
+        String token = data == null ? null : data.getString("token");
+        if (StringUtils.isEmpty(token)) {
+            log.error("銆愪附姘村井淇°�戣幏鍙杢oken澶辫触锛屽搷搴斾腑娌℃湁token锛歿}", resp);
+            return null;
+        }
+
+        long expiresIn = data.getLongValue("expiresIn");
+        if (expiresIn <= 0) {
+            expiresIn = 3000L;
+        }
+        long expireAt = now + Math.max(expiresIn - LS_WX_TOKEN_REFRESH_AHEAD_SECONDS, 1L) * 1000L;
+        LS_WX_TOKEN_CACHE.put(cacheKey, new LsWxToken(token, expireAt));
+        return token;
+    }
+
+    /**
+     * 鏍规嵁妯℃澘鍚嶇О鏌ヨ妯℃澘ID
+     */
+    private static Long findLsWxTemplateId(LsWxConfig config, String token, String templateName) throws IOException {
+        if (StringUtils.isEmpty(templateName)) {
+            return null;
+        }
+        String url = config.url(LS_WX_TEMPLATE_PATH) + "?appId=" + encode(config.getAppId());
+        Map<String, String> headers = new HashMap<>(2);
+        headers.put(LS_WX_TOKEN_HEADER, token);
+        String resp = lsWxRequest("GET", url, null, headers, config);
+        log.info("銆愪附姘村井淇°�戣幏鍙栨ā鏉垮搷搴旓細{}", resp);
+        if (StringUtils.isEmpty(resp)) {
+            return null;
+        }
+        JSONObject json = JSON.parseObject(resp);
+        if (json == null || json.getIntValue("code") != 0) {
+            log.error("銆愪附姘村井淇°�戣幏鍙栨ā鏉垮け璐ワ細{}", resp);
+            return null;
+        }
+        JSONArray data = json.getJSONArray("data");
+        if (data == null) {
+            return null;
+        }
+        for (int i = 0; i < data.size(); i++) {
+            JSONObject item = data.getJSONObject(i);
+            if (item != null && templateName.equals(item.getString("tmpName"))) {
+                return item.getLong("id");
+            }
+        }
+        log.error("銆愪附姘村井淇°�戞湭鎵惧埌妯℃澘锛歿}", templateName);
+        return null;
+    }
+
+    /**
+     * 鍒ゆ柇鍝嶅簲鏄惁灞炰簬浠ょ墝澶辨晥
+     */
+    private static boolean isLsWxTokenInvalid(String resp) {
+        if (StringUtils.isEmpty(resp)) {
+            return false;
+        }
+        try {
+            JSONObject json = JSON.parseObject(resp);
+            if (json == null) {
+                return false;
+            }
+            int code = json.getIntValue("code");
+            if (code == 401 || code == 403) {
+                return true;
+            }
+            String msg = json.getString("msg");
+            if (StringUtils.isEmpty(msg)) {
+                return false;
+            }
+            String lower = msg.toLowerCase();
+            return (lower.contains("token") || msg.contains("浠ょ墝"))
+                    && (lower.contains("expire") || lower.contains("invalid")
+                    || msg.contains("澶辨晥") || msg.contains("杩囨湡"));
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    /**
+     * 鍙戦�佷附姘村井淇� HTTP 璇锋眰
+     */
+    private static String lsWxRequest(String method, String url, String body,
+                                      Map<String, String> headers, LsWxConfig config) throws IOException {
+        HttpURLConnection connection = null;
+        try {
+            connection = (HttpURLConnection) new URL(url).openConnection();
+            connection.setRequestMethod(method);
+            connection.setConnectTimeout(config.getConnectTimeout() == null ? 5000 : config.getConnectTimeout());
+            connection.setReadTimeout(config.getReadTimeout() == null ? 10000 : config.getReadTimeout());
+            connection.setRequestProperty("Accept", "*/*");
+            if (headers != null) {
+                for (Map.Entry<String, String> entry : headers.entrySet()) {
+                    connection.setRequestProperty(entry.getKey(), entry.getValue());
+                }
+            }
+            if (body != null) {
+                connection.setDoOutput(true);
+                connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+                try (OutputStream os = connection.getOutputStream()) {
+                    os.write(body.getBytes(StandardCharsets.UTF_8));
+                }
+            }
+
+            int status = connection.getResponseCode();
+            InputStream inputStream = status >= 200 && status < 300
+                    ? connection.getInputStream() : connection.getErrorStream();
+            String resp = readStream(inputStream);
+            if (status < 200 || status >= 300) {
+                log.warn("銆愪附姘村井淇°�戣姹傝繑鍥為潪200锛屽湴鍧�锛歿}锛岀姸鎬佺爜锛歿}锛屽搷搴旓細{}", url, status, resp);
+            }
+            return resp;
+        } finally {
+            if (connection != null) {
+                connection.disconnect();
+            }
+        }
+    }
+
+    /**
+     * 璇诲彇鍝嶅簲娴�
+     */
+    private static String readStream(InputStream inputStream) throws IOException {
+        if (inputStream == null) {
+            return "";
+        }
+        StringBuilder result = new StringBuilder();
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                result.append(line);
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * 浠ょ墝缂撳瓨key
+     */
+    private static String tokenCacheKey(LsWxConfig config) {
+        return config.getBaseUrl() + "|" + config.getAppId();
+    }
+
+    /**
+     * URL鍙傛暟缂栫爜
+     */
+    private static String encode(String value) {
+        if (value == null) {
+            return "";
+        }
+        try {
+            return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
+        } catch (Exception e) {
+            return value;
+        }
+    }
+
+    /**
+     * null杞┖瀛楃涓�
+     */
+    private static String nvl(String value) {
+        return value == null ? "" : value;
+    }
+
+    /**
+     * 鏋勯�犳湰鍦板け璐ュ搷搴�
+     */
+    private static String lsWxFail(String msg) {
+        JSONObject json = new JSONObject(true);
+        json.put("code", -1);
+        json.put("msg", msg);
+        return json.toJSONString();
+    }
 }

--
Gitblit v1.9.3