当前位置:   article > 正文

微信公众号之后台开发_微信公众号开发后端

微信公众号开发后端

一、公众号后台配置

开发第一步,微信服务器要验证服务器是否有效。登录微信公众平台,在开发-基本设置页面,服务器配置项填写: 服务器地址(URL) 、令牌(Token) 、消息加解密密钥(EncodingAESKey)

针对URL开发两个接口:
		GET请求接口:用来做服务器有效性验证
		POST请求接口:用来接收微信服务器发送来的消息。
		
Token可以任意填写,用作生成签名

EncodingAESKey手动填写或随机生成,用作消息体加解密密钥。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述
现在提交肯定是验证token失败,因为还需要完成代码逻辑。

在这里插入图片描述

二、使用内网穿透

这里使用NATAPP内网穿透,文档齐全,很简单。

在这里插入图片描述

三、引入依赖

   <!--xml解析-->
        <dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>2.1.3</version>
        </dependency>
        <!--对象转xml-->
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.10</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

四、服务器校验

校验逻辑流程

在这里插入图片描述

校验逻辑实现

@RestController
@RequestMapping("/WeChat")
public class WxController {
    
    //与微信公众号 开发 基本配置中配置token保持一致
    private static final String TOKEN = "token";

    private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /**
     * 服务器校验
     * 安全校验,标识请求是否来源于微信
     *
     * @param request
     * @param response
     * @throws UnsupportedEncodingException
     */
    @GetMapping("/wx")
    public void verifyToken(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        request.setCharacterEncoding("UTF-8");
        //微信加密签名
        String signature = request.getParameter("signature");
        //时间戳
        String timestamp = request.getParameter("timestamp");
        //随机数
        String nonce = request.getParameter("nonce");
        //随机字符串
        String echostr = request.getParameter("echostr");
        PrintWriter out = null;
        try {
            out = response.getWriter();
            if (checkSignature(signature, timestamp, nonce)) {
                out.write(echostr);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            out.close();
        }
    }


    /**
     * 校验微信签名
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    private static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] str = new String[]{TOKEN, timestamp, nonce};
        //对token、timestamp、nonce三个参数进行字典序排序
        Arrays.sort(str);
        //将三个参数字符串拼接成一个字符串进行sha1加密
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < str.length; i++) {
            buffer.append(str[i]);
        }
        String temp = encode(buffer.toString());
        //获得加密后的字符串与signature对比
        return signature.equals(temp);
    }


    /**
     * 对字符串进行加密
     *
     * @param str
     * @return
     */
    private static String encode(String str) {
        if (str == null) {
            return null;
        }
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("SHA1");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        messageDigest.update(str.getBytes());
        byte[] digest = messageDigest.digest();

        int len = digest.length;
        StringBuilder buf = new StringBuilder(len * 2);
        for (int j = 0; j < len; j++) {
            buf.append(HEX_DIGITS[(digest[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[digest[j] & 0x0f]);
        }
        return buf.toString();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

在这里插入图片描述

五、消息接收

消息接收接口和服务器校验接口地址是一样的,只不过消息接收接口是一个 POST 请求。由于公众号后台配置消息加解密方式:明文模式,在后台收到的消息可以直接处理。

接收逻辑流程

1.收到微信服务器发来的消息之后,进行XML解析,提取出需要的信息。

2.根据发送的消息类型或业务做相关操作,再将操作的结果返回给微信服务器。
  • 1
  • 2
  • 3

在这里插入图片描述

接收与回复文本消息格式

1.接受到的文本消息格式

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[fromUser]]></FromUserName>
  <CreateTime>1348831860</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[this is a test]]></Content>
  <MsgId>1234567890123456</MsgId>
</xml>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
参数是否必须描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,文本为text
Content文本消息内容
MsgId消息id,64位整型

2.回复文本消息格式

收到粉丝消息后不想或者不能5秒内回复时,需回复“success”字符串

<xml>
 <ToUserName><![CDATA[粉丝号]]></ToUserName>
 <FromUserName><![CDATA[公众号]]></FromUserName>
 <CreateTime>1460541339</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[test]]></Content>
</xml>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
参数是否必须描述
ToUserName接收方帐号(收到的OpenID)
FromUserName开发者微信号
CreateTime消息创建时间 (整型)
MsgType消息类型,文本为text
Content回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示)

接收与回复逻辑实现

 /**
     * 接受微信发送的消息
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @PostMapping("/wx")
    public void processTheMessage(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, String> parseXml = parseXml(request);
        /**
         * 接受到的文本消息格式
         * <xml>
         *  <ToUserName><![CDATA[公众号]]></ToUserName>
         *  <FromUserName><![CDATA[粉丝号]]></FromUserName>
         *  <CreateTime>1460537339</CreateTime>
         *  <MsgType><![CDATA[text]]></MsgType>
         *  <Content><![CDATA[欢迎开启公众号开发者模式]]></Content>
         *  <MsgId>6272960105994287618</MsgId>
         * </xml>
         */
        //开发者微信号
        String tousername = parseXml.get("ToUserName");
        //发送方帐号(一个OpenID)
        String fromusername = parseXml.get("FromUserName");
        //消息创建时间 (整型)
        String createTime = parseXml.get("CreateTime");
        //消息类型,文本为text
        String msgType = parseXml.get("MsgType");
        //文本消息内容
        String content = parseXml.get("Content");
        //消息id,64位整型
        String msgId = parseXml.get("MsgId");

        System.out.println("开发者微信号: " + tousername);
        System.out.println("发送方帐号: " + fromusername);
        System.out.println("消息创建时间: " + createTime);
        System.out.println("消息类型: " + msgType);
        System.out.println("文本消息内容: " + content);
        System.out.println("消息id: " + msgId);

        /**
         * 被动回复文本消息的格式
         *  <xml>
         *  <ToUserName><![CDATA[粉丝号]]></ToUserName>
         *  <FromUserName><![CDATA[公众号]]></FromUserName>
         *  <CreateTime>1460541339</CreateTime>
         *  <MsgType><![CDATA[text]]></MsgType>
         *  <Content><![CDATA[test]]></Content>
         * </xml>
         *
         * 需注意ToUserName与FromUserName的设值
         */
        Message message = new Message();
        message.setToUserName(fromusername);
        message.setFromUserName(tousername);
        message.setCreateTime(createTime);
        message.setMsgType(msgType);
        message.setContent("Hello  管理员。");

        WxController.xstream.alias("xml", Message.class);
        String xml = WxController.xstream.toXML(message);
        System.out.println(xml);
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        out.println(xml);
        out.flush();
    }

    /**
     * 解析微信发来的请求(XML)
     *
     * @param request
     * @return
     * @throws Exception
     */
    private static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
        // 将解析结果存储在HashMap中
        Map<String, String> map = new HashMap<String, String>();
        // 从request中取得输入流
        InputStream inputStream = request.getInputStream();
        // 读取输入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        //得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子节点
        List<Element> elementList = root.elements();
        // 遍历所有子节点
        for (Element e : elementList) {
            map.put(e.getName(), e.getText());
        }
        // 释放资源
        inputStream.close();
        inputStream = null;
        return map;
    }

    /**
     * 扩展xstream使其支持CDATA
     */
    private static XStream xstream = new XStream(new XppDriver() {
        @Override
        public HierarchicalStreamWriter createWriter(Writer out) {
            return new PrettyPrintWriter(out) {
                // 对所有xml节点的转换都增加CDATA标记
                boolean cdata = true;

                @Override
                public void startNode(String name, Class clazz) {
                    super.startNode(name, clazz);
                }

                @Override
                protected void writeText(QuickWriter writer, String text) {
                    if (cdata) {
                        writer.write("<![CDATA[");
                        writer.write(text);
                        writer.write("]]>");
                    } else {
                        writer.write(text);
                    }
                }
            };
        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127

六、 执行测试

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/274215
推荐阅读
相关标签
  

闽ICP备14008679号