微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息

这篇具有很好参考价值的文章主要介绍了微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章导航

微信小程序生态1-初识小程序
微信小程序生态2-创建一个微信小程序
微信小程序生态3-微信小程序登录流程设计
微信小程序生态4-扫普通二维码进入小程序、打开短链接进入小程序
微信小程序生态5-微信公众号扫码登录PC端网页
微信小程序生态6-微信公众号授权登录(适用于H5小程序)
微信小程序生态7-微信公众号设置IP白名单
微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息
微信小程序生态9-微信开放平台unionId机制介绍
微信小程序生态10-微信公众号token验证失败
微信小程序生态11-一个二维码同时支持微信、钉钉、支付宝扫码打开小程序
微信小程序生态12-微信小程序开发设置中服务器域名和业务域名
微信小程序生态13-微信公众号自定义菜单、个性化菜单配置
微信小程序生态14-下线已发布的小程序
微信小程序生态15- 批量提交微信小程序审核的一种方式

正文

在微信里有这样一个公众号【华为运动健康】,当点击最新排行的时候,公众号就会发送今天最新的运动步数给你。如下图:

微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息

这里有两种格式的消息

1、有头像框,有聊天框——普通消息

2、消息有样式、颜色等——模板消息

微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息

本篇文章主要介绍的就是如何让微信公众号自动回复消息

参考文档链接:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html

开发之前,给大家介绍一个weixin-java-tools

简单介绍一下:

1、微信各种平台的api它都集成了,直接调用就行,不用自己维护微信官方url、各种常量、accessToken等;

2、微信那艹蛋的xml返回数据格式可以直接使用对象进行构建,它已经做好了封装;

3、WxMpMessageRouter非常好用,将微信的各种事件进行分发处理,示例如下:

maven引入:

<!-- weixin-java-mp SDK框架-->
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-mp</artifactId>
    <version>3.6.0</version>
</dependency>

github地址如下:https://github.com/binarywang/weixin-java-mp-demo

wiki文档如下:https://github.com/Wechat-Group/WxJava/wiki

SpringBoot-WeChat示例参考项目:https://github.com/Thinkingcao/SpringBootLearning/tree/master/springboot-wechat

一、登录微信公众平台,启用服务器配置

1、登录https://mp.weixin.qq.com,选择公众号进入,在设置与开发—基本配置

2、记下开发者AppId和开发者秘钥,IP白名单待会再说

3、点击修改配置,配置服务器地址,输入令牌生成加解密秘钥,选择安全模式点击保存

4、上面配置的服务器地址,就是微信回调我们服务器的回调地址,由于微信的数据格式是xml,所以我们需要在接口上进行一些处理

签名校验代码如下:

@RequestMapping(value = "handleWxEvent", method = RequestMethod.POST, produces = "application/xml; charset=UTF-8")
@ResponseBody
public String handleWxEvent(@RequestBody String requestBody,
                                @RequestParam("signature") String signature,
                                @RequestParam("timestamp") String timestamp,
                                @RequestParam("nonce") String nonce,
                                @RequestParam("openid") String openid,
                                @RequestParam(name = "encrypt_type", required = false) String encType,
                                @RequestParam(name = "msg_signature", required = false) String msgSignature){
  //微信加密签名
        String signature = request.getParameter("signature");
        //时间戳
        String timestamp = request.getParameter("timestamp");
        //随机数
        String nonce = request.getParameter("nonce");
        //随机字符串
        String echostr = request.getParameter("echostr");
        //接入验证
        if (checkSignature(signature, timestamp, nonce, gzhToken)) {
            log.info("微信公众号校验完成echostr:[{}]", echostr);
            try {
         //这样写可以防止服务器给返回的字符串加上双引号,导致验证失败
                response.getWriter().print(echostr);
            } catch (IOException e) {
                log.error("输出返回值异常", e);
            }
            return;
        }
        throw new DscException(ErrorCodeEnum.SYSTEM_EXCEPTION, "解析签名发生异常");
}

/**
   * 校验签名
   *
   * @param signature 签名
   * @param timestamp 时间戳
   * @param nonce     随机数
   * @return 布尔值
   */
public static boolean checkSignature(String signature, String timestamp, String nonce, String token) {
      String checkText = null;
      if (null != signature) {
          //对ToKen,timestamp,nonce 按字典排序
          String[] paramArr = new String[]{token, timestamp, nonce};
          Arrays.sort(paramArr);
          //将排序后的结果拼成一个字符串
          String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2])
            try {
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                //对接后的字符串进行sha1加密
                byte[] digest = md.digest(content.toString().getBytes());
                checkText = byteToStr(digest);
            } catch (Exception e) {
                log.error("解码发生异常", e);
            }
        }
        //将加密后的字符串与signature进行对比
        return checkText != null ? checkText.equals(signature.toUpperCase()) : false;
    }

二、配置公众号信息,实例化WxMpService、WxMpMessageRouter

WxMpService功能很多如验证消息的确来自微信服务器、获取access_token、进行相应的公众号切换…

WxMpMessageRouter:微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理

说明:

  1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理

  2. 默认情况下消息只会被处理一次,除非使用 WxMpMessageRouterRule.next()

  3. 规则的结束必须用WxMpMessageRouterRule.end()或者WxMpMessageRouterRule.next(),否则不会生效

1、在application.properties或者application.yml配置好公众号的相关信息

微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息

2、wxmp包如下

微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息

WxMpConfig.class

import com.google.common.collect.Maps;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

import static me.chanjar.weixin.common.api.WxConsts.EventType.SUBSCRIBE;
import static me.chanjar.weixin.common.api.WxConsts.EventType.UNSUBSCRIBE;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.*;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;


@Configuration
public class WxMpConfig {

    /**
     * 设置微信公众号的appid
     */
    @Value("${gzh.appId}")
    private String appId;

    /**
     * 设置微信公众号的app secret
     */
    @Value("${gzh.appSecret}")
    private String secret;

    /**
     * 设置微信公众号的token
     */
    @Value("${gzh.token}")
    private String token;

    /**
     * 设置微信公众号的EncodingAESKey
     */
    @Value("${gzh.aesKey}")
    private String aesKey;
    /**
     * 日志处理
     */
    @Autowired
    private LogHandler logHandler;
    @Autowired
    private NullHandler nullHandler;
    @Autowired
    private KfSessionHandler kfSessionHandler;
    @Autowired
    private StoreCheckNotifyHandler storeCheckNotifyHandler;
    @Autowired
    private LocationHandler locationHandler;
    @Autowired
    private MenuHandler menuHandler;
    @Autowired
    private MsgHandler msgHandler;
    @Autowired
    private UnsubscribeHandler unsubscribeHandler;
    @Autowired
    private SubscribeHandler subscribeHandler;
    @Autowired
    private ScanHandler scanHandler;
    @Autowired
    private TextMsgHandler textMsgHandler;
    @Autowired
    private ImgHandler imgHandler;

    @Bean("wxMpService")
    public WxMpService wxMpService() {
        WxMpDefaultConfigImpl wxMpDefaultConfig = new WxMpDefaultConfigImpl();
        wxMpDefaultConfig.setAppId(appId);
        wxMpDefaultConfig.setSecret(secret);
        wxMpDefaultConfig.setToken(token);
        wxMpDefaultConfig.setAesKey(aesKey);
        Map<String, WxMpConfigStorage> configMap = Maps.newHashMap();
        configMap.put(appId,wxMpDefaultConfig);
        WxMpService service = new WxMpServiceImpl();
        service.setMultiConfigStorages(configMap);
        return service;
    }
    @Bean
    public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);

        // 记录所有事件的日志 (异步执行)
        newRouter.rule().handler(this.logHandler).next();

        // 接收客服会话管理事件
        newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION)
                .handler(this.kfSessionHandler).end();
        newRouter.rule().async(false).msgType(EVENT).event(KF_CLOSE_SESSION)
                .handler(this.kfSessionHandler).end();
        newRouter.rule().async(false).msgType(EVENT).event(KF_SWITCH_SESSION)
                .handler(this.kfSessionHandler).end();

        // 门店审核事件
        newRouter.rule().async(false).msgType(EVENT).event(POI_CHECK_NOTIFY).handler(this.storeCheckNotifyHandler).end();

        // 自定义菜单事件
        newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.CLICK).handler(this.menuHandler).end();

        // 点击菜单连接事件
        newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.VIEW).handler(this.nullHandler).end();

        // 关注事件
        newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end();

        // 取消关注事件
        newRouter.rule().async(false).msgType(EVENT).event(UNSUBSCRIBE).handler(this.unsubscribeHandler).end();

        // 上报地理位置事件
        newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.LOCATION).handler(this.locationHandler).end();

        // 接收地理位置消息
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION).handler(this.locationHandler).end();

        // 扫码事件
        newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.SCAN).handler(this.scanHandler).end();

        // 文本消息处理
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.TEXT).handler(this.textMsgHandler).end();

        // 图片消息处理
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.IMAGE).handler(this.imgHandler).end();

        // 默认
        newRouter.rule().async(false).handler(this.msgHandler).end();

        return newRouter;
    }

}

3、各个handler如下

微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息

AbstractHandler.java

package com.example.wxmsg.wxmp.handler;

import me.chanjar.weixin.mp.api.WxMpMessageHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @dessc 父类
 */
public abstract class AbstractHandler implements WxMpMessageHandler {
    protected Logger logger = LoggerFactory.getLogger(getClass());

}

ImgHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.stereotype.Component;

/**
 * @desc 图片处理器
 */
@Component
public class ImgHandler extends AbstractHandler {
    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> map, WxMpService wxMpService,
        WxSessionManager wxSessionManager) throws WxErrorException {
        // msgType 消息类型
        String msgType = wxMessage.getMsgType();
        // content 消息内容
        String content = wxMessage.getContent();
        if (msgType.equals(WxConsts.XmlMsgType.IMAGE)) {
            //TODO: 如果需要做微信消息日志存储,可以在这里进行日志存储到数据库,这里省略不写。
        }
        // 获取微信用户基本信息
        WxMpUser userWxInfo = wxMpService.getUserService().userInfo(wxMessage.getFromUser(), "zh_CN");
        if (null != userWxInfo) {
            return WxMpXmlOutMessage
                .IMAGE()
                .mediaId("1C72rnlYrj7ZqBiRGdKCoS54AXQwSo4iULd9qRhOC-U")
                .fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser())
                .build();
        }
        return null;
    }
}

KfSessionHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

/**
 * @desc 客户对话处理
 */
@Component
public class KfSessionHandler extends AbstractHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) {
        //TODO 对会话做处理
        return null;
    }

}

LocationHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import com.example.wxmsg.wxmp.builder.TextBuilder;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;

/**
 * @desc 地理位置处理
 */
@Component
public class LocationHandler extends AbstractHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) {
        if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
            //TODO 接收处理用户发送的地理位置消息
            try {
                String content = "感谢反馈,您的的地理位置已收到!";
                return new TextBuilder().build(content, wxMessage, null);
            } catch (Exception e) {
                this.logger.error("位置消息接收处理失败", e);
                return null;
            }
        }

        //上报地理位置事件
        this.logger.info("上报地理位置,纬度 : {},经度 : {},精度 : {}",
                wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision()));

        //TODO  可以将用户地理位置信息保存到本地数据库,以便以后使用

        return null;
    }

}

LogHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import com.example.wxmsg.wxmp.utils.JsonUtils;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

/**
 * @author 日志处理
 */
@Component
public class LogHandler extends AbstractHandler {
    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) {
        this.logger.info("\n接收到请求消息,内容:{}", JsonUtils.toJson(wxMessage));
        return null;
    }

}

MenuHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

import static me.chanjar.weixin.common.api.WxConsts.EventType;

/**
 * @desc 公众号菜单处理
 */
@Component
public class MenuHandler extends AbstractHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService weixinService,
                                    WxSessionManager sessionManager) {
        String msg = String.format("type:%s, event:%s, key:%s",
            wxMessage.getMsgType(), wxMessage.getEvent(),
            wxMessage.getEventKey());
        if (EventType.VIEW.equals(wxMessage.getEvent())) {
            return null;
        }

        return WxMpXmlOutMessage
                .TEXT()
                .content(msg)
                .fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser())
                .build();
    }

}

MsgHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import com.example.wxmsg.wxmp.builder.TextBuilder;
import com.example.wxmsg.wxmp.utils.JsonUtils;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;

/**
 * @desc 消息对话处理
 */
@Component
public class MsgHandler extends AbstractHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService weixinService,
                                    WxSessionManager sessionManager) {

        if (!wxMessage.getMsgType().equals(XmlMsgType.EVENT)) {
            //TODO 可以选择将消息保存到本地
        }

        //当用户输入关键词如“你好”,“客服”等,并且有客服在线时,把消息转发给在线客服
        try {
            if (StringUtils.startsWithAny(wxMessage.getContent(), "你好", "客服")
                && weixinService.getKefuService().kfOnlineList()
                .getKfOnlineList().size() > 0) {
                return WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE()
                    .fromUser(wxMessage.getToUser())
                    .toUser(wxMessage.getFromUser()).build();
            }
        } catch (WxErrorException e) {
            e.printStackTrace();
        }

        //TODO 组装回复消息
        String content = "收到信息内容:" + JsonUtils.toJson(wxMessage);

        return new TextBuilder().build(content, wxMessage, weixinService);

    }

}

NullHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

/**
 * @desc null回复处理
 */
@Component
public class NullHandler extends AbstractHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) {
        return null;
    }

}

ScanHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import com.example.wxmsg.wxmp.builder.TextBuilder;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

/**
 * @desc 扫码处理
 */
@Component
public class ScanHandler extends AbstractHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> map,
        WxMpService wxMpService,
        WxSessionManager wxSessionManager) throws WxErrorException {
        // 扫码事件处理
        this.logger.info("扫码用户 OPENID: " + wxMessage.getFromUser());
        //todo 处理扫码相关的操作
        try {
            //从diamond中获取标准话术
            return new TextBuilder().build("感谢订阅", wxMessage, wxMpService);
        } catch (Exception e) {
            this.logger.error(e.getMessage(), e);
        }

        return null;
    }
}

StoreCheckNotifyHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

/**
 * @desc 门店审核事件处理
 */
@Component
public class StoreCheckNotifyHandler extends AbstractHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
        Map<String, Object> context, WxMpService wxMpService,
        WxSessionManager sessionManager) {
        // TODO 处理门店审核事件
        return null;
    }

}

SubscribeHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import org.springframework.stereotype.Component;
import com.example.wxmsg.wxmp.builder.TextBuilder;

/**
 * @desc 订阅处理
 */
@Component
public class SubscribeHandler extends AbstractHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
        Map<String, Object> context, WxMpService weixinService,
        WxSessionManager sessionManager) throws WxErrorException {
        try {
            WxMpConfigStorage wxMpConfigStorage = weixinService.getWxMpConfigStorage();
            this.logger.info("当前公众号AppId:[{}];新关注用户 OPENID: [{}]", wxMpConfigStorage.getAppId(),
                wxMessage.getFromUser());
            // TODO: 2023/3/27 此处可以循环调用KfSessionHandler发送消息
            //默认返回一条信息
            return new TextBuilder().build("订阅成功", wxMessage, weixinService);
        } catch (
            Exception e) {
            this.logger.error(e.getMessage(), e);
        }
        return null;
    }
}

TextMsgHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import org.springframework.stereotype.Component;

/**
 * @desc: 文本类型消息处理-TEXT
 */
@Component
public class TextMsgHandler extends AbstractHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> map, WxMpService wxMpService,
        WxSessionManager wxSessionManager) throws WxErrorException {
        WxMpConfigStorage wxMpConfigStorage = wxMpService.getWxMpConfigStorage();
        this.logger.info("当前公众号AppId:[{}];新关注用户 OPENID: [{}]", wxMpConfigStorage.getAppId(), wxMessage.getFromUser());
        //公众号对话处理
        return null;
    }

}

UnsubscribeHandler.java

package com.example.wxmsg.wxmp.handler;

import java.util.Map;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

/**
 * @desc 订阅取消管理
 */
@Component
public class UnsubscribeHandler extends AbstractHandler {
    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
        Map<String, Object> context, WxMpService wxMpService,
        WxSessionManager sessionManager) {
        String openId = wxMessage.getFromUser();
        //根据openId查询unionId
        this.logger.info("取消关注用户 OPENID: " + openId);
        return null;
    }

}

4、其他类

AbstractBuilder.java

import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;

/**
 * @desc 微信回复消息构建类
 */
public abstract class AbstractBuilder {

    /**
     * 构建xml消息内容
     *
     * @param content   消息内容
     * @param wxMessage 消息对象
     * @param service
     * @return
     */
    public abstract WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage, WxMpService service);
}

ImageBuilder.java

import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutImageMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;

/**
 * @desc 构建图文消息
 */
public class ImageBuilder extends AbstractBuilder {

    @Override
    public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
                                   WxMpService service) {

        WxMpXmlOutImageMessage m = WxMpXmlOutMessage
                .IMAGE()
                .mediaId(content)
                .fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser())
                .build();
        return m;
    }

}

TextBuilder.java

import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage;

/**
 * @desc 构建纯文本消息
 */
public class TextBuilder extends AbstractBuilder {

    @Override
    public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
                                   WxMpService service) {
        WxMpXmlOutTextMessage m = WxMpXmlOutMessage
                .TEXT()
                .content(content)
                .fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser())
                .build();
        return m;
    }
}

需要注意的是:

(1)消息回复的类型有文本、图片、图文、语音、视频、音乐等;

(2)图片、视频等消息都需要先上传到素材库并获取该素材的mediaId;

(3)回复的消息还可以是小程序卡片,但需要保证当前小程序必须绑定在该公众号下

(4)假如服务器无法保证在五秒内处理并回复,也必须回复,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示

三、服务器处理微信回调事件,并进行分发

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;


@Slf4j
@AllArgsConstructor
@RestControllerpublic class WxPortalController {
    private final WxMpService wxService;
    private final WxMpMessageRouter messageRouter;

    @PostMapping(value="handleWxEvent",produces = "application/xml; charset=UTF-8")
    public String handleWxEvent(@PathVariable String appid,
                       @RequestBody String requestBody,
                       @RequestParam("signature") String signature,
                       @RequestParam("timestamp") String timestamp,
                       @RequestParam("nonce") String nonce,
                       @RequestParam("openid") String openid,
                       @RequestParam(name = "encrypt_type", required = false) String encType,
                       @RequestParam(name = "msg_signature", required = false) String msgSignature) {
        log.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
                + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
            openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
if (!wxService.checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
        }

        String out = null;
        if (encType == null) {
            // 明文传输的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage == null) {
                return "";
            }

            out = outMessage.toXml();
        } else if ("aes".equalsIgnoreCase(encType)) {
            // aes加密的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(),
                timestamp, nonce, msgSignature);
            log.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage == null) {
                return "";
            }
            out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
        }

        log.debug("\n组装回复信息:{}", out);
        return out;
    }

    private WxMpXmlOutMessage route(WxMpXmlMessage message) {
        try {
            return this.messageRouter.route(message);
        } catch (Exception e) {
            log.error("路由消息时出现异常!", e);
        }

        return null;
    }

}

四、构建回复消息

1、关注公众号回复欢迎用户

微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息

这里我们可以看到,关注【乡荣】公众号后,不仅回复了信息,而且是两条。实现思路:

(1)第一条消息,当用户订阅公众号时会调用SubscribeHandler,该handler会返回一个WxMpXmlOutMessage,这个就是默认返回值

(2)第二条消息,我们可以使用【微信客服】发送,直接使用下面的方法进行发送

wxService.getKefuService().sendKefuMessage(WxMpKefuMessage
                    .TEXT()
                    .toUser(wxMessage.getFromUser())
                    .content("客服回复内容")
                    .build()); 

2、回复小程序卡片消息

微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息

回复小程序卡片这个功能在微信公众平台是找不到的,这个功能只能使用代码实现,这里就体现出代码的强大了💪。

如上图所示:当我们输入“最新直播”时,小程序会返回当前最新直播的小程序卡片,点击即可进入小程序。实现思路:

(1)用户输入的是文本消息,处理应该在TextMsgHandler中

(2)默认返回的WxMpXmlOutMessage是没有小程序卡片这个类型的,所以这里还得借助客服消息

(3)小程序卡片需要一个封面,且这个封面图必须上传到微信素材库后获取mediaId,上传代码如下:

//获取素材库相关实现
WxMpMaterialService materialService = wpService.getMaterialService();
//上传临时素材
WxMediaUploadResult wxMediaUploadResult = materialService.mediaUpload(WxConsts.KefuMsgType.IMAGE, ".jpg", inputStream);
//获取素材ID
String mediaId = wxMediaUploadResult.getMediaId();

(4)构建小程序卡片信息文章来源地址https://www.toymoban.com/news/detail-499905.html

 wpService.getKefuService().sendKefuMessage(WxMpKefuMessage
                    .MINIPROGRAMPAGE()
                    .title("小程序卡片标题")
                    .toUser(wxMessage.getFromUser())
                    .thumbMediaId(mediaId)
                    .appId("小程序ID")
                    .pagePath("卡片要跳转的路径").build());
   

到了这里,关于微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • spring boot整合第三方微信开发工具 weixin-java-miniapp 实现小程序微信登录

    有时候项目需要用到微信登录或获取用户的手机号码,weixin-java-miniapp是一个好用的第三方工具,不用我们自己写httpcline调用。 导入jar包 添加一个resource.properties文件,写上小程序的appid和secret 添加两个配置文件 WxMaProperties.java WxMaConfiguration.java 如何使用 小程序给微信发送消息

    2024年02月16日
    浏览(33)
  • 微信小程序:This Mini Program cannot be opened as your Weixin version is out-of-date.

    升级基础库3.2.0,然后PC端整个小程序都打不开了,点击小程序提示 ”This Mini Program cannot be opened as your Weixin version is out-of-date. Update Weixin to the latest version.“ ,并且点击 Update Weixin 按钮没有反应 pc基础库还没那么高 PC端的隐私能力还未上线,也不会拦截隐私接口调用 这个问题

    2024年02月03日
    浏览(36)
  • 微信小程序不在以下 request 合法域名列表中,请参考文档:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/n

    出现不在以下 request 合法域名列表中,请参考文档:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html 如果时仅仅提供了http协议接口、暂时没用提供https协议的接口 可以开启[不校验合法域名、TLS版本以及HTTPS证书]的选项 只能在开发和调试使用,项目上线之后要勾

    2024年02月15日
    浏览(33)
  • 微信小程序生态7-微信公众号设置IP白名单

    微信小程序生态1-初识小程序 微信小程序生态2-创建一个微信小程序 微信小程序生态3-微信小程序登录流程设计 微信小程序生态4-扫普通二维码进入小程序、打开短链接进入小程序 微信小程序生态5-微信公众号扫码登录PC端网页 微信小程序生态6-微信公众号授权登录(适用于H

    2024年02月01日
    浏览(26)
  • 基于Java+微信小程序实现《微信阅读平台》

    博主介绍 : ✌ 全网粉丝30W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精彩专栏 推荐订阅 👇🏻 不然下次找不到哟 2022-2024年

    2024年02月07日
    浏览(28)
  • 【微信小程序】基于Java+uniapp框架开发的全开源微信小程序商城系统

    基于Java+uniapp框架开发的全开源微信小程序商城系统,前端采用目前主流的uniapp框架开发,后端采用Java语言开发,前后端代码全部开源,减少重复造轮子,支持小程序商城秒杀、优惠券、多商户、直播卖货、分销等功能,帮助商家快速搭建一个属于自己的微信小程序商城。

    2024年02月16日
    浏览(41)
  • 基于Java+微信小程序实现《优购电商小程序》

    博主介绍 : ✌ 全网粉丝30W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精彩专栏 推荐订阅 👇🏻 不然下次找不到哟 2022-2024年

    2024年02月07日
    浏览(32)
  • 基于Java+微信小程序实现《医院管理系统小程序》

    博主介绍 : ✌ 全网粉丝30W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精彩专栏 推荐订阅 👇🏻 不然下次找不到哟 2022-2024年

    2024年02月06日
    浏览(38)
  • 基于Java微信小程序的医院挂号小程序,附源码

    博主介绍:✌IT徐师兄、7年大厂程序员经历。全网粉丝15W+、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅 文末获取源码联系 🍅 👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟 2022-2024年最全的计算机软件毕业设计选题大全:

    2024年04月09日
    浏览(34)
  • 微信小程序生态13-微信公众号自定义菜单、个性化菜单配置

    微信小程序生态1-初识小程序 微信小程序生态2-创建一个微信小程序 微信小程序生态3-微信小程序登录流程设计 微信小程序生态4-扫普通二维码进入小程序、打开短链接进入小程序 微信小程序生态5-微信公众号扫码登录PC端网页 微信小程序生态6-微信公众号授权登录(适用于H

    2024年02月13日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包