zoukankan      html  css  js  c++  java
  • Java微信公众平台开发之消息管理

    一定要先看下官方文档

    微信消息管理分为接收普通消息、接收事件推送、发送消息(被动回复)、客服消息、群发消息、模板消息这几部分

    一、接收普通消息

    当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。

    关于MsgId,官方给出解释,相当于每个消息ID,关于重试的消息排重,推荐使用msgid排重。微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。

    比如文本消息的Xml示例

    <xml>
     <ToUserName><![CDATA[toUser]]></ToUserName>
     <FromUserName><![CDATA[fromUser]]></FromUserName>
     <CreateTime>1348831860</CreateTime>
     <MsgType><![CDATA[text]]></MsgType>
     <Content><![CDATA[this is a test]]></Content>
     <MsgId>1234567890123456</MsgId>
     </xml>
    其他的消息去官方文档查看,简单封装如下

    消息抽象基类AbstractMsg.java

    package com.phil.wechat.msg.model.req;
    
    import java.io.Serializable;
    
    /**
     * 基础消息类
     * 
     * @author phil
     * 
     */
    public abstract class AbstractMsg implements Serializable {
    	
    	private static final long serialVersionUID = -6244277633057415731L;
    	private String ToUserName; // 开发者微信号
    	private String FromUserName; // 发送方帐号(一个OpenID)
    	private String MsgType = SetMsgType(); // 消息类型 例如 /text/image
    	private long CreateTime; // 消息创建时间 (整型)
    	private long MsgId; // 消息id,64位整型
    	/**
    	 * 消息类型
    	 * 
    	 * @return
    	 */
    	public abstract String SetMsgType();
    }

    文本消息TextMsg.java

    package com.phil.wechat.msg.model.req;
    
    /**
     * 文本消息
     * @author phil
     * @date  2017年6月30日
     *
     */
    public class TextMsg extends AbstractMsg {
    
    	private static final long serialVersionUID = -1764016801417503409L;
    	private String Content; // 文本消息
    	@Override
    	public String SetMsgType() {
    		return "text";
    	}
    }

    其他的依样画葫芦......

    二、被动回复用户消息

    微信服务器在将用户的消息发给公众号的开发者服务器地址(开发者中心处配置)后,微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次,如果在调试中,发现用户无法收到响应的消息,可以检查是否消息处理超时。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。

    如果出现“该公众号暂时无法提供服务,请稍后再试”,原因有两个

    • 开发者在5秒内未回复任何内容
    • 开发者回复了异常数据
    比如回复的文本消息Xml示例
    <xml>
    <ToUserName><![CDATA[toUser]]></ToUserName>
    <FromUserName><![CDATA[fromUser]]></FromUserName>
    <CreateTime>12345678</CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[你好]]></Content>
    </xml>
    简单封装下
    回复消息抽象基类RespAbstractMsg.java
    package com.phil.wechat.msg.model.resp;
    
    import java.io.Serializable;
    
    /**
     * 消息基类(公众帐号 -> 普通用户)
     * 
     * @author phil
     *
     */
    public abstract class RespAbstractMsg{
    	// 接收方帐号(收到的OpenID)
    	private String ToUserName;
    	// 开发者微信号
    	private String FromUserName;
    	// 消息创建时间 (整型)
    	private long CreateTime;
    	// 消息类型(text/music/news)
    	private String MsgType = setMsgType(); // 消息类型
    	public abstract String setMsgType();
    }
    回复文本消息RespTextMsg.java
    package com.phil.wechat.msg.model.resp;
    
    /**
     * 回复图片消息
     * 
     * @author phil
     * @data 2017年3月26日
     *
     */
    public class RespImageMsg extends RespAbstractMsg {
    	private Image Image;
    	@Override
    	public String setMsgType() {
    		return "image";
    	}
    
    	/**
    	 * 
    	 * @author phil
    	 * @date 2017年7月19日
    	 *
    	 */
    	public class Image {
    
    		// 通过素材管理中的接口上传多媒体文件,得到的id。
    		private String MediaId;
    
    		public String getMediaId() {
    			return MediaId;
    		}
    
    		public void setMediaId(String mediaId) {
    			MediaId = mediaId;
    		}
    	}
    }
    其他消息类型依样画葫芦......

    三、消息的处理

    掌握xml解析

    package com.phil.wechat.msg.controller;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Map;
    import java.util.Objects;
    
    import org.apache.commons.lang3.StringUtils;
    import org.dom4j.DocumentException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    import com.phil.modules.config.WechatConfig;
    import com.phil.modules.util.MsgUtil;
    import com.phil.modules.util.SignatureUtil;
    import com.phil.modules.util.XmlUtil;
    import com.phil.wechat.base.controller.BaseController;
    import com.phil.wechat.base.result.WechatResult;
    import com.phil.wechat.msg.model.req.BasicMsg;
    import com.phil.wechat.msg.model.resp.RespAbstractMsg;
    import com.phil.wechat.msg.model.resp.RespNewsMsg;
    import com.phil.wechat.msg.service.WechatMsgService;
    
    /**
     * @author phil
     * @date  2017年9月19日
     *
     */
    @Controller
    @RequestMapping("/wechat")
    public class WechatMsgController extends BaseController {
    	
    	private Logger logger = LoggerFactory.getLogger(this.getClass());
    	
    	@Autowired
    	private WechatMsgService wechatMsgService;
    	
    	/**
    	 * 校验信息是否是从微信服务器发出,处理消息
    	 * @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");
    		boolean ispost = Objects.equals("POST", this.getRequest().getMethod().toUpperCase());
    		if (ispost) {
    			logger.debug("接入成功,正在处理逻辑");
    			String respXml = defaultMsgDisPose(this.getRequest().getInputStream());//processRequest(request, response);
    			if (StringUtils.isNotBlank(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);
    			}
    		}
    	}
    
    	/**
    	 * 默认处理方法
    	 * @param input
    	 * @return
    	 * @throws Exception
    	 * @throws DocumentException
    	 */
    	private String defaultMsgDisPose(InputStream inputStream) throws Exception {
    		String result = null;
    		if (inputStream != null) {
    			Map<String, String> params = XmlUtil.parseStreamToMap(inputStream);
    			if (params != null && params.size() > 0) {
    				BasicMsg msgInfo = new BasicMsg();
    				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 resultObj = coreHandler(msgInfo, params);
    				if(resultObj == null){ //
    					return null;
    				}
    				boolean success = resultObj.isSuccess();  //如果 为true,则表示返回xml文件, 直接转换即可,否则按类型
    				if (success) {
    					result = resultObj.getObject().toString();
    				} else {
    					int type = resultObj.getType(); // 这里规定 1 图文消息 否则直接转换
    					if (type == WechatResult.NEWSMSG) {
    						RespNewsMsg newsMsg = (RespNewsMsg) resultObj.getObject();
    						result = MsgUtil.newsMsgToXml(newsMsg);
    					} else {
    						RespAbstractMsg basicMsg = (RespAbstractMsg) resultObj.getObject();
    						result = MsgUtil.msgToXml(basicMsg);
    					}
    				}
    			} else {
    				result = "msg is wrong";
    			}
    		}
    		return result;
    	}
    	
    	/**
    	 * 核心处理
    	 * 
    	 * @param msg
    	 *            消息基类
    	 * @param params
    	 *            xml 解析出来的 数据
    	 * @return
    	 */
    	private WechatResult coreHandler(BasicMsg msg, Map<String, String> params) {
    		WechatResult result = null;
    		String msgType = params.get("MsgType");
    		if (StringUtils.isNotEmpty(msgType)) {
    			switch (msgType) {
    			case WechatConfig.REQ_MESSAGE_TYPE_TEXT: // 文本消息
    				result = wechatMsgService.textMsg(msg, params);
    				break;
    			case WechatConfig.REQ_MESSAGE_TYPE_IMAGE: // 图片消息
    				result = wechatMsgService.imageMsg(msg, params);
    				break;
    			case WechatConfig.REQ_MESSAGE_TYPE_LINK: // 链接消息
    				result = wechatMsgService.linkMsg(msg, params);
    				break;
    			case WechatConfig.REQ_MESSAGE_TYPE_LOCATION: // 地理位置
    				result = wechatMsgService.locationMsg(msg, params);
    				break;
    			case WechatConfig.REQ_MESSAGE_TYPE_VOICE: // 音频消息
    				result = wechatMsgService.voiceMsg(msg, params);
    				break;
    			case WechatConfig.REQ_MESSAGE_TYPE_SHORTVIDEO: // 短视频消息
    				result = wechatMsgService.shortvideo(msg, params);
    				break;
    			case WechatConfig.REQ_MESSAGE_TYPE_VIDEO: // 视频消息
    				result = wechatMsgService.videoMsg(msg, params);
    				break;
    			case WechatConfig.REQ_MESSAGE_TYPE_EVENT: // 事件消息
    				String eventType = params.get("Event"); //
    				if (eventType != null && !"".equals(eventType)) {
    					switch (eventType) {
    					case WechatConfig.EVENT_TYPE_SUBSCRIBE:
    						result = wechatMsgService.subscribe(msg, params);
    						break;
    					case WechatConfig.EVENT_TYPE_UNSUBSCRIBE:
    						result = wechatMsgService.unsubscribe(msg, params);
    						break;
    					case WechatConfig.EVENT_TYPE_SCAN:
    						result = wechatMsgService.scan(msg, params);
    						break;
    					case WechatConfig.EVENT_TYPE_LOCATION:
    						result = wechatMsgService.eventLocation(msg, params);
    						break;
    					case WechatConfig.EVENT_TYPE_CLICK:
    						result = wechatMsgService.eventClick(msg, params);
    						break;
    					case WechatConfig.EVENT_TYPE_VIEW:
    						result = wechatMsgService.eventView(msg, params);
    						break;
    					case WechatConfig.KF_CREATE_SESSION:
    						result = wechatMsgService.kfCreateSession(msg, params);
    						break;
    					case WechatConfig.KF_CLOSE_SESSION:
    						result = wechatMsgService.kfCloseSession(msg, params);
    						break;
    					case WechatConfig.KF_SWITCH_SESSION:
    						result = wechatMsgService.kfSwitchSession(msg, params);
    						break;
    					default:
    						wechatMsgService.eventDefaultReply(msg, params);
    						break;
    					}
    				}
    				break;
    			default:
    				wechatMsgService.defaultMsg(msg, params);
    			}
    		}
    		return result;
    	}
    }
    只是提供个思路,如若参考代码请 移步
    本文为Phil Jing原创文章,未经博主允许不得转载,如有问题请直接回复或者加群。
  • 相关阅读:
    【Java每日一题】20161202
    【Java每日一题】20161201
    【Java每日一题】20161130
    LeetCode刷题:Reverse Words in a String(翻转字符串中的单词)
    **公司实习生笔试总结
    C++ primer学习笔记_6_函数---函数定义、参数传递
    求职面试--复习笔记3
    求职面试--复习笔记2
    一道经典面试题,atoi函数的实现
    求职面试-算法复习系列
  • 原文地址:https://www.cnblogs.com/phil_jing/p/15615880.html
Copyright © 2011-2022 走看看