微信公众号开发-消息事件接收处理

对用户的消息及事件作出处理

首先在公众号后台设置开发者后需要是指一个消息的返回地址
我这里设置的接口地址是: /wxpublic/verify_wx_token
如下图:

bp_wx_wxmanage是我的项目名称,我这里热部署在tomcat上的,所以配置完成以后微信就会发送消息到/wxpublic/verify_wx_token接口,在此Controller里处理数据即可。

首先需要做一次token的接口验证

这里微信需要一个可外界访问的接口,本地测试的话你可以下载一个花生壳操作一哈,配置上微信的白名单就可以进行测试了。
做token验证时也是访问的上诉接口,是以get方式请求的,而发送事件消息是post消息,因此可以进行区分:

@RequestMapping("/wxpublic/verify_wx_token")
	@ResponseBody
	public void verifyWXToken(HttpServletRequest request, HttpServletResponse response)
			throws AesException, IOException {
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");
		boolean isGet = request.getMethod().toLowerCase().equals("get");
		PrintWriter out = response.getWriter();
		try {
			if (isGet) {
				String msgSignature = request.getParameter("signature");
				String msgTimestamp = request.getParameter("timestamp");

				String msgNonce = request.getParameter("nonce");
				String echostr = request.getParameter("echostr");

				if (WXPublicUtils.verifyUrl(msgSignature, msgTimestamp, msgNonce)) {
					logger.info("验证完毕返回");
					try {
						response.getWriter().write(echostr);
					} catch (IOException e) {
						logger.error("验证失败= {}", e.getMessage());
					}
				}
			} else {
				String respMessage = "异常消息!";
				try {
					respMessage = weiXinPostService.weixinPost(request);
					if (respMessage != null)
						out.print(respMessage);
					logger.info("The request completed successfully");
					logger.info("to weixin server " + respMessage);
				} catch (Exception e) {
					logger.error("Failed to convert the message from weixin! {}", e.getMessage());
				}
			}
		} catch (Exception e) {
			logger.error("Connect the weixin server is error. e.errorMsg={}", e.getMessage());
		} finally {
			out.close();
			out = null;
		}
	}

在这里我区分了get和post,get用来验证
这里自定义了一个异常处理:AesException

public class AesException extends Exception{
	 public final static int OK = 0;
	    public final static int ValidateSignatureError = -40001;
	    public final static int ParseXmlError = -40002;
	    public final static int ComputeSignatureError = -40003;
	    public final static int IllegalAesKey = -40004;
	    public final static int ValidateAppidError = -40005;
	    public final static int EncryptAESError = -40006;
	    public final static int DecryptAESError = -40007;
	    public final static int IllegalBuffer = -40008;
	    public final static int EncodeBase64Error = -40009;
	    public final static int DecodeBase64Error = -40010;
	    public final static int GenReturnXmlError = -40011;

	    private int code;

	    private static String getMessage(int code) {
	        switch (code) {
	        case ValidateSignatureError:
	            return "签名验证错误";
	        case ParseXmlError:
	            return "xml解析失败";
	        case ComputeSignatureError:
	            return "sha加密生成签名失败";
	        case IllegalAesKey:
	            return "SymmetricKey非法";
	        case ValidateAppidError:
	            return "appid校验失败";
	        case EncryptAESError:
	            return "aes加密失败";
	        case DecryptAESError:
	            return "aes解密失败";
	        case IllegalBuffer:
	            return "解密后得到的buffer非法";
	        case EncodeBase64Error:
	            return "base64加密错误";
	        case DecodeBase64Error:
	            return "base64解密错误";
	        case GenReturnXmlError:
	            return "xml生成失败";
	        default:
	            return null;
	        }
	    }

	    public int getCode() {
	        return code;
	    }

	    public AesException(int code) {
	        super(getMessage(code));
	        this.code = code;
	    }
}

WXPublicUtils.verifyUrl返回了验证结果
WXPublicUtils工具类代码如下:

public class WXPublicUtils {
	/**
	 * 验证Token
	 * 
	 * @param msgSignature
	 *            签名串,对应URL参数的signature
	 * @param timeStamp
	 *            时间戳,对应URL参数的timestamp
	 * @param nonce
	 *            随机串,对应URL参数的nonce
	 *
	 * @return 是否为安全签名
	 * @throws AesException
	 *             执行失败,请查看该异常的错误码和具体的错误信息
	 */
	public static boolean verifyUrl(String msgSignature, String timeStamp, String nonce) throws AesException {
		// 这里的 WXPublicConstants.TOKEN 填写你自己设置的Token就可以了
		String signature = SHA1.getSHA1("wxtoken", timeStamp, nonce);
		if (!signature.equals(msgSignature)) {
			throw new AesException(AesException.ValidateSignatureError);
		}
		return true;
	}
}

SHA1.getSHA1(“wxtoken”, timeStamp, nonce);中的wxtoken就是在微信后台的配置自己设置的
在这里插入图片描述
使用SHA1算法验证Token:

public class SHA1 {
	/**
	 * 用SHA1算法验证Token
	 *
	 * @param token
	 *            票据
	 * @param timestamp
	 *            时间戳
	 * @param nonce
	 *            随机字符串
	 * @return 安全签名
	 * @throws AesException
	 */
	public static String getSHA1(String token, String timestamp, String nonce) throws AesException {
		try {
			String[] array = new String[] { token, timestamp, nonce };
			StringBuffer sb = new StringBuffer();
			// 字符串排序
			Arrays.sort(array);
			for (int i = 0; i < 3; i++) {
				sb.append(array[i]);
			}
			String str = sb.toString();
			// SHA1签名生成
			MessageDigest md = MessageDigest.getInstance("SHA-1");
			md.update(str.getBytes());
			byte[] digest = md.digest();

			StringBuffer hexstr = new StringBuffer();
			String shaHex = "";
			for (int i = 0; i < digest.length; i++) {
				shaHex = Integer.toHexString(digest[i] & 0xFF);
				if (shaHex.length() < 2) {
					hexstr.append(0);
				}
				hexstr.append(shaHex);
			}
			return hexstr.toString();
		} catch (Exception e) {
			e.printStackTrace();
			throw new AesException(AesException.ComputeSignatureError);
		}
	}
}

接下来对用户的时间进行处理Post消息接收

上诉的weiXinPostService.weixinPost(request);用于处理请求

这里需要使用xml处理一下请求
Xml的工具类提供一哈,顺便规定了一哈处理的事件类型

public class MessageUtil {
	/**
	 * 返回消息类型:文本
	 */
	public static final String RESP_MESSAGE_TYPE_TEXT = "text";

	/**
	 * 返回消息类型:音乐
	 */
	public static final String RESP_MESSAGE_TYPE_MUSIC = "music";

	/**
	 * 返回消息类型:图文
	 */
	public static final String RESP_MESSAGE_TYPE_NEWS = "news";

	/**
	 * 请求消息类型:文本
	 */
	public static final String REQ_MESSAGE_TYPE_TEXT = "text";

	/**
	 * 请求消息类型:图片
	 */
	public static final String REQ_MESSAGE_TYPE_IMAGE = "image";

	/**
	 * 请求消息类型:链接
	 */
	public static final String REQ_MESSAGE_TYPE_LINK = "link";

	/**
	 * 请求消息类型:地理位置
	 */
	public static final String REQ_MESSAGE_TYPE_LOCATION = "LOCATION";

	/**
	 * 请求消息类型:音频
	 */
	public static final String REQ_MESSAGE_TYPE_VOICE = "voice";

	/**
	 * 请求消息类型:视频
	 */
	public static final String REQ_MESSAGE_TYPE_VIDEO = "video";

	/**
	 * 请求消息类型:推送
	 */
	public static final String REQ_MESSAGE_TYPE_EVENT = "event";

	/**
	 * 事件类型:subscribe(订阅)
	 */
	public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";

	/**
	 * 事件类型:unsubscribe(取消订阅)
	 */
	public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";

	/**
	 * 事件类型:CLICK(自定义菜单点击事件)
	 */
	public static final String EVENT_TYPE_CLICK = "CLICK";

	/**
	 * xml转换为map
	 * 
	 * @param request
	 * @return
	 * @throws IOException
	 */

	public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException {
		Map<String, String> map = new HashMap<String, String>();
		SAXReader reader = new SAXReader();
		InputStream ins = null;
		try {
			ins = request.getInputStream();
			Document doc = reader.read(ins);
			Element root = doc.getRootElement();
			@SuppressWarnings("unchecked")
			List<Element> list = root.elements();
			for (Element e : list) {
				map.put(e.getName(), e.getText());
			}

			return map;
		} catch (DocumentException e1) {
			e1.printStackTrace();
		} finally {
			ins.close();
		}

		return null;
	}

	/**
	 * 文本消息对象转换成xml
	 * 
	 * @param textMessage
	 *            文本消息对象
	 * @return xml
	 */
	public static String textMessageToXml(Object textMessage) {
		XStream xstream = new XStream();
		xstream.alias("xml", textMessage.getClass());
		return xstream.toXML(textMessage);
	}

	// 图文消息转化为XML   
	public static String newsMessageToXml(Object newsMessage) {
		XStream xstream = new XStream();
	xstream.alias("xml", newsMessage.getClass());
	xstream.alias("item", new News().getClass());
	return xstream.toXML(newsMessage);
	}

	public static void main(String[] args) {
		VoiceMessage voiceMessage=new VoiceMessage();
		voiceMessage.setToUserName("aaaa");
		voiceMessage.setFromUserName("bbbb");
		voiceMessage.setCreateTime(new Date().getTime());
		voiceMessage.setMsgType("voice");
		Voice voice=new Voice();
		voice.setMediaId("llllllllllllllllll");
		voiceMessage.setVoice(voice);
		String textMessageToXml = textMessageToXml(voiceMessage);
		System.out.println(textMessageToXml);
	}

}
接下来开始处理事件
/**
	 * 处理微信发来的请求
	 * 
	 * @param request
	 * @return
	 */
	public String weixinPost(HttpServletRequest request) {

		String respMessage = null;
		try {

			// xml请求解析
			Map<String, String> requestMap = MessageUtil.xmlToMap(request);
			
			LOGGER.info(requestMap.toString());
			// 发送方帐号(open_id)
			String fromUserName = requestMap.get("FromUserName");
			// 公众帐号
			String toUserName = requestMap.get("ToUserName");
			// 消息类型
			String msgType = requestMap.get("MsgType");
			// 消息内容
			String content = requestMap.get("Content");

			LOGGER.info("FromUserName is:" + fromUserName + ", ToUserName is:" + toUserName + ", MsgType is:" + msgType);
			
			TextMessage text = new TextMessage();//这里我规定给用户反馈的文本

			// 文本消息
			if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
				
			}
			/*
			 * else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {//
			 * 事件推送 String eventType = requestMap.get("Event");// 事件类型
			 * 
			 * if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {// 订阅
			 * respContent = "欢迎关注xxx公众号!"; return
			 * MessageResponse.getTextMessage(fromUserName , toUserName ,
			 * respContent); } else if
			 * (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {// 自定义菜单点击事件
			 * String eventKey = requestMap.get("EventKey");//
			 * 事件KEY值,与创建自定义菜单时指定的KEY值对应 logger.info("eventKey is:" +eventKey);
			 * return xxx; } } //开启微信声音识别测试 2015-3-30 else
			 * if(msgType.equals("voice")) { String recvMessage =
			 * requestMap.get("Recognition"); //respContent =
			 * "收到的语音解析结果:"+recvMessage; if(recvMessage!=null){ respContent =
			 * TulingApiProcess.getTulingResult(recvMessage); }else{ respContent
			 * = "您说的太模糊了,能不能重新说下呢?"; } return
			 * MessageResponse.getTextMessage(fromUserName , toUserName ,
			 * respContent); } //拍照功能 else if(msgType.equals("pic_sysphoto")) {
			 * 
			 * } else { return MessageResponse.getTextMessage(fromUserName ,
			 * toUserName , "返回为空"); }
			 */
			// 事件推送
			else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
				String eventType = requestMap.get("Event");// 事件类型
				
				if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {// 订阅
					
				else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {// 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息
					
				}

				else if (eventType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {// 获取地址
					
				}

				// 自定义菜单点击事件
				else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {// 点击类型为Click的按
					respMessage = MessageUtil.textMessageToXml(text);
				}
				/*其他事件继续else if添加就好了*/
				
			}
		} catch (Exception e) {
			LOGGER.error("error......{}", e.getMessage());
		}
		return respMessage;
	}

规定一个给用户反馈的对象的基础类

public class BaseMessage {
	// 开发者微信号  
    private String ToUserName;  
    // 发送方帐号(一个OpenID)  
    private String FromUserName;  
    // 消息创建时间 (整型)  
    private Long CreateTime;  
    // 消息类型(text/image/location/link)  
    private String MsgType;  
    // 消息id,64位整型  
    private Long MsgId;
    /**
     * 位0x0001被标志时,星标刚收到的消息
     */
    private Integer FuncFlag;
	public String getToUserName() {
		return ToUserName;
	}
	public void setToUserName(String toUserName) {
		ToUserName = toUserName;
	}
	public String getFromUserName() {
		return FromUserName;
	}
	public void setFromUserName(String fromUserName) {
		FromUserName = fromUserName;
	}
	public Long getCreateTime() {
		return CreateTime;
	}
	public void setCreateTime(Long createTime) {
		CreateTime = createTime;
	}
	public String getMsgType() {
		return MsgType;
	}
	public void setMsgType(String msgType) {
		MsgType = msgType;
	}
	public Long getMsgId() {
		return MsgId;
	}
	public void setMsgId(Long msgId) {
		MsgId = msgId;
	}
	public Integer getFuncFlag() {
		return FuncFlag;
	}
	public void setFuncFlag(Integer funcFlag) {
		FuncFlag = funcFlag;
	}
}

我这里给用户返回的text为文本,最后都需要转成Xml,使用MessageUtil.textMessageToXml(text);

public class TextMessage extends BaseMessage {
	 // 消息内容
    private String Content;
    
	public String getContent() {
        return Content;
    }
    public void setContent(String content) {
        Content = content;
    }
}

微信公众号的事件处理业务到这里差不多结束了,其他的可自行补充。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值