一、新建我的项目工程

  1. 新建一个spring我的项目

  1. 填写 Group 和 Artifact 信息

  1. 这步能够间接跳过,前面再按需导入

  1. 抉择工程地址

二、配置

pom.xml

<dependencies>    <!-- spring相干包 -->    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter</artifactId>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-test</artifactId>        <scope>test</scope>    </dependency>    <!-- http申请 -->    <dependency>        <groupId>org.apache.httpcomponents</groupId>        <artifactId>httpclient</artifactId>        <version>4.5.6</version>    </dependency>    <!-- 工具包 -->    <dependency>        <groupId>cn.hutool</groupId>        <artifactId>hutool-all</artifactId>        <version>5.5.8</version>    </dependency>    <!-- xml解析工具包 -->    <dependency>        <groupId>dom4j</groupId>        <artifactId>dom4j</artifactId>        <version>1.6.1</version>    </dependency></dependencies>

application.yml

spring:  application:    name: wechatserver:  port: 8900appid: # 微信开发者appidsecret: # 微信开发者appsecrettoken: # 服务器校验token

三、相干类

AccessToken / AccessTokenInfo

/** * AccessToken 实体类 * @author unidentifiable * @date 2021-02-28 */public class AccessToken {    /**     * 获取到的凭证     */    private String tokenName;    /**     * 凭证无效工夫  单位:秒     */    private int expireSecond;    /**     * get/set ...     */}/** * AccessToken 实体类 * @author unidentifiable * @date 2021-02-28 */public class AccessTokenInfo {    /**     * accessToken:像微信端发动申请需携带该accessToken     */    public static AccessToken accessToken = null;}

MessageUtil

/** * 信息工具类 * @author unidentifiable * @date 2021-02-28 */public class MessageUtil {    /**     * 解析微信发来的申请(XML)     *     * @param request 申请     * @return map     * @throws Exception 异样     */    public static Map<String, String> parseXml(HttpServletRequest request) {        // 将解析后果存储在HashMap中        Map<String, String> map = new HashMap<>(16);        // 从request中获得输出流        try (InputStream inputStream = request.getInputStream()) {            System.out.println("获取输出流");            // 读取输出流            SAXReader reader = new SAXReader();            Document document = reader.read(inputStream);            // 失去xml根元素            Element root = document.getRootElement();            // 失去根元素的所有子节点            List<Element> elementList = root.elements();            // 遍历所有子节点            for (Element e : elementList) {                System.out.println(e.getName() + " | " + e.getText());                map.put(e.getName(), e.getText());            }        } catch (Exception e) {            e.printStackTrace();        }        return map;    }    /**     * 获取用户详情     * @param openId 微信公众号用户ID     * @return 用户详情     */    public static String getUserInfo(String openId) {        // 拼接 url,发动 http.get 申请        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + AccessTokenInfo.accessToken.getTokenName() + "&openid=" + openId + "&lang=zh_CN";        return HttpUtil.get(url);    }}

AccessTokenConfig

/** * AccessToken 配置类 * * @author unidentifiable * @date 2021-02-28 */public class AccessTokenConfig {    static {        Properties prop = new Properties();        String appid = null;        String secret = null;        try {            // 读取 application.yml 获取微信开发者 appid 和 appsecret            InputStream in = MessageUtil.class.getClassLoader().getResourceAsStream("application.yml");            prop.load(in);            appid = prop.getProperty("appid");            secret = prop.getProperty("secret");        } catch (Exception e) {            e.printStackTrace();        }        // 接口地址为https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET,其中grant_type固定写为client_credential即可。        String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appid, secret);        // 此申请为https的get申请,返回的数据格式为{"access_token":"ACCESS_TOKEN","expires_in":7200}        String result = HttpUtil.get(url);        System.out.println("获取到的access_token=" + result);        //应用FastJson将Json字符串解析成Json对象        JSONObject json = new JSONObject(result);        AccessToken token = new AccessToken();        token.setTokenName(json.get("access_token", String.class));        token.setExpireSecond(json.get("expires_in", Integer.class));        // 开启一个线程,循环更新 AccessToken,该值有效期 2小时,需手动刷新        new Thread(() -> {            while (true) {                try {                    // 获取accessToken                    AccessTokenInfo.accessToken = token;                    // 获取胜利                    if (AccessTokenInfo.accessToken != null) {                        // 获取到access_token 休眠7000秒,大概2个小时左右                        Thread.sleep(7000 * 1000);                    } else {                        // 获取的access_token为空 休眠3秒                        Thread.sleep(3000);                    }                } catch (Exception e) {                    System.out.println("产生异样:" + e.getMessage());                    e.printStackTrace();                    try {                        // 产生异样休眠1秒                        Thread.sleep(1000);                    } catch (Exception e1) {                        e.printStackTrace();                    }                }            }        }).start();    }}

SubscribeService

package com.unidentifiable.wechat.service;import com.unidentifiable.wechat.util.MessageUtil;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletRequest;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Arrays;import java.util.Map;/** * Service * @author unidentifiable * @date 2021-02-28 */@Service("subscribeService")public class SubscribeService {    @Value("${subscriptionKey}")    public String subscriptionKey;    @Value("${uriBase}")    public String uriBase;    @Value("${token}")    public String token;    /**     * 公众号服务器校验     *     * @param req 申请     * @return 校验后果     */    public String verification(HttpServletRequest req) {        // 接管微信服务器发送申请时传递过去的参数        String signature = req.getParameter("signature");        String timestamp = req.getParameter("timestamp");        String nonce = req.getParameter("nonce");        String echostr = req.getParameter("echostr");        // 将token、timestamp、nonce三个参数进行字典序排序,并拼接为一个字符串        String sortStr = sort(token, timestamp, nonce);        // 字符串进行shal加密        String mySignature = shal(sortStr);        // 校验微信服务器传递过去的签名 和  加密后的字符串是否统一, 若统一则签名通过        if (!"".equals(signature) && !"".equals(mySignature) && signature.equals(mySignature)) {            System.out.println("-----签名校验通过-----");            return echostr;        } else {            System.out.println("-----校验签名失败-----");            return "";        }    }    /**     * 参数排序     *     * @param token     自定义token     * @param timestamp timestamp     * @param nonce     nonce     * @return 排序后拼接字符串     */    public String sort(String token, String timestamp, String nonce) {        String[] strArray = {token, timestamp, nonce};        Arrays.sort(strArray);        StringBuilder sb = new StringBuilder();        for (String str : strArray) {            sb.append(str);        }        return sb.toString();    }    /**     * 字符串进行shal加密     *     * @param str 字符串     * @return 密文     */    public String shal(String str) {        try {            MessageDigest digest = MessageDigest.getInstance("SHA-1");            digest.update(str.getBytes());            byte messageDigest[] = digest.digest();            StringBuilder hexString = new StringBuilder();            // 字节数组转换为 十六进制 数            for (int i = 0; i < messageDigest.length; i++) {                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);                if (shaHex.length() < 2) {                    hexString.append(0);                }                hexString.append(shaHex);            }            return hexString.toString();        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        }        return "";    }    /**     * 关注申请     *     * @param req 申请     * @return 关注事件后果     */    public String subscribeEvent(HttpServletRequest req) {        String result = null;        Map<String, String> map = null;        try {            /*                解析申请,失去相干信息                FromUserName| openid 用户ID                CreateTime|1614499703 工夫                MsgType|event 音讯类型                Event|subscribe 事件类型                EventKey|             */            map = MessageUtil.parseXml(req);        } catch (Exception e) {            e.printStackTrace();        }        // 新开一个线程避免以后当初延时导致微信反复发动申请        final Map<String, String> m = map;        final String[] str = new String[1];        new Thread(() -> {            // 获取判断是否为关注事件            if (null != m && "event".equals(m.get("MsgType")) && "subscribe".equals(m.get("Event"))) {                str[0] = MessageUtil.getUserInfo(m.get("FromUserName"));                System.out.println(str[0]);                                // 这里能够增加邮件告诉等性能,也能够判断别的事件,做出对应操作            }        }).start();        return result;    }}

SubscribeController

package com.unidentifiable.wechat.controller;import com.unidentifiable.wechat.service.SubscribeService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import javax.servlet.http.HttpServletRequest;/** * Controller * @author unidentifiable * @date 2021-02-28 */public class SubscribeController {    @Autowired    private SubscribeService subscribeService;    /**     * 服务器校验     * @param req 申请     * @return 校验后果     */    @GetMapping("/")    public String verification(HttpServletRequest req) {        return subscribeService.verification(req);    }    /**     * 音讯事件     * @param req 申请     * @return 后果     */    @PostMapping("/")    public boolean subscribeEvent(HttpServletRequest req) {        String s = subscribeService.subscribeEvent(req);        return null != s;    }}

四、内网穿透(有域名的这一步能够省略)

这里应用的是 natapp 这一款工具,下载好对应版本工具

https://natapp.cn/

新建一个收费的隧道,配置好须要映射的地址跟端口,而后复制 authtoken

批改客户端配置文件中的 authtoken(我这里是win版本,linux版本没有该文件,倡议新增一份,不而后台启动可能会连贯超时)

config.ini

#将本文件搁置于natapp同级目录 程序将读取 [default] 段#在命令行参数模式如 natapp -authtoken=xxx 等雷同参数将会笼罩掉此配置#命令行参数 -config= 能够指定任意config.ini文件[default]authtoken=                      #对应一条隧道的authtokenclienttoken=                    #对应客户端的clienttoken,将会疏忽authtoken,若无请留空,log=none                        #log 日志文件,可指定本地文件, none=不做记录,stdout=间接屏幕输入 ,默认为noneloglevel=DEBUG                  #日志等级 DEBUG, INFO, WARNING, ERROR 默认为 DEBUGhttp_proxy=                     #代理设置 如 http://10.123.10.10:3128 非代理上网用户请务必留空

配置实现间接双击运行即可,linux版后盾启动可用 (./natapp &) 命令运行,留神是有括号的。呈现如下界面即为胜利。

五、微信公众平台接口测试账号

https://mp.weixin.qq.com/debu...

拿到 appID 跟 appsecret 填入 appliation.yml 配置文件中,启动我的项目,启动 natapp ,填入域名以及自定义的token 进行接口配置校验。

绑定实现服务器信息之后,就能够扫描上面的二维码进行测试了。

教程到这里就完结了,大家有想实现什么自定义性能的话能够查看微信官网文档,看外面有提供什么性能,而后本人再批改下对应的判断即可。

我的项目地址: https://gitee.com/unidentifia...