TangCheng
8 天以前 4e6c02a5fc3991d11c44283b677fcda4252c489a
Merge branch 'master' of http://47.103.154.90:83/r/WI/Service.V1.0
已修改3个文件
已添加9个文件
612 ■■■■■ 文件已修改
.idea/Service.V1.0.iml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/misc.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/modules.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/vcs.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/workspace.xml 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTAIWeixinControl.java 346 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTKnowledgeControl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/util/SMTWXSStatic.java 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTAIServer/src/main/resources/requestmap/weixin.json 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTAIServer/src/main/resources/spring-config-aiserver.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTServlet/.idea/codeStyles/codeStyleConfig.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JAVA/SMTServlet/src/main/java/com/smtservlet/core/SMTRequest.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/Service.V1.0.iml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$" />
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>
.idea/misc.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectRootManager">
    <output url="file://$PROJECT_DIR$/out" />
  </component>
</project>
.idea/modules.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectModuleManager">
    <modules>
      <module fileurl="file://$PROJECT_DIR$/.idea/Service.V1.0.iml" filepath="$PROJECT_DIR$/.idea/Service.V1.0.iml" />
    </modules>
  </component>
</project>
.idea/vcs.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="" vcs="Git" />
  </component>
</project>
.idea/workspace.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ChangeListManager">
    <list default="true" id="9b028a58-b5e6-412e-aa77-b791b5d1d839" name="Changes" comment="" />
    <option name="SHOW_DIALOG" value="false" />
    <option name="HIGHLIGHT_CONFLICTS" value="true" />
    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
    <option name="LAST_RESOLUTION" value="IGNORE" />
  </component>
  <component name="MarkdownSettingsMigration">
    <option name="stateVersion" value="1" />
  </component>
  <component name="ProjectColorInfo"><![CDATA[{
  "associatedIndex": 3
}]]></component>
  <component name="ProjectId" id="2u6nLRVazjvwQ4iyxpATXcPxo0Z" />
  <component name="ProjectViewState">
    <option name="hideEmptyMiddlePackages" value="true" />
    <option name="showLibraryContents" value="true" />
  </component>
  <component name="PropertiesComponent"><![CDATA[{
  "keyToString": {
    "RunOnceActivity.OpenProjectViewOnStart": "true",
    "RunOnceActivity.ShowReadmeOnStart": "true",
    "WebServerToolWindowFactoryState": "false",
    "vue.rearranger.settings.migration": "true"
  }
}]]></component>
  <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
  <component name="TaskManager">
    <task active="true" id="Default" summary="Default task">
      <changelist id="9b028a58-b5e6-412e-aa77-b791b5d1d839" name="Changes" comment="" />
      <created>1741577834674</created>
      <option name="number" value="Default" />
      <option name="presentableId" value="Default" />
      <updated>1741577834674</updated>
      <workItem from="1741577838432" duration="9000" />
    </task>
    <servers />
  </component>
  <component name="TypeScriptGeneratedFilesManager">
    <option name="version" value="3" />
  </component>
</project>
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTAIWeixinControl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,346 @@
package com.smtaiserver.smtaiserver.control;
import com.smtaiserver.smtaiserver.core.SMTAIServerApp;
import com.smtaiserver.smtaiserver.core.SMTAIServerRequest;
import com.smtaiserver.smtaiserver.database.SMTDatabase;
import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecords;
import com.smtaiserver.smtaiserver.javaai.SMTJavaAIChat;
import com.smtaiserver.smtaiserver.util.SMTWXSStatic;
import com.smtservlet.util.Json;
import com.smtservlet.util.SMTJsonWriter;
import com.smtservlet.util.SMTStatic;
import java.util.*;
import javax.servlet.http.HttpServletRequest;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.web.servlet.ModelAndView;
public class SMTAIWeixinControl {
    private static final HashMap<String, String> asynchronousList = new HashMap<>();
    private static final String FROM_USER_NAME = "FromUserName";
    private static final String TO_USER_NAME = "ToUserName";
    private static final String CONTENT = "Content";
    private static final Logger _logger = LogManager.getLogger(SMTAIServerControl.class);
    private final Object _lockToken = new Object();
    /**
     * å¾®ä¿¡éªŒè¯
     */
    public ModelAndView weChatNotify(SMTAIServerRequest tranReq) throws Exception {
        String method = tranReq.getRequest().getMethod();
        if (method.equals("GET")) return SMTWXSStatic.getModelAndView(tranReq);
        return reply(tranReq);
    }
  /** è¢«åŠ¨å›žå¤ */
  private ModelAndView reply(SMTAIServerRequest tranReq) {
    long l = System.currentTimeMillis() / 1000;
    String createTimeStr = String.valueOf(l);
    HttpServletRequest request = tranReq.getRequest();
    Map<String, String> requestMap = SMTWXSStatic.getWechatReqMap(request);
    String fromUserName = requestMap.get(FROM_USER_NAME);
    String toUserName = requestMap.get(TO_USER_NAME);
    if (requestMap.isEmpty()) {
      return null;
    }
    String reqContent = requestMap.get(CONTENT);
    if (asynchronousList.get(fromUserName) != null && !reqContent.equals("停止输出")) {
      String dissuadeReturn = dissuadeReturn(fromUserName, toUserName, createTimeStr);
      return tranReq.returnText(dissuadeReturn);
    }
    UUID randomUuid = UUID.randomUUID();
    asynchronousList.put(fromUserName, randomUuid.toString());
    String reply;
    reply = getReply(reqContent);
    String textContent =
        "我正在思考哦~请稍等……\n<a href=\"weixin://bizmsgmenu?msgmenucontent=停止输出&msgmenuid=101\">停止输出</a>";
    String baiduTextContent = "我是百度\n<a href=\"www.baidu.com\">百度</a>";
    String result =
        getString(
            fromUserName,
            toUserName,
            createTimeStr,
            reply,
            null,
            "https://pics0.baidu.com/feed/d31b0ef41bd5ad6e9388c7f8d8eda0d4b6fd3c60.png@f_auto?token=3da8e06f44a46832a7d0f50fa9e92c34",
            "总书记引用的这些古语耐人寻味",
            "“没有规矩,不成方圆”、“己不正,焉能正人”、“尽小者大,慎微者著”……总书记引用的这些古语耐人寻味。",
            "https://www.baidu.com/s?&wd=%E6%80%BB%E4%B9%A6%E8%AE%B0%E5%BC%95%E7%94%A8%E7%9A%84%E8%BF%99%E4%BA%9B%E5%8F%A4%E8%AF%AD%E8%80%90%E4%BA%BA%E5%AF%BB%E5%91%B3",
            null);
    if (reqContent.equals("停止输出")) {
      asynchronousList.remove(fromUserName);
      _logger.info("用户停止输出");
      return null;
    }
        // å¼‚步调用 aiReplyToTheUserASecondTime
//    CompletableFuture.runAsync(
//        () -> {
//          try {
//            SMTAIServerRequest threadTranReq = new SMTAIServerRequest();
//            threadTranReq.initInstance(null, "", null);
//            String answer = callAIForAnswerQuestion(reqContent, threadTranReq); // Ai调用 è¿”回结果
//            aiReplyToTheUserASecondTime(
//                answer, requestMap.get(FROM_USER_NAME), randomUuid.toString());
//          } catch (Exception e) {
//            _logger.error("aiReplyToTheUserASecondTime error", e);
//            asynchronousList.remove(request.getParameter("FromUserName"));
//          }
//        });
        _logger.info("微信消息返参:" + result);
        // è¿”回 XML å­—符串
        return tranReq.returnText(result);
    }
//  public ModelAndView weChatTest(SMTAIServerRequest tranReq) throws Exception {
//    String question = "冰箱是什么";
//    tranReq.setAIQuestion(question);
//    tranReq.setTextResultMode();
//
//    Set<String> setAgentGroup = new HashSet<>();
//    String weixinGroupId =
//        (String) SMTAIServerApp.getApp().getGlobalConfig("weixin.group_id", false);
//    setAgentGroup.add(weixinGroupId);
//
//    SMTJavaAIChat.questionChat("aliyun", setAgentGroup, "业务场景", question, null, false, tranReq);
//    String text = tranReq.getTextResult();
//
//    return tranReq.returnText(text);
//  }
  /** ai回复 */
//  private String callAIForAnswerQuestion(String question, SMTAIServerRequest tranReq)
//      throws Exception {
//    tranReq.setAIQuestion(question);
//    tranReq.setTextResultMode();
//
//    Set<String> setAgentGroup = new HashSet<>();
//    String weixinGroupId =
//        (String) SMTAIServerApp.getApp().getGlobalConfig("weixin.group_id", false);
//    setAgentGroup.add(weixinGroupId);
//
//    SMTJavaAIChat.questionChat("aliyun", setAgentGroup, "业务场景", question, null, false, tranReq);
//    return tranReq.getTextResult();
//  }
  /** äºŒæ¬¡å›žå¤ */
  public void aiReplyToTheUserASecondTime(String answer, String fromUserName, String abortID)
      throws Exception {
    String accessToken = getAccessToken();
    if (answer.isEmpty()) answer = "抱歉,我暂时无法理解您的问题。";
    SMTJsonWriter jsonWr = new SMTJsonWriter(false);
    jsonWr.addKeyValue("touser", fromUserName);
    jsonWr.addKeyValue("msgtype", "text");
    jsonWr.beginMap("text");
    {
      jsonWr.addKeyValue("content", answer);
    }
    jsonWr.endMap();
    String url =
        String.format(
            "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s", accessToken);
    if (abortID.equals(asynchronousList.get(fromUserName))) {
      String s = SMTWXSStatic.sendPost(url, jsonWr.getRootJson());
      asynchronousList.remove(fromUserName);
      _logger.info("上传结果: : " + s);
    } else {
      asynchronousList.remove(fromUserName);
      _logger.info("异步调用被取消");
    }
  }
  /** æ•°æ®åº“获取 access_koen */
  public String getAccessToken() throws Exception {
    synchronized (this._lockToken) {
      SMTDatabase db = SMTAIServerApp.getApp().allocDatabase();
      //      try (SMTDatabase db = SMTAIServerApp.getApp().allocDatabase()) {
      HashMap<String, String> weixinParam = SMTWXSStatic.getWeixinParam();
      Date curTime = new Date();
      String appId = weixinParam.get("appId");
      // æŸ¥è¯¢æœªè¿‡æœŸçš„ 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, curTime});
      // æ•°æ®åº“无记录,从微信服务器获取 access_token
      List<SMTDatabase.DBRecord> records = dbRecord.getRecords();
      if (dbRecord.getRowCount() > 0) {
        return records.get(0).getString("access_token");
      }
      // å¾®ä¿¡å–,返回token并且保存或覆盖数据
      else {
        Object[] accessToken = fetchAccessTokenFromWeixinServer(); // ä»Žå¾®ä¿¡æœåŠ¡å™¨èŽ·å– access_token
        Date expiresTime =
            SMTStatic.calculateTime(
                curTime, SMTStatic.SMTCalcTime.ADD_SECOND, ((int) accessToken[1]) / 2);
        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[0], expiresTime});
        return (String) accessToken[0];
      }
      //      } catch (Exception e) {
      //        throw new Exception("Failed to get access token", e);
      //
      //      }
    }
  }
  /** ä»Žå¾®ä¿¡æœåŠ¡å™¨èŽ·å– access_token */
  private Object[] fetchAccessTokenFromWeixinServer() throws Exception {
    HashMap<String, String> weixinParam = SMTWXSStatic.getWeixinParam();
    OkHttpClient okHttpClient = new OkHttpClient();
    // åˆ›å»ºè¯·æ±‚
    Request request =
        new Request.Builder()
            .url(
                "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
                    + weixinParam.get("appId")
                    + "&secret="
                    + weixinParam.get("secret")) // è¯·æ±‚URL
            .get() // ä½¿ç”¨GET方法
            .build();
    Response response = okHttpClient.newCall(request).execute();
    if (!response.isSuccessful() || response.body() == null) {
      throw new Exception("can't get weixin token");
    }
    Json json = Json.read(response.body().string());
    String accessToken = json.safeGetStr("access_token", null);
    String expiresIn = json.safeGetStr("expires_in", null);
    if (accessToken != null) {
      return new Object[] {accessToken, SMTStatic.toInt(expiresIn)};
    } else {
      _logger.info("can't get weixin token : " + json);
      return null;
      //      throw new Exception("can't get weixin token : " + json);
    }
  }
    @NotNull
    private static String getString(String fromUserName, String toUserName, String createTimeStr, String msgType, String content, String mediaId, String title, String description, String musicUrl, String hqMusicUrl) {
        StringBuilder xmlBuilder = new StringBuilder();
        xmlBuilder.append("<xml>\n")
                .append("  <ToUserName><![CDATA[").append(fromUserName).append("]]></ToUserName>\n")
                .append("  <FromUserName><![CDATA[").append(toUserName).append("]]></FromUserName>\n")
                .append("  <CreateTime>").append(createTimeStr).append("</CreateTime>\n")
                .append("  <MsgType><![CDATA[").append(msgType).append("]]></MsgType>\n");
        switch (msgType) {
            case "text":
                xmlBuilder.append("  <Content><![CDATA[").append(content).append("]]></Content>\n");
                break;
            case "image":
                xmlBuilder.append("  <Image><MediaId><![CDATA[").append(mediaId).append("]]></MediaId></Image>\n");
                break;
            case "voice":
                xmlBuilder.append("  <Voice><MediaId><![CDATA[").append(mediaId).append("]]></MediaId></Voice>\n");
                break;
            case "video":
                xmlBuilder.append("  <Video>\n")
                        .append("    <MediaId><![CDATA[").append(mediaId).append("]]></MediaId>\n")
                        .append("    <Title><![CDATA[").append(title).append("]]></Title>\n")
                        .append("    <Description><![CDATA[").append(description).append("]]></Description>\n")
                        .append("  </Video>\n");
                break;
            case "music":
                xmlBuilder.append("  <Music>\n")
                        .append("    <Title><![CDATA[").append(title).append("]]></Title>\n")
                        .append("    <Description><![CDATA[").append(description).append("]]></Description>\n")
                        .append("    <MusicUrl><![CDATA[").append(musicUrl).append("]]></MusicUrl>\n")
                        .append("    <HQMusicUrl><![CDATA[").append(hqMusicUrl).append("]]></HQMusicUrl>\n")
                        .append("    <ThumbMediaId><![CDATA[").append(mediaId).append("]]></ThumbMediaId>\n")
                        .append("  </Music>\n");
                break;
            case "news": // å›¾æ–‡æ¶ˆæ¯
                xmlBuilder.append("  <ArticleCount>2</ArticleCount>\n")
                        .append("  <Articles>\n")
                        .append("    <item>\n")
                        .append("      <Title><![CDATA[").append(title).append("]]></Title>\n")
                        .append("      <Description><![CDATA[").append(description).append("]]></Description>\n")
                        .append("      <PicUrl><![CDATA[").append(mediaId).append("]]></PicUrl>\n")
                        .append("      <Url><![CDATA[").append(musicUrl).append("]]></Url>\n")
                        .append("    </item>\n")
                        .append("  </Articles>\n");
                break;
            default:
                xmlBuilder.append("  <Content><![CDATA[未知的消息类型]]></Content>\n");
        }
        xmlBuilder.append("</xml>");
        return xmlBuilder.toString();
    }
    /**
     * ç”¨äºŽæµ‹è¯•,正常可以不用
     *
     * @param reqContent
     * @return
     */
    @NotNull
    private static String getReply(String reqContent) {
        String reply;
        switch (reqContent) {
            case "文字":
                reply = "text";
                break;
            case "图片":
                reply = "image";
                break;
            case "语音":
                reply = "voice";
                break;
            case "视频":
                reply = "video";
                break;
            case "音乐":
                reply = "music";
                break;
            case "图文":
                reply = "news";
                break;
            default:
                reply = "text";
                break;
        }
        return reply;
    }
    private static String dissuadeReturn(
            String fromUserName, String toUserName, String createTimeStr) {
        String xmltemp =
                "<xml>\n"
                        + "  <ToUserName><![CDATA[{{{toUser}}}]]></ToUserName>\n"
                        + "  <FromUserName><![CDATA[{{{fromUser}}}]]></FromUserName>\n"
                        + "  <CreateTime>{{{CreateTime}}}</CreateTime>\n"
                        + "  <MsgType><![CDATA[text]]></MsgType>\n"
                        + "  <Content><![CDATA[上一条消息还在加载中哦,请稍等或点击下次停止上一轮回复\n<a href=\"weixin://bizmsgmenu?msgmenucontent=停止输出&msgmenuid=101\">停止输出</a>]]></Content>\n"
                        + "  <Content><![CDATA[]]></Content>\n"
                        + "</xml>";
        // æ›¿æ¢å ä½ç¬¦
        return xmltemp
                .replace("{{{toUser}}}", fromUserName)
                .replace("{{{fromUser}}}", toUserName)
                .replace("{{{CreateTime}}}", createTimeStr);
    }
}
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/control/SMTKnowledgeControl.java
@@ -1,13 +1,5 @@
package com.smtaiserver.smtaiserver.control;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.*;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import com.smtaiserver.smtaiserver.core.SMTAIServerApp;
import com.smtaiserver.smtaiserver.core.SMTAIServerRequest;
import com.smtaiserver.smtaiserver.core.SMTCheckChatStreamView;
@@ -18,6 +10,12 @@
import com.smtaiserver.smtaiserver.javaai.qwen.agent.SMTQwenAgent;
import com.smtservlet.util.SMTJsonWriter;
import com.smtservlet.util.SMTStatic;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.*;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
public class SMTKnowledgeControl
{
JAVA/SMTAIServer/src/main/java/com/smtaiserver/smtaiserver/util/SMTWXSStatic.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,149 @@
package com.smtaiserver.smtaiserver.util;
import com.smtaiserver.smtaiserver.control.SMTAIServerControl;
import com.smtaiserver.smtaiserver.core.SMTAIServerApp;
import com.smtservlet.core.SMTRequest;
import com.smtservlet.util.Json;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.Arrays.sort;
public class SMTWXSStatic {
  private static Logger _logger = LogManager.getLogger(SMTAIServerControl.class);
  /** å¾®ä¿¡éªŒè¯ */
  public 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(
        "开始校验此次消息是否来自微信服务器,param->signature:{},\ntimestamp:{},\nnonce:{},\nechostr:{}",
        signature,
        timestamp,
        nonce,
        echostr);
    // éœ€è¦éªŒè¯çš„æ—¶å€™å°±å¯ç”¨
    if (checkSignature(signature, timestamp, nonce)) {
      return tranReq.returnText(echostr);
    }
    return tranReq.returnText("");
  }
  /** éªŒè¯ç­¾åutil */
  public static boolean checkSignature(String signature, String timestamp, String nonce)
      throws Exception {
    HashMap<String, String> weixinParam = getWeixinParam();
    String[] arr = new String[] {weixinParam.get("token"), timestamp, nonce};
    // å°†token、timestamp、nonce三个参数进行字典序排序
    // 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 = byteToHex(digest);
    } catch (NoSuchAlgorithmException e) {
      _logger.error("签名异常", e);
    }
    content = null;
    // å°†sha1加密后的字符串可与signature对比,标识该请求来源于微信
    return tmpStr != null && tmpStr.equals(signature.toUpperCase());
  }
  public 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;
  }
  public static String byteToHex(byte[] data)
  {
    String hex = "0123456789ABCDEF";
    StringBuilder sb = new StringBuilder();
    for(byte v : data)
    {
      sb.append(hex.charAt((v >> 4) & 0x0F));
      sb.append(hex.charAt(v & 0x0F));
      //sb.append(String.format("%02X", v));
    }
    return sb.toString();
  }
  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()) {
      @SuppressWarnings("resource")
    java.util.Scanner scanner = new java.util.Scanner(in).useDelimiter("\\A");
      return scanner.hasNext() ? scanner.next() : "";
    }
  }
}
JAVA/SMTAIServer/src/main/resources/requestmap/weixin.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
{
  "weixin/wechat_notify": {"map": { "class": "#SMTAIWeixinControl", "method": "weChatNotify"},  "no_shrio": true,
    "swaggers": [
      { "tags": ["微信验证"],
        "title": "微信验证",
        "parameters": [
        ]
      }
    ]
  }
}
JAVA/SMTAIServer/src/main/resources/spring-config-aiserver.xml
@@ -33,4 +33,5 @@
     <bean id="SMTSystemManagerControl" class="com.smtaiserver.smtaiserver.control.SMTSystemManagerControl"/>
     <bean id="SMTWorkflowManagerControl" class="com.smtaiserver.smtaiserver.control.SMTWorkflowManagerControl"/>
     <bean id="SMTAIMapControl" class="com.smtaiserver.smtaiserver.control.SMTAIMapControl"/>
     <bean id="SMTAIWeixinControl" class="com.smtaiserver.smtaiserver.control.SMTAIWeixinControl"/>
</beans>
JAVA/SMTServlet/.idea/codeStyles/codeStyleConfig.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
  <state>
    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
  </state>
</component>
JAVA/SMTServlet/src/main/java/com/smtservlet/core/SMTRequest.java
@@ -735,6 +735,8 @@
     */
    public void setRequestAttribute(String name, Object value) throws Exception
    {
        if(this.getRequest() == null)
            return;
        this.getRequest().setAttribute(name, value);
    }
    
@@ -802,6 +804,10 @@
     */
    public Object getSessionAttribute(String name) throws Exception
    {
        HttpSession session= this.getSession();
        if(session == null)
            return null;
        return this.getSession().getAttribute(name);
    }
@@ -931,6 +937,8 @@
     */
    public HttpServletRequest getRequest()
    {
        if(_webRequest == null)
            return null;
        return _webRequest.getNativeRequest(HttpServletRequest.class);
    }
    
@@ -946,7 +954,10 @@
     */
    public HttpSession getSession() throws Exception
    {
        return getRequest().getSession();
        HttpServletRequest request = getRequest();
        if(request == null)
            return null;
        return request.getSession();
    }
    
    /**