WeChat public account pays attention to or clears customs before processing our own business logic

The business is: according to scanning the QR code of different stores (the above blog post has been introduced), counting the number of followers from each store.

Every QR code scanned in is the official account of Everbright Bank, but the scene value in the QR code of each store is different. It is necessary to count the number of attention paid by scanning each store to judge the drainage situation of each store.

Reference blog post: https://blog.csdn.net/LiuAustin/article/details/104507369

Code:

1. In the following WxPublicController code, there is a get(), post() method, these two methods are the interface automatically called by the WeChat background, the url of this controller needs to be consistent with the url configured in the official account;

2. Since the code for the official account was written by (other company) PHP before, this time we added statistics on the drainage of each merchant (our company completed the java writing), so the url on the official account cannot be modified. What should I do now?

My idea is: when a user follows/unfollows the official account, the WeChat backend will return an xml file to the previously configured url. After receiving the xml, php will call my java interface for logical processing. Since php encapsulates xml into json, I use @RequestBody JSONObject jsonObject here

Come to receive, and then perform logical processing, where EventKey is the scene value with the scene value QR code generated before, and my side is the merchant id.

Note: The user scans the QR code to follow (Event is subscribe), and the WeChat official account backend returns EventKey with a value. If it is unfollowing (Event is unsubscribe), the EventKey returned from the WeChat official account backend has no value and is empty.

/**
 * Copyright (C), 2018-2020, XXX有限公司
 * FileName: WxPublicController
 * Author:   zhanglei
 * Date:     2020/8/11 13:28
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.asyware.game.controller;

/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @author zhanglei
 * @create 2020/8/11
 * @since 1.0.0
 */

import com.asyware.game.entity.Attention;
import com.asyware.game.mapper.AttentionMapper;
import com.asyware.game.service.AttentionService;
import com.asyware.game.utils.SignUtil;
import com.asyware.game.utils.wx.MsgUtil;

import com.asyware.game.utils.wx.TextMsg;
import com.asyware.game.utils.wx.XmlUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONObject;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author liuqh
 * @date 2019-08-13 16:26
 * @description
 */
@RestController
@RequestMapping(value = "/wx")
@Api(tags = "微信")
public class WxPublicController {

    protected static Logger logger = LoggerFactory.getLogger(WxPublicController.class);
    //填写和公众号后台配置的一样的token
    private static final String TOKENN = "自己公众号的token";
    @Autowired
    private AttentionService attentionService;
    @Autowired
    private AttentionMapper attentionMapper;


    /**
     * 微信公众号appId
     */
    @Value("${APPID}")
    private String publicAppId;
    /**
     * 微信公众号appSecret
     */
    @Value("${APPSECRET}")
    private String publicAppSecret;


    @RequestMapping(method = RequestMethod.GET)
    public void get(HttpServletRequest request, HttpServletResponse response) {
        // 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
        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();
            // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,否则接入失败
            if (SignUtil.checkSignature(TOKENN, signature, timestamp, nonce)) {
                out.print(echostr);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null ) {
                out.close();
            }
        }
    }




 //   @RequestMapping(method = RequestMethod.POST)
 @ApiOperation(value = "PHP那边传入json,进行商户关注人数加减一",notes = "")
 @PostMapping("/parseXml")
    public void post(HttpServletRequest request, HttpServletResponse response,
                     @RequestBody JSONObject jsonObject) throws Exception{
        // 响应消息
        PrintWriter out = null;
        String resMessage = "success";
        try {
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
            //把微信返回的xml信息转义成map
    //        Map<String, String> map = XmlUtil.parseXml(request);
            //消息来源用户标识
            String fromUserName = (String)jsonObject.get("FromUserName");
            //消息目的用户标识
            String toUserName = (String)jsonObject.get("ToUserName");
            //消息创建时间(整型)
            String createTime = (String)jsonObject.get("CreateTime");
            //消息类型
            String msgType =(String)jsonObject.get("MsgType");
            //事件类型:subscribe/unsubscribe
            String eventType = (String)jsonObject.get("Event");

            //如果为事件类型
            if(MsgUtil.MSGTYPE_EVENT.equals(msgType)){
                //处理订阅事件
                if(MsgUtil.MESSAGE_SUBSCIBE.equals(eventType)){
                    resMessage = MsgUtil.subscribeForText(toUserName, fromUserName,"欢迎关注,精彩内容不容错过!!!");
                    //TODO 关注的业务逻辑
                    //场景值
                    String eventKey = (String)jsonObject.get("EventKey");
                    List<Attention> list = attentionService.lambdaQuery().eq(Attention::getOpenId, fromUserName).list();
                    if(CollectionUtils.isEmpty(list) && !StringUtils.isEmpty(eventKey)){//没有关注过
                        String[] s = eventKey.split("_");
                        if("1".equals(s[2])){//关注二维码
                            Attention a=new Attention(fromUserName,Integer.valueOf(s[1]));
                            attentionMapper.insert(a);
                        }else{//核销二维码

                        }
                    }
                } else if(MsgUtil.MESSAGE_UNSUBSCIBE.equals(eventType)) { //处理取消订阅消息
                    resMessage = MsgUtil.unsubscribeForText(toUserName, fromUserName);
                    //TODO 取消关注的业务逻辑
                    List<Attention> list = attentionService.lambdaQuery().eq(Attention::getOpenId, fromUserName).list();
                    if(!CollectionUtils.isEmpty(list)){
                        attentionMapper.deleteById(list.get(0).getId());
                    }
                }else if(MsgUtil.MSGTYPE_EVENT.equals(eventType)){//关注之后的扫码消息
                    //场景值
                    String eventKey = (String)jsonObject.get("EventKey");
                    if(!StringUtils.isEmpty(eventKey)){
                        String[] s = eventKey.split("_");
                        if("2".equals(s[2])){//核销二维码

                        }
                    }
                    //todo
                }
                logger.info("eventType:"+eventType+",fromUserName:"+fromUserName+",toUserName:"+toUserName+",msgType:"+msgType+",createTime:"+createTime);
            }
            out = response.getWriter();
            out.println(resMessage);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null ) {
                out.close();
            }
        }
    }
}

2. SignUtil class:

/**
 * Copyright (C), 2018-2020, XXX有限公司
 * FileName: SignUtil
 * Author:   zhanglei
 * Date:     2020/8/11 12:01
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.asyware.game.utils;

/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @author zhanglei
 * @create 2020/8/11
 * @since 1.0.0
 */

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

/**
 * @author liuqh
 * @date 2019-08-13 16:20
 * @description
 */
public class SignUtil {

    /**
     * 验证签名
     * @param token
     * @param signature 签名用来核实最后的结果是否一致
     * @param timestamp 时间标记
     * @param nonce 随机数字标记
     * @return 一个布尔值确定最后加密得到的是否与signature一致
     */
    public static boolean checkSignature(String token, String signature, String timestamp, String nonce) {
        //将传入参数变成一个String数组然后进行字典排序
        String[] arr = new String[] { token, timestamp, nonce };
        // 将token、timestamp、nonce三个参数进行字典排序
        Arrays.sort(arr);
        //创建一个对象储存排序后三个String的结合体
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        // 将sha1加密后的字符串可与signature对比
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

    /**
     * 将字节数组转换为十六进制字符串
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * 将每一个字节转换为十六进制字符串
     * @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;
    }
}

3. MsgUtil class:

/**
 * Copyright (C), 2018-2020, XXX有限公司
 * FileName: MsgUtil
 * Author:   zhanglei
 * Date:     2020/8/11 13:25
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.asyware.game.utils.wx;

/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @author zhanglei
 * @create 2020/8/11
 * @since 1.0.0
 */


import java.util.Date;

/**
 * @author liuqh
 * @date 2020-02-20 10:10
 * @description
 */
public class MsgUtil {

    public static final String MSGTYPE_EVENT = "event";//消息类型--事件
    public static final String MESSAGE_SUBSCIBE = "subscribe";//消息事件类型--订阅事件
    public static final String MESSAGE_UNSUBSCIBE = "unsubscribe";//消息事件类型--取消订阅事件
    public static final String MESSAGE_SCAN = "scan";//消息事件类型--已关注时的扫码事件
    public static final String MESSAGE_TEXT = "text";//消息类型--文本消息

    /**
     * 组装文本消息
     */
    public static String textMsg(String toUserName,String fromUserName,String content){
        TextMsg text = new TextMsg();
        text.setFromUserName(toUserName);
        text.setToUserName(fromUserName);
        text.setMsgType(MESSAGE_TEXT);
        text.setCreateTime(new Date().getTime());
        text.setContent(content);
        return XmlUtil.textMsgToxml(text);
    }

    /**
     * 响应订阅事件--回复文本消息
     */
    public static String subscribeForText(String toUserName,String fromUserName,String content){
        return textMsg(toUserName, fromUserName, content);
    }

    /**
     * 响应取消订阅事件
     */
    public static String unsubscribeForText(String toUserName,String fromUserName){
        System.out.println("用户:"+ fromUserName +"取消关注~");
        return "";
    }
}

 

Guess you like

Origin blog.csdn.net/zhangleiyes123/article/details/107963047