微信企业号接收消息(使用SpringMVC)
微信企业号接收消息(使用SpringMVC)
微信企业号接收消息(使用SpringMVC)
将应用设置在回调模式时,企业可以通过回调URL接收员工回复的消息,以及员工关注、点击菜单、上报地理位置等事件。
在接收到事件后,企业可以发送被动响应消息,实现员工与企业的互动。
注意,企业在接收消息,以及发送被动响应消息时,消息体都以AES方式加密,以保证传输的安全。
接收普通消息
普通消息是指员工向企业号应用发送的消息,包括文本、图片、语音、视频、地理位置等类型。
接收事件
事件是指员工在企业号上的某些操作行为,比如关注、上报地理位置、点击菜单等。(关注事件请参考’关注与取消关注’)
被动响应消息
以上文档必须仔细阅读,
消息处理流程大致如下,比较简陋!
具体实现如下:
在文章 微信企业号接入(使用SpringMVC)的基础上实现!
在消息回复处理中添加自己的业务,对于关注事件和取消关注事件如有需要加入即可!
对于xml的处理有多种方式,大家可以任选一种!
此处需要说明的是腾讯的文档必须要完完整整的看,有些看文档就有答案的!
package org.oms.qiye.web; import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.oms.qiye.aes.AesException;
import org.oms.qiye.aes.WXBizMsgCrypt;
import org.oms.qiye.service.CoreService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.apache.commons.io.IOUtils;
/**
* 注解方式打开链接
*
* @author Sunlight
*
*/
@Controller
public class CoreController {
private String token = "sunlight";
private String encodingAESKey = "s8vFF4f6AWay3uAdJh79WD6imaam4BV6Kl4eL4UzgfM";
private String corpId = "此处修改为你的企业ID"; @RequestMapping(value = { "/coreJoin.do" }, method = RequestMethod.GET)
public void coreJoinGet(HttpServletRequest request,
HttpServletResponse response) throws IOException {
// 微信加密签名
String msg_signature = request.getParameter("msg_signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr"); System.out.println("request=" + request.getRequestURL()); PrintWriter out = response.getWriter();
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
String result = null;
try {
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey,
corpId);
result = wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr);
} catch (AesException e) {
e.printStackTrace();
}
if (result == null) {
result = token;
}
out.print(result);
out.close();
out = null;
} @RequestMapping(value = { "/coreJoin.do" }, method = RequestMethod.POST)
public void coreJoinPost(HttpServletRequest request,
HttpServletResponse response) throws IOException {
// 将请求、响应的编码均设置为UTF-8(防止中文乱码)
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8"); // 微信加密签名
String msg_signature = request.getParameter("msg_signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce"); //从请求中读取整个post数据
InputStream inputStream = request.getInputStream();
String postData = IOUtils.toString(inputStream, "UTF-8");
System.out.println(postData); String msg = "";
WXBizMsgCrypt wxcpt = null;
try {
wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId);
//解密消息
msg = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, postData);
} catch (AesException e) {
e.printStackTrace();
}
System.out.println("msg=" + msg); // 调用核心业务类接收消息、处理消息
String respMessage = CoreService.processRequest(msg);
System.out.println("respMessage=" + respMessage); String encryptMsg = "";
try {
//加密回复消息
encryptMsg = wxcpt.EncryptMsg(respMessage, timestamp, nonce);
} catch (AesException e) {
e.printStackTrace();
} // 响应消息
PrintWriter out = response.getWriter();
out.print(encryptMsg);
out.close(); } }
CoreService类:
package org.oms.qiye.service; import java.util.Date;
import java.util.Map; import org.oms.qiye.pojo.resp.TextMessage;
import org.oms.qiye.util.MessageUtil; /**
* 处理微信发来的信息
* @author Sunlight
*
*/
public class CoreService { public static String processRequest(String msg) {
String respMessage = null;
try {
// 默认返回的文本消息内容
String respContent = "请求处理异常,请稍候尝试!"; // xml请求解析
Map<String, String> requestMap = MessageUtil.parseXml(msg); System.out.println("Event=="+requestMap.get("Event")); // 发送方帐号(open_id)
String fromUserName = requestMap.get("FromUserName");
// 公众帐号
String toUserName = requestMap.get("ToUserName");
// 消息类型
String msgType = requestMap.get("MsgType"); // 回复文本消息
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
textMessage.setFuncFlag(0); // 文本消息
if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
String content = requestMap.get("Content");
respContent = "Sunlight提示:您发送的是文本消息!内容是:"+content;
}
// 图片消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
respContent = "Sunlight提示:您发送的是图片消息!";
}
// 地理位置消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {
respContent = "Sunlight提示:您发送的是地理位置消息!";
}
// 链接消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {
respContent = "Sunlight提示:您发送的是链接消息!";
}
// 音频消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
respContent = "Sunlight提示:您发送的是音频消息!";
}
// 事件推送
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
// 事件类型
String eventType = requestMap.get("Event");
// 自定义菜单点击事件
if (eventType.equalsIgnoreCase(MessageUtil.EVENT_TYPE_CLICK)) {
// 事件KEY值,与创建自定义菜单时指定的KEY值对应
String eventKey = requestMap.get("EventKey");
System.out.println("EventKey="+eventKey);
respContent = "Sunlight提示:您点击的菜单KEY是"+eventKey;
}
} textMessage.setContent(respContent);
respMessage = MessageUtil.textMessageToXml(textMessage);
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
respMessage="有异常了。。。";
}
return respMessage;
} }
MessageUtil类需要修改一下,此类使用了 柳峰 大神写的:
package org.oms.qiye.util; import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.oms.qiye.pojo.resp.Article;
import org.oms.qiye.pojo.resp.MusicMessage;
import org.oms.qiye.pojo.resp.NewsMessage;
import org.oms.qiye.pojo.resp.TextMessage; import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver; /**
* 消息工具类
*
* @author sunlight
*
*/
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_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)
*
* @param request
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static Map<String, String> parseXml(String msg)
throws Exception {
// 将解析结果存储在HashMap中
Map<String, String> map = new HashMap<String, String>(); // 从request中取得输入流
InputStream inputStream = new ByteArrayInputStream(msg.getBytes("UTF-8")); // 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List<Element> elementList = root.elements(); // 遍历所有子节点
for (Element e : elementList)
map.put(e.getName(), e.getText()); // 释放资源
inputStream.close();
inputStream = null; return map;
} /**
* 文本消息对象转换成xml
*
* @param textMessage
* 文本消息对象
* @return xml
*/
public static String textMessageToXml(TextMessage textMessage) {
xstream.alias("xml", textMessage.getClass());
return xstream.toXML(textMessage);
} /**
* 音乐消息对象转换成xml
*
* @param musicMessage
* 音乐消息对象
* @return xml
*/
public static String musicMessageToXml(MusicMessage musicMessage) {
xstream.alias("xml", musicMessage.getClass());
return xstream.toXML(musicMessage);
} /**
* 图文消息对象转换成xml
*
* @param newsMessage
* 图文消息对象
* @return xml
*/
public static String newsMessageToXml(NewsMessage newsMessage) {
xstream.alias("xml", newsMessage.getClass());
xstream.alias("item", new Article().getClass());
return xstream.toXML(newsMessage);
} /**
* 扩展xstream,使其支持CDATA块
*
* @date 2013-05-19
*/
private static XStream xstream = new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata = true; @Override
@SuppressWarnings("rawtypes")
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
} @Override
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
}
项目结构图:
此处消息类的封装可以使用公众号的,此处不在列出!
测试结果:
微信企业号接收消息(使用SpringMVC)的更多相关文章
- C#开发微信门户及应用(21)-微信企业号的消息和事件的接收处理及解密
在上篇随笔<C#开发微信门户及应用(19)-微信企业号的消息发送(文本.图片.文件.语音.视频.图文消息等)>介绍了有关企业号的消息发送,官方特别声明消息是不用加密发送的.但是在回调的服务 ...
- C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)
我们知道,企业号主要是面向企业需求而生的,因此内部消息的交流显得非常重要,而且发送.回复消息数量应该很可观,对于大企业尤其如此,因此可以结合企业号实现内部消息的交流.企业号具有关注安全.消息无限制等特 ...
- C# 微信 企业号通知消息
每当有个Create 事件,要通知相关的人员. 1.扫码登录企业微信,到企业应用. 2.获取微信配置信息. Secret和AgentId. 3.管理通讯录,配置接收消息的人群.可以按照部门,标签.获取 ...
- python与shell通过微信企业号发送消息
python与shell通过微信企业号发送信息,脚本来源于网络,做好搬运工,哈哈,相应的参考链接放在末位 shell版本: #!/bin/bash # CropID="xxxx" ...
- java与微信企业号交互
微信企业号接收消息(使用SpringMVC): http://blog.csdn.net/omsvip/article/details/39480577 微信企业号api: http://qydev. ...
- C#开发微信门户及应用(25)-微信企业号的客户端管理功能
我们知道,微信公众号和企业号都提供了一个官方的Web后台,方便我们对微信账号的配置,以及相关数据的管理功能,对于微信企业号来说,有通讯录中的组织架构管理.标签管理.人员管理.以及消息的发送等功能,其中 ...
- C#开发微信门户及应用(20)-微信企业号的菜单管理
前面几篇陆续介绍了很多微信企业号的相关操作,企业号和公众号一样都可以自定义菜单,因此他们也可以通过API进行菜单的创建.获取列表.删除的操作,因此本篇继续探讨这个主体,介绍企业号的菜单管理操作. 菜单 ...
- C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理
在上篇随笔<C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理>介绍了通讯录的部门的相关操作管理,通讯录管理包括部门管理.成员管理.标签管理三个部分,本篇主要介绍成员的管 ...
- C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理
前面一篇随笔企业号的一些基础信息,以及介绍如何配置企业号的回调方式实现和企业号服务器进行沟通的桥梁.本篇主要还是继续介绍企业号的开发工作的开展,介绍微信企业号通讯录管理开发功能,介绍其中组织机构里面如 ...
随机推荐
- java调用webservice
http://www.cnblogs.com/sun_moon_earth/archive/2009/02/03/1383308.html http://www.cnblogs.com/siqi/ar ...
- 负载均衡软件LVS分析三(配置)
LVS集群有DR.TUN.NAT三种配置模式,可以对www服务.FTP服务.MAIL服务等做负载均衡,下面通过搭建www服务的负载均衡实例,讲述基于DR模式的LVS集群配置. 一. Director ...
- Mybatis拦截器实现分页
本文介绍使用Mybatis拦截器,实现分页:并且在dao层,直接返回自定义的分页对象. 最终dao层结果: public interface ModelMapper { Page<Model&g ...
- 【蒙地卡罗法求PI】
/* 蒙地卡罗法求PI 说明 蒙地卡罗为摩洛哥王国之首都,该国位于法国与义大利国境,以赌博闻名.蒙地卡罗的基本原理为以乱数配合面积公式来进行解题,这种以机 率来解题的方式带有赌博的意味,虽然在精确度上 ...
- MyBatis 源码分析——动态代理
MyBatis框架是如何去执行SQL语句?相信不只是你们,笔者也想要知道是如何进行的.相信有上一章的引导大家都知道SqlSession接口的作用.当然默认情况下还是使用DefaultSqlSessio ...
- list、set、map以及array的区别
对于刚刚学习集合框架来说,如何选择list.set.map以及array是比较模糊的 在此我将对这四种情况做总结: array:数组,可以存储对象和基本数据类型,长度固定. Collection:集合 ...
- DOM范围
前面的话 为了让开发人员更方便地控制页面,DOM定义了“范围”(range)接口.通过范围可以选择文档中的一个区域,而不必考虑节点的界限(选择在后台完成,对用户是不可见的).在常规的DOM操作不能更有 ...
- .NET Core在WindowsServer服务器部署及发布
VS使用WEB DEPLOY发布.NET Core程序 背景是这样的,公司有两台服务器,平时一台备用,另一台做为主生产机器.当有大量补丁或者安装什么东西需要重启的时候,交其中一台直接关掉IIS,然 ...
- PLSQL触发器
触发器权限 数据库创建用户时想要在本用户下使用触发器,需要给用户触发器的权限 使用DBA用户执行 GRANT CREATE TRIGGER TO user_name; 如果想在当前用户下创建其他用户 ...
- OpenGL理解
说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640*480分辨率.16色 ...