From f24fcdf2e20eccf6b155e83cb11136503138d5f7 Mon Sep 17 00:00:00 2001 From: qfrjava <13402782+qfrjava@user.noreply.gitee.com> Date: 星期四, 06 三月 2025 14:35:48 +0800 Subject: [PATCH] refactor(smtaiserver):重构微信控制类 --- JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTAIWeixinControl.java | 374 +++++++++++++++-------------------------------------- 1 files changed, 105 insertions(+), 269 deletions(-) diff --git a/JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTAIWeixinControl.java b/JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTAIWeixinControl.java index 2c2b918..d02c495 100644 --- a/JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTAIWeixinControl.java +++ b/JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTAIWeixinControl.java @@ -7,11 +7,13 @@ import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecords; import com.smtaiserver.smtaiserver.javaai.ast.ASTDBMap; import com.smtaiserver.smtaiserver.javaai.llm.core.SMTLLMConnect; +import com.smtaiserver.smtaiserver.util.SMTWXSStatic.WeixinuUtil; import com.smtservlet.core.SMTRequest; import com.smtservlet.util.Json; import com.smtservlet.util.SMTJsonWriter; import com.smtservlet.util.SMTStatic; +import okhttp3.OkHttpClient; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.dom4j.Document; @@ -23,20 +25,18 @@ import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; import java.io.IOException; import java.io.OutputStream; -import java.io.StringWriter; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.sql.Timestamp; import java.util.*; import java.util.concurrent.CompletableFuture; +import static com.smtaiserver.smtaiserver.util.SMTWXSStatic.WeixinuUtil.*; import static java.util.Arrays.sort; public class SMTAIWeixinControl { @@ -46,27 +46,29 @@ private static final String CONTENT = "Content"; private static Logger _logger = LogManager.getLogger(SMTAIServerControl.class); - private Object _lockToken = new Object(); + private final Object _lockToken = new Object(); private String _tokenValue = null; private long _tokenTicket = 0; + private OkHttpClient _web; /** 寰俊楠岃瘉 */ public ModelAndView weChatNotify(SMTAIServerRequest tranReq) throws Exception { String method = tranReq.getRequest().getMethod(); - if (method.equals("GET")) return getModelAndView(tranReq); + if (method.equals("GET")) return WeixinuUtil.getModelAndView(tranReq); return reply(tranReq); } /** 琚姩鍥炲 */ - private ModelAndView reply(SMTAIServerRequest tranReq) throws Exception { + private ModelAndView reply(SMTAIServerRequest tranReq) { + long l = System.currentTimeMillis() / 1000; + String createTimeStr = String.valueOf(l); HttpServletRequest request = tranReq.getRequest(); Map<String, String> requestMap = getWechatReqMap(request); + String fromUserName = requestMap.get(FROM_USER_NAME); + String toUserName = requestMap.get(TO_USER_NAME); if (requestMap.isEmpty()) { return null; } - // wechatMessage.setFromUserName(requestMap.get(TO_USER_NAME)); - // wechatMessage.setToUserName(requestMap.get(FROM_USER_NAME)); - // wechatMessage.setCreateTime(System.currentTimeMillis() / 1000); String xmltemp = "<xml>\n" + " <ToUserName><![CDATA[{{{toUser}}}]]></ToUserName>\n" @@ -75,42 +77,13 @@ + " <MsgType><![CDATA[text]]></MsgType>\n" + " <Content><![CDATA[鎴戞鍦ㄦ�濊�冨摝~璇风◢绛夆�︹�]></Content>\n" + "</xml>"; - long l = System.currentTimeMillis() / 1000; - String createTimeStr = String.valueOf(l); // 灏� long 杞崲涓� String // 鏇挎崲鍗犱綅绗� String result = xmltemp - .replace("{{{toUser}}}", requestMap.get(TO_USER_NAME)) - .replace("{{{fromUser}}}", requestMap.get(FROM_USER_NAME)) + .replace("{{{toUser}}}", fromUserName) + .replace("{{{fromUser}}}", toUserName) .replace("{{{CreateTime}}}", createTimeStr); String reqContent = requestMap.get(CONTENT); - // 璁剧疆娑堟伅绫诲瀷 - // switch (reqContent) { - // case "鏂囧瓧": - // wechatMessage.setMsgType("text"); - // break; - // case "鍥剧墖": - // wechatMessage.setMsgType("image"); - // break; - // case "璇煶": - // wechatMessage.setMsgType("voice"); - // break; - // case "瑙嗛": - // wechatMessage.setMsgType("video"); - // break; - // case "闊充箰": - // wechatMessage.setMsgType("music"); - // break; - // case "鍥炬枃": - // wechatMessage.setMsgType("news"); - // break; - // default: - // wechatMessage.setMsgType("text"); - // break; - // } - - // MediaVo media = new MediaVo(); - // wechatMessage.setContent("鎴戞鍦ㄦ�濊�冨摝~璇风◢绛夆�︹��"); // 寮傛璋冪敤 aiReplyToTheUserASecondTime CompletableFuture.runAsync( () -> { @@ -121,57 +94,10 @@ _logger.error("aiReplyToTheUserASecondTime error", e); } }); - - // 璁剧疆娑堟伅鍐呭 - // switch (reqContent) { - // case "鏂囧瓧": - // wechatMessage.setContent("鎴戞鍦ㄦ�濊�冨摝~璇风◢绛夆�︹��"); - // // 寮傛璋冪敤 aiReplyToTheUserASecondTime - // CompletableFuture.runAsync( - // () -> { - // try { - // aiReplyToTheUserASecondTime(tranReq, requestMap.get(FROM_USER_NAME)); - // } catch (Exception e) { - // e.printStackTrace(); - // } - // }); - // break; - // case "鍥剧墖": - // media.setMediaId("SI7HPwMI5PL1QV_I9M5AFw6K-1ZVMyTGE0-a5jQM4czTmffKTQpHa6zlYDmvIAPX"); - // wechatMessage.setImage(media); - // break; - // case "璇煶": - // media.setMediaId("c6hRH_X2HGwrOa1MiTQAcg35D7M42Xa4VMhyzSFMk8MA0pWFhly19W4K3W5NaH4b"); - // wechatMessage.setVoice(media); - // break; - // case "瑙嗛": - // media.setMediaId("c6hRH_X2HGwrOa1MiTQAcmo7zQjGAIV7uSP1U1S-tsnR0VJXUS0y10Z5FkaueU5Y"); - // media.setTitle("浣犲ソ"); - // media.setDescription("浣犲ソ鍟�"); - // wechatMessage.setVideo(media); - // break; - // case "闊充箰": - // System.out.println("杩涘叆闊充箰鍒嗘敮"); - // break; - // case "鍥炬枃": - // System.out.println("杩涘叆鍥炬枃鍒嗘敮"); - // break; - // default: - // System.out.println("杩涘叆榛樿鍒嗘敮"); - // wechatMessage.setContent("鎴戜笉澶璇嗕綘鐨勮緭鍏ュ摝"); - // break; - // } - try { - // 灏� WechatMessageVO 瀵硅薄杞崲涓� XML - // JAXBContext jaxbContext = JAXBContext.newInstance(WechatMessageVO.class); - // Marshaller marshaller = jaxbContext.createMarshaller(); - // marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); - // StringWriter sw = new StringWriter(); - // marshaller.marshal(wechatMessage, sw); - _logger.info("寰俊娑堟伅杩斿弬锛�" + xmltemp); + _logger.info("寰俊娑堟伅杩斿弬锛�" + result); // 杩斿洖 XML 瀛楃涓� - return tranReq.returnText(xmltemp.toString()); + return tranReq.returnText(result); } catch (Exception e) { throw new RuntimeException(e); } @@ -203,41 +129,45 @@ SMTLLMConnect llm = SMTAIServerApp.getApp().allocLLMConnect(null); String answer = llm.callWithMessage(new String[] {prompt}, question, tranReq); tranReq.traceLLMDebug(answer); - List<Json> jsonASTList = SMTStatic.convLLMAnswerToJson(answer, true).asJsonList(); - if (jsonASTList.size() > 0) { - Json jsonAST = jsonASTList.get(0); - if ("query_water_fee".equals(jsonAST.safeGetStr("call", null))) { - jsonAST = jsonAST.getJson("args"); - try (ASTDBMap dbMap = new ASTDBMap()) { - SMTDatabase db = dbMap.getDatabase("DS_74_CHENGTOU"); - DBRecords recs = - db.querySQL( - " SELECT ROUND(SUM(" - + jsonAST.getJson("value_name").asString() - + ")::NUMERIC(10, 2), 2) AS TOTAL" - + " FROM chengtou_data.bill_data WHERE billing_date BETWEEN ? AND ?", - new Object[] { - SMTStatic.toDate(jsonAST.getJson("start_time").asString()), - SMTStatic.toDate(jsonAST.getJson("end_time").asString()) - }); + Json ojsonASTList = SMTStatic.convLLMAnswerToJson(answer, true); + if (ojsonASTList != null && ojsonASTList.isArray()) { + List<Json> jsonASTList = ojsonASTList.asJsonList(); + if (jsonASTList.size() > 0) { + Json jsonAST = jsonASTList.get(0); + if ("query_water_fee".equals(jsonAST.safeGetStr("call", null))) { + jsonAST = jsonAST.getJson("args"); + try (ASTDBMap dbMap = new ASTDBMap()) { + SMTDatabase db = dbMap.getDatabase("DS_74_CHENGTOU"); + DBRecords recs = + db.querySQL( + " SELECT ROUND(SUM(" + + jsonAST.getJson("value_name").asString() + + ")::NUMERIC(10, 2), 2) AS TOTAL" + + " FROM chengtou_data.bill_data WHERE billing_date BETWEEN ? AND ?", + new Object[] { + SMTStatic.toDate(jsonAST.getJson("start_time").asString()), + SMTStatic.toDate(jsonAST.getJson("end_time").asString()) + }); - if (recs.getRowCount() == 0) + if (recs.getRecord(0).getString(0) == null) + return "浠�" + + jsonAST.getJson("start_time").asString() + + "鍒�" + + jsonAST.getJson("end_time").asString() + + "鐨�" + + jsonAST.getJson("value_title").asString() + + "鏈煡鍒颁换浣曟暟鎹�"; + return "浠�" + jsonAST.getJson("start_time").asString() + "鍒�" + jsonAST.getJson("end_time").asString() + "鐨�" + jsonAST.getJson("value_title").asString() - + "鏈煡鍒颁换浣曟暟鎹�"; - - return "浠�" - + jsonAST.getJson("start_time").asString() - + "鍒�" - + jsonAST.getJson("end_time").asString() - + "鐨�" - + jsonAST.getJson("value_title").asString() - + "鎬昏" - + recs.getRecord(0).getString(0); + + "鎬昏" + + recs.getRecord(0).getString(0) + + ("volume".equals(jsonAST.getJson("value_name").asString()) ? "鍚�" : "鍏�"); + } } } } @@ -250,7 +180,6 @@ public ModelAndView aiReplyToTheUserASecondTime(String answer, String fromUserName) throws Exception { String accessToken = getAccessToken(); - SMTJsonWriter jsonWr = new SMTJsonWriter(false); jsonWr.addKeyValue("touser", fromUserName); jsonWr.addKeyValue("msgtype", "text"); @@ -259,174 +188,81 @@ jsonWr.addKeyValue("content", answer); } jsonWr.endMap(); - // JSONObject jsonObject = new JSONObject(); - // jsonObject.put("touser", fromUserName); - // jsonObject.put("msgtype", "text"); - // JSONObject jsonObject1 = new JSONObject(); - // jsonObject1.put("content", answer); - // jsonObject.put("text", jsonObject1); - // _logger.info("jsonObject: {}", jsonObject); String url = String.format( "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s", accessToken); - // Map<String, Object> stringObjectMap = jsonObjectToMap(jsonWr.getRootJson()); String s = sendPost(url, jsonWr.getRootJson()); _logger.info("涓婁紶缁撴灉: {}", s); return null; } - /** 寰俊楠岃瘉 */ - private static ModelAndView getModelAndView(SMTRequest tranReq) throws Exception { - String signature = tranReq.convParamToString("signature", true); - String timestamp = tranReq.convParamToString("timestamp", true); - String nonce = tranReq.convParamToString("nonce", true); - String echostr = tranReq.convParamToString("echostr", true); - // 鑾峰彇寰俊璇锋眰鍙傛暟 - _logger.info( - "寮�濮嬫牎楠屾娆℃秷鎭槸鍚︽潵鑷井淇℃湇鍔″櫒锛宲aram->signature:{},\ntimestamp:{},\nnonce:{},\nechostr:{}", - signature, - timestamp, - nonce, - echostr); - // 闇�瑕侀獙璇佺殑鏃跺�欏氨鍚敤 - if (checkSignature(signature, timestamp, nonce)) { - return tranReq.returnText(echostr); - } - return tranReq.returnText(""); - } - public String getAccessToken() throws Exception { synchronized (this._lockToken) { - if (_tokenValue == null || (System.currentTimeMillis() - _tokenTicket) > 3600 * 1000) { + SMTDatabase db = SMTAIServerApp.getApp().allocDatabase(); + try { HashMap<String, String> weixinParam = getWeixinParam(); - String url = - "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" - + weixinParam.get("appId") - + "&secret=" - + weixinParam.get("secret"); - String response = HttpUtil.get(url); - JSONObject jsonObject = new JSONObject(response); - if (jsonObject.has("access_token")) { - String accessToken = jsonObject.getString("access_token"); + long ONE_HOUR_IN_MILLIS = 3600 * 1000; + long expiresTime = System.currentTimeMillis() + ONE_HOUR_IN_MILLIS; + Timestamp expiresTimestamp = new Timestamp(expiresTime); + String appId = weixinParam.get("appId"); - _tokenValue = accessToken; - } else { - throw new Exception("can't get weixin token"); + // 鏌ヨ鏈繃鏈熺殑 access_token + DBRecords dbRecord = + db.querySQL( + "SELECT app_id, access_token, expires_time " + + "FROM ai_weixin_token " + + "WHERE app_id = ? " + + " AND expires_time > ?", + new Object[] {appId, expiresTimestamp}); + + // 鏁版嵁搴撴棤璁板綍锛屼粠寰俊鏈嶅姟鍣ㄨ幏鍙� access_token + List<SMTDatabase.DBRecord> records = dbRecord.getRecords(); + boolean res = false; + if (dbRecord.getRowCount() != 0) { + String expires_time = records.get(0).getString("expires_time"); + long dbExpiresTime = Timestamp.valueOf(expires_time).getTime(); + res = System.currentTimeMillis() <= dbExpiresTime; } - _tokenTicket = System.currentTimeMillis(); + // 寰俊鍙栵紝杩斿洖token骞朵笖淇濆瓨鎴栬鐩栨暟鎹� + if (dbRecord.getRowCount() == 0 || !res) { + String accessToken = fetchAccessTokenFromWeixinServer(); // 浠庡井淇℃湇鍔″櫒鑾峰彇 access_token + String sql = + "INSERT INTO ai_weixin_token (app_id, access_token, expires_time) " + + "VALUES (?, ?, ?) " + + "ON CONFLICT (app_id) " + + // 濡傛灉 app_id 鍐茬獊 + "DO UPDATE SET " + + " access_token = EXCLUDED.access_token, " + + " expires_time = EXCLUDED.expires_time;"; + db.executeSQL(sql, new Object[] {appId, accessToken, expiresTimestamp}); + return accessToken; + } else { // 鐩存帴鎷挎暟鎹簱accesstoken + return records.get(0).getString("access_token"); + } + } catch (Exception e) { + throw new Exception("Failed to get access token: " + e); + } finally { + if (db != null) { + db.close(); + } } - return _tokenValue; } } - /** 楠岃瘉绛惧悕util */ - public static boolean checkSignature(String signature, String timestamp, String nonce) - throws Exception { + private String fetchAccessTokenFromWeixinServer() throws Exception { HashMap<String, String> weixinParam = getWeixinParam(); - String[] arr = new String[] {weixinParam.get("token"), timestamp, nonce}; - // 灏唗oken銆乼imestamp銆乶once涓変釜鍙傛暟杩涜瀛楀吀搴忔帓搴� - // Arrays.sort(arr); - sort(arr); - StringBuilder content = new StringBuilder(); - for (String s : arr) { - content.append(s); - } - MessageDigest md = null; - String tmpStr = null; - - try { - md = MessageDigest.getInstance("SHA-1"); - // 灏嗕笁涓弬鏁板瓧绗︿覆鎷兼帴鎴愪竴涓瓧绗︿覆杩涜sha1鍔犲瘑 - byte[] digest = md.digest(content.toString().getBytes()); - tmpStr = byteToStr(digest); - } catch (NoSuchAlgorithmException e) { - _logger.error("绛惧悕寮傚父", e); - } - content = null; - // 灏唖ha1鍔犲瘑鍚庣殑瀛楃涓插彲涓巗ignature瀵规瘮锛屾爣璇嗚璇锋眰鏉ユ簮浜庡井淇� - - return tmpStr != null && tmpStr.equals(signature.toUpperCase()); - } - - private static HashMap<String, String> getWeixinParam() throws Exception { - Object weixinParam = SMTAIServerApp.getApp().getGlobalConfig("weixin_core_param", "false"); - _logger.info("寰俊鍙傛暟锛歿}", weixinParam); - JSONObject weixinJson = new JSONObject(weixinParam.toString()); - String appId = (String) weixinJson.get("appId"); - String secret = (String) weixinJson.get("secret"); - String token = (String) weixinJson.get("token"); - HashMap<String, String> paramMap = new HashMap<>(); - paramMap.put("appId", appId); - paramMap.put("secret", secret); - paramMap.put("token", token); - return paramMap; - } - - public static Map<String, String> getWechatReqMap(HttpServletRequest request) { - Map<String, String> requestMap = new HashMap<>(); - SAXReader reader = new SAXReader(); - try (ServletInputStream inputStream = request.getInputStream()) { - Document document = reader.read(inputStream); - Element root = document.getRootElement(); - List<Element> elementList = root.elements(); - for (Element e : elementList) { - requestMap.put(e.getName(), e.getText()); - } - } catch (IOException | DocumentException e) { - throw new RuntimeException(e); - } - return requestMap; - } - - /** - * 灏嗗瓧鑺傛暟缁勮浆鎹负鍗佸叚杩涘埗瀛楃涓� - * - * @param byteArray - * @return - */ - private static String byteToStr(byte[] byteArray) { - StringBuilder strDigest = new StringBuilder(); - for (byte b : byteArray) { - strDigest.append(byteToHexStr(b)); - } - return strDigest.toString(); - } - - /** - * 灏嗗瓧鑺傝浆鎹负鍗佸叚杩涘埗瀛楃涓� - * - * @param mByte - * @return - */ - private static String byteToHexStr(byte mByte) { - char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - char[] tempArr = new char[2]; - tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; - tempArr[1] = Digit[mByte & 0X0F]; - String s = new String(tempArr); - return s; - } - - public static String sendPost(String urlString, Json jsonParam) throws Exception { - // 灏嗗弬鏁拌浆鎹负 JSON 鏍煎紡瀛楃涓� - // JSONObject jsonParams = new JSONObject(params); - String payload = jsonParam.toString(); - // 鍒涘缓杩炴帴 - URL url = new URL(urlString); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("POST"); - // 璁剧疆璇锋眰澶� - connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); - connection.setDoOutput(true); - // 鍐欏叆璇锋眰浣� - try (OutputStream os = connection.getOutputStream()) { - byte[] input = payload.getBytes(StandardCharsets.UTF_8); - os.write(input, 0, input.length); - } - // 璇诲彇鍝嶅簲 - try (java.io.InputStream in = connection.getInputStream()) { - java.util.Scanner scanner = new java.util.Scanner(in).useDelimiter("\\A"); - return scanner.hasNext() ? scanner.next() : ""; + String url = + "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + + weixinParam.get("appId") + + "&secret=" + + weixinParam.get("secret"); + String response = HttpUtil.get(url); + Json json = Json.read(response); + String accessToken = json.safeGetStr("access_token", null); + if (accessToken != null) { + return accessToken; + } else { + throw new Exception("can't get weixin token : " + json); } } } -- Gitblit v1.9.3