第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > 微信小程序入门8-基于weixin-java-mp实现微信公众号被动回复消息

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

时间:2020-12-28 05:36:47

相关推荐

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

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

这里有两种格式的消息

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

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

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

参考文档链接:https://developers./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地址如下:/binarywang/weixin-java-mp-demo

wiki文档如下:/Wechat-Group/WxJava/wiki

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

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

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

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

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

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

签名校验代码如下:

@RequestMapping(value = "handleWxEvent", method = RequestMethod.POST, produces = "application/xml; charset=UTF-8")@ResponseBodypublic 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处理

说明:

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

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

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

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

2、wxmp包如下

WxMpConfig.class

import mon.collect.Maps;import me.mon.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.mon.api.WxConsts.EventType.SUBSCRIBE;import static me.mon.api.WxConsts.EventType.UNSUBSCRIBE;import static me.mon.api.WxConsts.XmlMsgType.EVENT;import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.*;import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;@Configurationpublic 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;/*** 日志处理*/@Autowiredprivate LogHandler logHandler;@Autowiredprivate NullHandler nullHandler;@Autowiredprivate KfSessionHandler kfSessionHandler;@Autowiredprivate StoreCheckNotifyHandler storeCheckNotifyHandler;@Autowiredprivate LocationHandler locationHandler;@Autowiredprivate MenuHandler menuHandler;@Autowiredprivate MsgHandler msgHandler;@Autowiredprivate UnsubscribeHandler unsubscribeHandler;@Autowiredprivate SubscribeHandler subscribeHandler;@Autowiredprivate ScanHandler scanHandler;@Autowiredprivate TextMsgHandler textMsgHandler;@Autowiredprivate 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;}@Beanpublic 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如下

需要注意的是:

(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 mons.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、关注公众号回复欢迎用户

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

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

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

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

2、回复小程序卡片消息

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

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

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

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

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

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

(4)构建小程序卡片信息

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。