完成公众号的接入之后,公众号的开发才正式开始。

在微信用户和公众号产生交互的过程中,用户的某些操作会使得微信服务器通过事件推送的形式通知到开发者在开发者中心处设置的服务器地址,从而开发者可以获取到该信息。其中,某些事件推送在发生后,是允许开发者回复用户的,某些则不允许,详细内容如下:

关注/取消关注事件
扫描带参数二维码事件
上报地理位置事件
自定义菜单事件
点击菜单拉取消息时的事件推送
点击菜单跳转链接时的事件推送

这里以关注取消事件为例

用户在关注与取消关注公众号时,微信会把这个事件推送到开发者填写的URL。方便开发者给用户下发欢迎消息或者做帐号的解绑。为保护用户数据隐私,开发者收到用户取消关注事件时需要删除该用户的所有信息。

微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。

关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。

假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。

推送XML数据包示例:

<xml>
<ToUserName>< ![CDATA[toUser] ]></ToUserName>
<FromUserName>< ![CDATA[FromUser] ]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType>< ![CDATA[event] ]></MsgType>
<Event>< ![CDATA[subscribe] ]></Event>
</xml>

参数说明:

参数               描述
ToUserName       开发者微信号
FromUserName     发送方帐号(一个OpenID)
CreateTime       消息创建时间 (整型)
MsgType          消息类型,event
Event            事件类型,subscribe(订阅)、unsubscribe(取消订阅)

当用户点击关注,微信通过post请求访问URL:域名/端口/wechat/handler
经过控制器controller的判断后,将处理后的入参传给接口MessageHandleService

package cc.feefox.wechat.main;import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Objects;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;import cc.feefox.wechat.common.util.SignatureUtil;
import cc.feefox.wechat.common.util.StringUtils;
import cc.feefox.wechat.common.util.XmlUtil;
import cc.feefox.wechat.message.service.interfaces.MessageHandleService;/*** 微信消息入口* * @Package: cc.feefox.wechat.main* @author: cc* @date: 2018年8月18日 下午12:18:39*/
@RestController
@RequestMapping("/wechat")
public class WeChatController extends BaseController {private static final Logger logger = LoggerFactory.getLogger(WeChatController.class);@Autowiredprivate MessageHandleService messageHandleService;/*** 校验信息是否是从微信服务器发出,处理消息* * @param request* @param out* @throws IOException*/@RequestMapping(value = "/handler", method = { RequestMethod.GET, RequestMethod.POST })public void processPost() throws Exception {this.getRequest().setCharacterEncoding("UTF-8");this.getResponse().setCharacterEncoding("UTF-8");logger.info("开始校验信息是否是从微信服务器发出");boolean ispost = Objects.equals("POST", this.getRequest().getMethod().toUpperCase());if (ispost) {logger.debug("接入成功,正在处理逻辑");InputStream inputStream = this.getRequest().getInputStream();Map<String, String> params = XmlUtil.parseStreamToMap(inputStream);String respXml = messageHandleService.handleMessage(params);if (StringUtils.isNotNull(respXml)) {// 输出流this.getResponse().getWriter().write(respXml);}} else {// 签名String signature = this.getRequest().getParameter("signature");// 时间戳String timestamp = this.getRequest().getParameter("timestamp");// 随机数String nonce = this.getRequest().getParameter("nonce");// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败if (SignatureUtil.checkSignature(signature, timestamp, nonce)) {// 随机字符串String echostr = this.getRequest().getParameter("echostr");logger.debug("接入成功,echostr {}", echostr);this.getResponse().getWriter().write(echostr);}}}
}

MessageHandleService接口对参数进行封装处理,传给CodeHandleService进行分类处理

/*** @ClassName: MessageHandleServiceImpl * @Description: TODO* @author: cc* @date: 2018年8月18日 上午11:48:28* */
package cc.feefox.wechat.message.service.impl;import java.util.Map;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import cc.feefox.wechat.common.result.WeChatResult;
import cc.feefox.wechat.common.util.MessageUtil;
import cc.feefox.wechat.message.model.BaseMessage;
import cc.feefox.wechat.message.model.NewsMessage;
import cc.feefox.wechat.message.service.interfaces.CodeHandleService;
import cc.feefox.wechat.message.service.interfaces.MessageHandleService;/*** @Package: cc.feefox.wechat.message.service.impl* @author: cc* @date: 2018年8月18日 上午11:48:28*/
@Service
public class MessageHandleServiceImpl implements MessageHandleService {private static final Logger logger = LoggerFactory.getLogger(MessageHandleServiceImpl.class);@Autowiredprivate CodeHandleService codeHandleService;/** 对来自微信的消息作出响应(包含消息和事件)* * @param inputStream* * @return* * @throws Exception*/@Overridepublic String handleMessage(Map<String, String> params) throws Exception {logger.info("开始处理【message】信息");String result = null;if (params != null && params.size() > 0) {BaseMessage msgInfo = new BaseMessage();String createTime = params.get("CreateTime");String msgId = params.get("MsgId");msgInfo.setCreateTime((createTime != null && !"".equals(createTime)) ? Integer.parseInt(createTime) : 0);msgInfo.setFromUserName(params.get("FromUserName"));msgInfo.setMsgId((msgId != null && !"".equals(msgId)) ? Long.parseLong(msgId) : 0);msgInfo.setToUserName(params.get("ToUserName"));WeChatResult resp = codeHandleService.handleCode(params, msgInfo);if (null == resp) {
//              String str = "<xml>\r\n" + "  <ToUserName><![CDATA[oWnU700PB2HTtgzReJva2Gz00000]]></ToUserName>\r\n"
//                      + "  <FromUserName><![CDATA[gh_23ba766d4f8c]]></FromUserName>\r\n"
//                      + "  <CreateTime><![CDATA[1534324363936]]></CreateTime>\r\n"
//                      + "  <MsgType><![CDATA[news]]></MsgType>\r\n" + "  <FuncFlag><![CDATA[0]]></FuncFlag>\r\n"
//                      + "  <ArticleCount><![CDATA[2]]></ArticleCount>\r\n" + "  <Articles>\r\n" + "    <item>\r\n"
//                      + "      <Title><![CDATA[飞狐互动:feefox]]></Title>\r\n"
//                      + "      <Description><![CDATA[欢迎关注我的个人博客<a href=\"http://118.25.62.232/images/showreel.jpg\">图片</a><a href=\"http://118.25.62.232/images/showreel.jpg\">图片</a>]]></Description>\r\n"
//                      + "      <PicUrl><![CDATA[http://118.25.62.232/images/showreel.jpg]]></PicUrl>\r\n"
//                      + "      <Url><![CDATA[http://118.25.62.232/apple/]]></Url>\r\n" + "    </item>\r\n"
//                      + "    <item>\r\n" + "      <Title><![CDATA[飞狐互动:feefox]]></Title>\r\n"
//                      + "      <Description><![CDATA[欢迎关注我的个人博客<a href=\"http://118.25.62.232/images/showreel.jpg\">图片</a><a href=\"http://118.25.62.232/images/showreel.jpg\">图片</a>]]></Description>\r\n"
//                      + "      <PicUrl><![CDATA[http://118.25.62.232/images/showreel.jpg]]></PicUrl>\r\n"
//                      + "      <Url><![CDATA[http://118.25.62.232/apple/]]></Url>\r\n" + "    </item>\r\n"
//                      + "  </Articles>\r\n" + "</xml>";
//              return str;return null;}boolean success = resp.isSuccess(); // 如果 为true,则表示返回xml文件, 直接转换即可,否则按类型if (success) {result = resp.getObject().toString();} else {int type = resp.getType(); // 这里规定 1 图文消息 否则直接转换if (type == WeChatResult.NEWSMSG) {NewsMessage message = (NewsMessage) resp.getObject();result = MessageUtil.newsMessagegToXml(message);return result;} else {BaseMessage baseMessage = (BaseMessage) resp.getObject();result = MessageUtil.baseMessageToXml(baseMessage);return result;}}} else {result = "msg is wrong";}return result;}}

CodeHandleService层完成消息的分类后,将数据传递给实现层WechatMsgService进行逻辑处理

/*** @ClassName: CodeHandleServiceImpl * @Description: TODO* @author: cc* @date: 2018年8月18日 下午2:14:06* */
package cc.feefox.wechat.message.service.impl;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import cc.feefox.wechat.common.constant.MessagegConstant;
import cc.feefox.wechat.common.result.WeChatResult;
import cc.feefox.wechat.common.util.StringUtils;
import cc.feefox.wechat.message.model.BaseMessage;
import cc.feefox.wechat.message.service.interfaces.CodeHandleService;
import cc.feefox.wechat.message.service.interfaces.WechatMsgService;/*** @Package: cc.feefox.wechat.message.service.impl* @author: cc* @date: 2018年8月18日 下午2:14:06*/
@Service
public class CodeHandleServiceImpl implements CodeHandleService {@Autowiredprivate WechatMsgService wechatMsgService;/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult handleCode(Map<String, String> params, BaseMessage msgInfo) {WeChatResult result = new WeChatResult();String msgInfoType = params.get("MsgType");if (!StringUtils.isBlank(msgInfoType)) {switch (msgInfoType) {case MessagegConstant.REQ_MESSAGE_TYPE_TEXT: // 文本消息result = wechatMsgService.textMsgInfo(params, msgInfo);break;case MessagegConstant.REQ_MESSAGE_TYPE_IMAGE: // 图片消息result = wechatMsgService.imageMsgInfo(params, msgInfo);break;case MessagegConstant.REQ_MESSAGE_TYPE_LINK: // 链接消息result = wechatMsgService.linkMsgInfo(params, msgInfo);break;case MessagegConstant.REQ_MESSAGE_TYPE_LOCATION: // 地理位置result = wechatMsgService.locationMsgInfo(params, msgInfo);break;case MessagegConstant.REQ_MESSAGE_TYPE_VOICE: // 音频消息result = wechatMsgService.voiceMsgInfo(params, msgInfo);break;case MessagegConstant.REQ_MESSAGE_TYPE_SHORTVIDEO: // 短视频消息result = wechatMsgService.shortVideo(params, msgInfo);break;case MessagegConstant.REQ_MESSAGE_TYPE_VIDEO: // 视频消息result = wechatMsgService.videoMsgInfo(params, msgInfo);break;case MessagegConstant.REQ_MESSAGE_TYPE_EVENT: // 事件消息String eventType = params.get("Event"); //if (eventType != null && !"".equals(eventType)) {switch (eventType) {case MessagegConstant.EVENT_TYPE_SUBSCRIBE:result = wechatMsgService.subscribe(params, msgInfo);break;case MessagegConstant.EVENT_TYPE_UNSUBSCRIBE:result = wechatMsgService.unsubscribe(params, msgInfo);break;case MessagegConstant.EVENT_TYPE_SCAN:result = wechatMsgService.scan(params, msgInfo);break;case MessagegConstant.EVENT_TYPE_LOCATION:result = wechatMsgService.eventLocation(params, msgInfo);break;case MessagegConstant.EVENT_TYPE_CLICK:result = wechatMsgService.eventClick(params, msgInfo);break;case MessagegConstant.EVENT_TYPE_VIEW:result = wechatMsgService.eventView(params, msgInfo);break;case MessagegConstant.KF_CREATE_SESSION:result = wechatMsgService.kfCreateSession(params, msgInfo);break;case MessagegConstant.KF_CLOSE_SESSION:result = wechatMsgService.kfCloseSession(params, msgInfo);break;case MessagegConstant.KF_SWITCH_SESSION:result = wechatMsgService.kfSwitchSession(params, msgInfo);break;default:wechatMsgService.eventDefaultReply(params, msgInfo);break;}}break;default:wechatMsgService.defaultMsgInfo(params, msgInfo);}}return result;}}

最后,WechatMsgService层作出相应的响应,组织回复消息。

/*** @ClassName: WechatMsgServiceImpl * @Description: TODO* @author: cc* @date: 2018年8月18日 下午3:19:48* */
package cc.feefox.wechat.message.service.impl;import java.util.Map;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import cc.feefox.wechat.common.json.JsonConfig;
import cc.feefox.wechat.common.result.WeChatResult;
import cc.feefox.wechat.common.util.DateTimeUtil;
import cc.feefox.wechat.customer.service.interfaces.CustomService;
import cc.feefox.wechat.main.WeChatController;
import cc.feefox.wechat.message.model.BaseMessage;
import cc.feefox.wechat.message.model.TextMessage;
import cc.feefox.wechat.message.service.interfaces.WechatMsgService;
import net.sf.json.JSONObject;/*** @Package: cc.feefox.wechat.message.service.impl* @author: cc* @date: 2018年8月18日 下午3:19:48*/
@Service
public class WechatMsgServiceImpl implements WechatMsgService {@Autowiredprivate CustomService customService;private static final Logger logger = LoggerFactory.getLogger(WeChatController.class);/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult textMsgInfo(Map<String, String> params, BaseMessage msgInfo) {logger.info("文本消息");WeChatResult result = new WeChatResult();TextMessage text = new TextMessage();text.setContent(params.get("Content").trim());// 自动回复text.setCreateTime(DateTimeUtil.currentTime());text.setToUserName(msgInfo.getFromUserName());text.setFromUserName(msgInfo.getToUserName());text.setMsgId(msgInfo.getMsgId());text.setMsgType("text");result.setObject(text);return result;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult imageMsgInfo(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult linkMsgInfo(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult locationMsgInfo(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult voiceMsgInfo(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult shortVideo(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult videoMsgInfo(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult subscribe(Map<String, String> params, BaseMessage msgInfo) {logger.info("开始调用关注回复服务");// 关注回复,使用客服接口customService.handlerCustomerMessage_subscribe(params);// 发送小程序卡片customService.handlerCustomerMessage_miniprogrampage(params);return null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult unsubscribe(Map<String, String> params, BaseMessage msgInfo) {return null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult scan(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult eventLocation(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult eventClick(Map<String, String> params, BaseMessage msgInfo) {logger.info("CLICK_RGKF事件");if (params.get("EventKey").equals("CLICK_BUG")) {String text = JsonConfig.getJsonResource("datas/BUG").toString();JSONObject json = JSONObject.fromObject(text);json.put("touser", params.get("FromUserName"));customService.handleKefuMessage(json);}if (params.get("EventKey").equals("CLICK_RGKF")) {String text = JsonConfig.getJsonResource("datas/rgkf").toString();JSONObject json = JSONObject.fromObject(text);json.put("touser", params.get("FromUserName"));customService.handleKefuMessage(json);}return null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult eventView(Map<String, String> params, BaseMessage msgInfo) {logger.info("view事件,人工客服");//      String content = "欢迎关注我的微信公众号";
//      WeChatResult result = new WeChatResult();
//      String text = JsonConfig.getJsonResource("datas/rgkf").toString();//      TextMessage text = new TextMessage();
//      text.setContent(content);// 自动回复
//      text.setCreateTime(DateTimeUtil.currentTime());
//      text.setToUserName(msgInfo.getFromUserName());
//      text.setFromUserName(msgInfo.getToUserName());
//      text.setMsgId(msgInfo.getMsgId());
//      text.setMsgType("text");
//      result.setObject(text);return null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult kfCreateSession(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult kfCloseSession(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo* * @return*/@Overridepublic WeChatResult kfSwitchSession(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stubreturn null;}/** TODO* * @param params* * @param msgInfo*/@Overridepublic void eventDefaultReply(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stub}/** TODO* * @param params* * @param msgInfo*/@Overridepublic void defaultMsgInfo(Map<String, String> params, BaseMessage msgInfo) {// TODO Auto-generated method stub}}

如有错漏请指出,欢迎加群 581817132

Java 微信公众平台开发(二)——事件推送与被动回复相关推荐

  1. Java微信公众平台开发(二)--微信服务器post消息体的接收

    转自: http://www.cuiyongzhi.com/post/39.html 在上一篇的文章中我们详细讲述了如何将我们的应用服务器和微信腾讯服务器之间的对接操作,最后接入成功,不知道你有没有发 ...

  2. 微信公众号开发-----接送事件推送之关注/取消关注

    本文主要实现的功能包括 关注/取消关注事件 阅读本文之前请先认真阅读微信公众号技术文档之接受事件推送 需注意的是:验证消息的确来自微信服务器和接收事件时微信服务器都会发送请求到填写的服务器地址URL上 ...

  3. 微信公众号开发-菜单事件推送

    菜单事件推送在微信公众号开发中也是属于比较常用的一个功能,就是用户点击菜单之后,微信会将事件推送给接口程序. 不过微信开发到现在也是老生常谈的的东西了,我就简单写一下菜单事件推送的这个过程. 注意:点 ...

  4. Java微信公众平台开发--番外篇,对GlobalConstants文件的补充

    转自:http://www.cuiyongzhi.com/post/63.html 之前发过一个[微信开发]系列性的文章,也引来了不少朋友观看和点评交流,可能我在写文章时有所疏忽,对部分文件给出的不是 ...

  5. Java微信公众平台开发(一)--接入微信公众平台

    转载自崔用志博客:http://www.cuiyongzhi.com/ 前面几篇文章一直都在说微信公众平台的开发准备工作,那么从这篇开始我们就将正式的进入JAVA微信公众平台开发的整个流程,那么这篇我 ...

  6. Java微信公众平台开发(一)——接入微信公众平台

    前面几篇文章一直都在说微信公众平台的开发准备工作,那么从这篇开始我们就将正式的进入JAVA微信公众平台开发的整个流程,那么这篇我们开始聊聊如何将我们的服务端和微信公众平台对接! (一)接入流程解析 在 ...

  7. PHP实现微信公众平台开发---提升篇(上传素材并回复)

    一.HTTP接收事件订阅与恢复响应消息 i. 接收事件推送 并回复 1. 无连接:当用户关注微信公众账号的时候  微信公众平台会向我们推送post请求  关注推送的并不是数组  而是XML 2. 接收 ...

  8. php公众号开发关注事件推送图文_PHP_微信公众平台开发关注及取消关注事件的方法,本文实例讲述了微信公众平台 - phpStudy...

    微信公众平台开发关注及取消关注事件的方法 本文实例讲述了微信公众平台开发关注及取消关注事件的方法.分享给大家供大家参考.具体分析如下: 用户在关注与取消关注公众号时,微信会把这个事件推送到开发者填写的 ...

  9. 微信信息回复 java,微信公众平台开发中使用Java如何实现一个消息回复功能

    微信公众平台开发中使用Java如何实现一个消息回复功能 发布时间:2020-11-17 16:11:11 来源:亿速云 阅读:82 作者:Leah 本篇文章给大家分享的是有关微信公众平台开发中使用Ja ...

最新文章

  1. 单机负载告警,数据库与应用分离
  2. Error:java: Annotation processing is not supported for module cycles.异常解决
  3. JDK8 Stream 操作
  4. 福禄电子烟遭消费者起诉:吸完不舒服 广告与说明书自相矛盾
  5. sql 上亿 查询_在文件上使用 SQL 查询的示例
  6. Atitit mq读取队列信息 范例 目录 1.1. 读取原理与主要流程 1 1.2. 范例项目 C:\0wkspc\MqDemoPrj 1 1.3. 范例代码 1 1.1.读取原理与主要流程
  7. Java编程思想阅读收获
  8. PMP-质量管理7种质量工具详细对比
  9. H5:MathJax解析数学公式
  10. DELL EqualLogic PS存储硬盘故障数据恢复
  11. 2022电大国家开放大学网上形考任务-贸易实务(山东)非免费(非答案)
  12. 资讯_计算机屏幕_镜面屏;
  13. python 沪江_Python基础篇 -- 字符串
  14. 深度之眼(十七)——Python标准库
  15. 利用反电动势的过零点来测转子位置在讨论无转子位置
  16. c语言*p和**p,c语言分析(*p)++和*p++的不同含义
  17. 人力资源管理平台数据库
  18. python实现自动化抢微信红包功能_【Python】用Python实现微信自动化抢红包,再也不用担心抢不到红包了...
  19. 联邦威力 JavaScript Netscape
  20. 静态HTML网页设计作品:订餐系统网站设计——绿色的网上订餐系统(23个页面) 网页作品 订餐系统网页设计作业模板 学生网页制作源代码下载

热门文章

  1. 数字孪生场景、代码即开即用 | 图观引擎 超详细功能范例演示
  2. mysql清空数据库所有表的命令_mysql清空表数据命令是什么?_数据库,mysql,清空表数据...
  3. 简单几步骤查看天猫国际同行大量商品的发布、下架时间
  4. win2003服务器360修复漏洞打不开网页,WIN2003服务器出现HookPort 服务启动失败的解决办法!...
  5. SVN 使用和问题汇总
  6. 前端面试CSS自检(下)页面布局、定位与浮动和场景应用(先看问题 自己自述一遍 不会再看答案 )
  7. c语言格式化字符串,C语言格式化输出小结
  8. js学习(三)--同样灵活的函数、类
  9. js slice 假分页
  10. vnc远程屏幕大小设置