微信公众号的开发中,消息处理至关重要。微信会发送各式各样的消息,公众号需作出相应应对,这其中涉及众多技巧。例如,如何高效应对不同类型的消息,以及如何提升access_token获取的效率等问题。这些都是开发公众号时必须掌握的核心知识。
@RequestMapping("send")
public String send(@RequestBody String requestBody, @RequestParam("signature") String signature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) {
// 校验签名
if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
log.error("签名校验 ===》 非法请求");
// 消息签名不正确,说明不是公众平台发过来的消息
return null;
}
log.error("签名校验 ===》 验证成功");
// 解析消息体,封装为对象
WxMpXmlMessage xmlMessage = WxMpXmlMessage.fromXml(requestBody);
// 接收消息内容
String inContent = xmlMessage.getContent();
// 响应的消息内容
String outContent;
// 根据不同的关键字回复消息
if (inContent.contains("hello")) {
outContent = "hello world";
} else if (inContent.contains("java")) {
outContent = "hello java";
} else {
outContent = "服务繁忙,暂时不能回复";
}
// 构造响应消息对象
WxMpXmlOutTextMessage outTextMessage = WxMpXmlOutMessage.TEXT().content(outContent).fromUser(xmlMessage.getToUser())
.toUser(xmlMessage.getFromUser()).build();
// 将响应消息转换为xml格式返回
return outTextMessage.toXml();
}
不同消息类型的回复对象
信息种类繁多,对于各类信息,存在一种特别的回复对象,称作WxMpXmlOutTextMessage。这相当于一座桥梁,将公众号与用户紧密相连。例如,当用户发送文本或其它形式的信息时,开发者可通过构建此对象的不同方式来作出回应。在实际的开发过程中,开发者需依据信息类型来决定如何构建该对象,以向用户提供恰当的反馈。此外,在某些情况下,信息类型难以辨识,这时开发者可能需要投入更多精力来处理这些问题。
信息种类繁多,公众号需作出相应应对。以小商家公众号为例,用户可能咨询产品或反映问题,若处理不当,用户满意度将大打折扣。因此,对各类信息作出精确回应是提高服务质量的关键。
msgType
event
eventKey
content
微信消息路由器的作用
WxMpMessageRouter这个消息路由器真是个好帮手。微信推送的公众号消息种类繁多,若用if/else逐一判断,确实挺麻烦。而这个路由器却能从四个方面对消息进行匹配。例如,某些公众号拥有多种功能模块,每个模块对应不同的消息,这时,消息路由器便能准确地将消息导向相应的处理区域。
比如,我了解一个提供资讯的公众号,它设有多个栏目,比如时事报道、娱乐新闻等。这些栏目对应着不同类型的消息,而通过消息路由器,这些消息能准确分配到相应的栏目进行管理。这样一来,公众号处理信息的速度得到了显著提升,同时,整个系统的结构也更加清晰和科学。
public interface WxMpMessageHandler {
/**
*
* @param wxMessage
* @param context 上下文,如果同一个路由规则内的handler或interceptor之间有信息要传递,可以用这个
* @param wxMpService
* @return xml格式的消息,如果在异步规则里处理的话,可以返回null
*/
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map context,
WxMpService wxMpService,
WxSessionManager sessionManager) ;
}
消息处理器的实现
针对不同种类的信息处理,我们需要自行编写符合WxMpMessageHandler接口的消息处理器。以用户询问订单信息为例,我们需通过实现该接口来应对此类信息。这实际上是针对具体业务需求进行消息定制处理的关键环节。由于各个业务场景各不相同,消息处理器必须作出适当的调整。
public interface WxMpMessageInterceptor {
/**
* 拦截微信消息
* @param wxMessage
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个
* @param wxMpService
* @return true代表OK,false代表不OK
*/
public boolean intercept(WxMpXmlMessage wxMessage,
Map context,
WxMpService wxMpService,
WxSessionManager sessionManager) ;
}
一些在线商城的公众号,买家下单或查询物流时,需要不同的消息处理器。若接口实现不当,消息处理将出现问题,可能引发订单错误或物流信息混乱,给业务带来不便。
添加拦截器处理消息
@Component
public class MyTextHandler implements WxMpMessageHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService, WxSessionManager sessionManager) throws WxErrorException {
// 接收消息内容
String inContent = wxMessage.getContent();
// 响应的消息内容
String outContent;
// 根据不同的关键字回复消息
if (inContent.contains("hello")) {
outContent = "hello world";
} else if (inContent.contains("java")) {
outContent = "hello java";
} else if (inContent.contains("***")) {
outContent = "请文明用语";
} else {
outContent = "服务繁忙,暂时不能回复";
}
// 构造响应消息对象
return WxMpXmlOutMessage.TEXT().content(outContent).fromUser(wxMessage.getToUser())
.toUser(wxMessage.getFromUser()).build();
}
}
偶尔,我们可引入WxMessageInterceptor拦截器。当处理微信公众账号信息时,它能对信息进行预处理和筛选。需自行编写拦截处理器,并实现WxMessageHandler接口。例如,若公众账号接收到恶意或广告信息,拦截器能先行过滤。
/**
* 对微信公众号消息进行预处理、过滤等操作,根据具体业务需求决定是否允许继续执行后面的路由处理方法
*
* 如果要中止消息的继续处理,即表示拦截了这个消息,需要返回 false。否则,在执行完当前拦截器操作后,允许消息的继续处理,返回 true
*/
@Component
public class MyTextInterceptor implements WxMpMessageInterceptor {
@Override
public boolean intercept(WxMpXmlMessage wxMpXmlMessage, Map map, WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
String msg = wxMpXmlMessage.getContent();
String msgType = wxMpXmlMessage.getMsgType();
if (msgType.equals("text") && msg.contains("混蛋")) {
wxMpXmlMessage.setContent("***");
return true;
}
return true;
}
}
某公司的客服公众号常收到无关紧要的广告信息。若安装拦截工具,便能阻止这些信息进入后续的繁琐处理步骤,仅将客户咨询和投诉等有用信息送达指定处理环节,从而既节约了资源,又提高了工作效率。
消息路由的配置与使用
为了处理不同种类的信息,我们依赖消息路由对象WxMpMessageRouter。在Controller中注入此对象,即可将信息精确地导向相应的处理器。以一个提供多业务的服务公众号为例,如外卖点餐、家政等,这种配置能确保各业务相关的信息被准确送达至对应的处理器,从而有序推进各项业务。
@Configuration
public class MessageRouterConfig {
@Autowired
private WxMpService wxMpService;
@Autowired
private MyTextHandler textHandler;
@Autowired
private MyTextInterceptor textInterceptor;
@Bean
public WxMpMessageRouter messageRouter() {
// 创建消息路由
final WxMpMessageRouter router = new WxMpMessageRouter(wxMpService);
// 添加一个同步处理文本消息的路由规则 同时添加interceptor、handler
router.rule().async(false).msgType(WxConsts.XmlMsgType.TEXT).interceptor(textInterceptor).handler(textHandler).end();
return router;
}
}
在实际情况中,若这一环节处理不当,信息便会陷入混乱。例如,外卖订单的信息误入家政服务的处理系统,整个业务流程便会陷入混乱。
access_token的持久化
@Slf4j
@RestController
public class TestController {
@Autowired
private WxMpService wxMpService;
@Autowired
private WxMpMessageRouter wxMpMessageRouter;
@RequestMapping("send")
public String configAccess(@RequestBody String requestBody, @RequestParam("signature") String signature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) {
// 校验签名
if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
log.error("签名校验 ===》 非法请求");
// 消息签名不正确,说明不是公众平台发过来的消息
return null;
}
log.error("签名校验 ===》 验证成功");
// 解析消息体,封装为对象
WxMpXmlMessage xmlMessage = WxMpXmlMessage.fromXml(requestBody);
WxMpXmlOutMessage outMessage = null;
try {
// 将消息路由给对应的处理器,获取响应
outMessage = wxMpMessageRouter.route(xmlMessage);
} catch (Exception e) {
log.error("消息路由异常", e);
}
// 将响应消息转换为xml格式返回
return outMessage == null ? null : outMessage.toXml();
}
}
微信公众号开发中,对access_token的管理颇为关键。WxMpConfigStorage负责存储公众号的相关信息,其中的access_token尤为关键。微信API在获取此token时有限制,若每次交互都重新获取,不仅效率低下,还可能遭遇获取失败的风险。在分布式环境中,这一问题更为突出。
大型互联网公司通常拥有众多子项目,其中不少是微信公众号。若要分别获取每个服务的资源,既繁琐又浪费。因此,我们可以将access_token长期保存在redis中。这就像将宝藏存放在保险库,需要时直接取用,从而大幅提高整体效率。但若使用redisTemplate的type,则需要额外引入相应的依赖。
在使用微信公众号开发服务的各位朋友中,是否有人遇到过消息处理上的混乱问题,或者是在获取access_token时遇到了麻烦?不妨点个赞,分享这篇文章,并在评论区交流讨论。