大家好,我是小悟

在做微信小程序或公众号开发的有时候,难免会遇到需要在用户关注或取关公众号后处理业务逻辑的需求,只需要几步就可以搞定。

1、配置

首先我们需要在微信公众号后台进行服务器配置,登录公众号后台->开发->基本配置->服务器配置,如下:

实现公众号关注或取关后再处理我们自己的业务逻辑_微信公众号

服务器地址就是我们写的一个controller(代码在下面),用来给微信校验,和接收微信发过来的消息,如果地址错误或者token错误,提交信息的时候会报错

实现公众号关注或取关后再处理我们自己的业务逻辑_微信公众号_02

2、代码实现

SignUtil

/**
 * @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;
        }
}
  • 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.

MsgUtil

/**
 * @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_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,String content){
        System.out.println("用户:"+ fromUserName +"取消关注~");
        return "";
    }
}
  • 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.

application.yml

parameter:
  #微信公众号
  publicAppId: 微信公众号AppId
  publicAppSecret: 微信公众号AppSecret
  • 1.
  • 2.
  • 3.
  • 4.

WxPublicController

/**
 * @description
 */
@Controller
@RequestMapping(value = "/message/weixin")
public class WxPublicController {

    protected static Logger logger = LoggerFactory.getLogger(WxPublicController.class);
   //填写和公众号后台配置的一样的token
    private static final String TOKEN = "";

    /**
     * 微信公众号appId
     */
    @Value("${parameter.publicAppId}")
    private String publicAppId;
    /**
     * 微信公众号appSecret
     */
    @Value("${parameter.publicAppSecret}")
    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(TOKEN, signature, timestamp, nonce)) {
                out.print(echostr);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null ) {
                out.close();
            }
        }
    }

    @RequestMapping(method = RequestMethod.POST)
    public void post(HttpServletRequest request, HttpServletResponse response) {
        // 响应消息
        PrintWriter out = null;
        String resMessage = "";
        try {
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
            //把微信返回的xml信息转义成map
            Map<String, String> map = XmlUtil.parseXml(request);
            //消息来源用户标识
            String fromUserName = map.get("FromUserName");
            //消息目的用户标识
            String toUserName = map.get("ToUserName");
            //消息创建时间(整型)
            String createTime = map.get("CreateTime");
            //消息类型
            String msgType = map.get("MsgType");
            //事件类型:subscribe/unsubscribe
            String eventType = map.get("Event");
            //如果为事件类型
            if(MsgUtil.MSGTYPE_EVENT.equals(msgType)){
                //处理订阅事件
                if(MsgUtil.MESSAGE_SUBSCIBE.equals(eventType)){
                    resMessage = MsgUtil.subscribeForText(toUserName, fromUserName, "您好,谢谢您的关注!!!");
                    //TODO 业务逻辑
                    //处理取消订阅消息
                } else if(MsgUtil.MESSAGE_UNSUBSCIBE.equals(eventType)) {
                    //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();
            }
        }
    }
}
  • 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.


您的一键三连,是我更新的最大动力,谢谢

山水有相逢,来日皆可期,谢谢阅读,我们再会

我手中的金箍棒,上能通天,下能探海