微信公众号服务器自定义回复

        

1.效果图

微信公众号服务器自定义回复_第1张图片


2.maven

        
        
            com.github.binarywang
            weixin-java-mp
            4.1.0
        

3.代码

        与微信公众号保持心跳的接口,以及自定义回复公众号信息

package com.kenick.mp.controller;

import com.kenick.mp.config.WxMpUtil;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.builder.outxml.TextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * @description 微信公众号
 * @date 2023/12/27
 */
@Controller
@RequestMapping("/mp")
public class WxMpController {

    private final static Logger logger = LoggerFactory.getLogger(WxMpController.class);

    @Resource
    private WxMpUtil wxMpUtil;

    /**
     * 与微信服务器保持心跳,同时进行内容校验
     * 必须为get方式
     *
     * @param signature 心跳内容签名,微信服务器配置的token+timestamp+nonce进行sha1加密后的密文
     * @param timestamp 时间戳字符串
     * @param nonce     随机数
     * @param echostr   随机内容,回复时要保持一致
     * @return 校验通过回复对方发送过来的内容, 否则回复空字符串
     */
    @ResponseBody
    @RequestMapping("/heartbeat")
    public String heartbeat(@RequestParam("signature") String signature,
                            @RequestParam("timestamp") String timestamp,
                            @RequestParam("nonce") String nonce,
                            @RequestParam("echostr") String echostr) {
        logger.debug("WxMpController.heartbeat,{},{},{},{}", signature, timestamp, nonce, echostr);
        try {
            if (wxMpUtil.checkSignature("微信配置的token,不是accessToken", timestamp, nonce, signature)) {
                return echostr;
            }
        } catch (Exception e) {
            logger.error("公众号心跳异常", e);
        }
        return "";
    }

    /**
     * 接收微信公众号发送过来的消息,与心跳接口路径一样
     * 必须为post方式
     *
     * @return 无自定义回复返回success, 表示服务器已收到;自定义回复xml格式数据
     */
    @ResponseBody
    @PostMapping(value = "/heartbeat")
    public String receive(HttpServletRequest request) {
        try {
            WxMpXmlMessage wxMpXmlMessage = WxMpXmlMessage.fromXml(request.getInputStream());
            logger.debug("WxMpController.receive,{}", wxMpXmlMessage);
            if (wxMpXmlMessage != null && "text".equals(wxMpXmlMessage.getMsgType())) {
                String toUserName = wxMpXmlMessage.getFromUser();
                String fromUserName = wxMpXmlMessage.getToUser();
                String content = wxMpXmlMessage.getContent();
                logger.debug("toUserName:{},fromUserName:{},content:{}", toUserName, fromUserName, content);

                String replyXml = new TextBuilder().fromUser(fromUserName)
                        .toUser(toUserName)
                        .content("replay:" + content + ",\n链接:https://www.baidu.com")
                        .build().toXml();
                logger.debug("回应的xml:{}", replyXml);
                return replyXml;
            }
        } catch (Exception e) {
            logger.error("接收消息异常", e);
        }
        return "success";
    }

    /**
     * 获取微信公众号的accessToken
     *
     * @param passwd 简单的自定义密码验证
     */
    @ResponseBody
    @RequestMapping("/getAccessToken")
    public String getAccessToken(@RequestParam(value = "passwd", required = false) String passwd) {
        logger.debug("WxMpController.getAccessToken");
        try {
            if ("kenick".equals(passwd)) {//简单的密码验证
                return wxMpUtil.getAccessToken();
            }
        } catch (Exception e) {
            logger.error("getAccessToken异常", e);
        }
        return "";
    }

}

         微信公众号工具类,注意校验心跳消息时使用的token是在微信平台上配置的token,而不是accessToken。

package com.kenick.mp.config;

import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @description 微信公众号工具类
 * @date 2023/12/27
 */
@Component
public class WxMpUtil {

    private final static Logger logger = LoggerFactory.getLogger(WxMpUtil.class);

    //微信公众号id
    @Value("${wechat.mpAppId}")
    private String mpAppId;

    //微信公众号密码
    @Value("${wechat.mpAppSecret}")
    private String mpAppSecret;

    //微信公众号工具服务
    private static WxMpService wxMpService;

    //获取mp服务
    public WxMpService getMpService() {
        if (wxMpService != null) {
            return wxMpService;
        }
        WxMpDefaultConfigImpl wxMpConfigStorage = new WxMpDefaultConfigImpl();
        wxMpConfigStorage.setAppId(mpAppId);
        wxMpConfigStorage.setSecret(mpAppSecret);
        WxMpService wxMpService = new WxMpServiceImpl();
        wxMpService.setWxMpConfigStorage(wxMpConfigStorage);
        return wxMpService;
    }

    //通过WxMpService工具获取accessToken
    public String getAccessToken() {
        try {
            return getMpService().getAccessToken();
        } catch (Exception e) {
            logger.error("获取accessToken异常", e);
        }
        return "";
    }

    //校验心跳消息签名
    public boolean checkSignature(String token, String timestamp, String nonce, String signature) {
        try {
            return signature.equals(gen(token, timestamp, nonce));
        } catch (Exception e) {
            logger.error("校验签名异常", e);
        }
        return false;
    }

    //sha1加密
    public String gen(String... arr) {
        if (StringUtils.isAnyEmpty(arr)) {
            throw new IllegalArgumentException("非法请求参数,有部分参数为空 : " + Arrays.toString(arr));
        } else {
            Arrays.sort(arr);
            StringBuilder sb = new StringBuilder();
            String[] var2 = arr;
            int var3 = arr.length;

            for (int var4 = 0; var4 < var3; ++var4) {
                String a = var2[var4];
                sb.append(a);
            }

            return DigestUtils.sha1Hex(sb.toString());
        }
    }

}

微信公众号服务器自定义回复_第2张图片

         微信公众号的appid配置,放在spring配置文件中。

wechat.mpAppId=xxxx
wechat.mpAppSecret=xxxx

        注意事项:

        1.调用获取accessToken时,注意程序运行的ip地址要放进白名单

        2.个人订阅号和未经过微信认证的不能使用官方的自定义菜单,也不能通过接口配置菜单

        3.提交服务器配置时,会验证心跳接口是否可用,不可用无法提交

        4.被动接收公众号发送过来的消息接口,使用的就是心跳接口路径,只是请求方式为post,接收的数据为xml格式,奇奇怪怪

        5.注意配置好服务器后,需要启用配置,自定义回复才会生效

        

你可能感兴趣的:(java,微信,java,微信公众平台)