微信企业号接收消息(使用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)的更多相关文章

  1. C#开发微信门户及应用(21)-微信企业号的消息和事件的接收处理及解密

    在上篇随笔<C#开发微信门户及应用(19)-微信企业号的消息发送(文本.图片.文件.语音.视频.图文消息等)>介绍了有关企业号的消息发送,官方特别声明消息是不用加密发送的.但是在回调的服务 ...

  2. C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)

    我们知道,企业号主要是面向企业需求而生的,因此内部消息的交流显得非常重要,而且发送.回复消息数量应该很可观,对于大企业尤其如此,因此可以结合企业号实现内部消息的交流.企业号具有关注安全.消息无限制等特 ...

  3. C# 微信 企业号通知消息

    每当有个Create 事件,要通知相关的人员. 1.扫码登录企业微信,到企业应用. 2.获取微信配置信息. Secret和AgentId. 3.管理通讯录,配置接收消息的人群.可以按照部门,标签.获取 ...

  4. python与shell通过微信企业号发送消息

    python与shell通过微信企业号发送信息,脚本来源于网络,做好搬运工,哈哈,相应的参考链接放在末位 shell版本: #!/bin/bash # CropID="xxxx" ...

  5. java与微信企业号交互

    微信企业号接收消息(使用SpringMVC): http://blog.csdn.net/omsvip/article/details/39480577 微信企业号api: http://qydev. ...

  6. C#开发微信门户及应用(25)-微信企业号的客户端管理功能

    我们知道,微信公众号和企业号都提供了一个官方的Web后台,方便我们对微信账号的配置,以及相关数据的管理功能,对于微信企业号来说,有通讯录中的组织架构管理.标签管理.人员管理.以及消息的发送等功能,其中 ...

  7. C#开发微信门户及应用(20)-微信企业号的菜单管理

    前面几篇陆续介绍了很多微信企业号的相关操作,企业号和公众号一样都可以自定义菜单,因此他们也可以通过API进行菜单的创建.获取列表.删除的操作,因此本篇继续探讨这个主体,介绍企业号的菜单管理操作. 菜单 ...

  8. C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理

    在上篇随笔<C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理>介绍了通讯录的部门的相关操作管理,通讯录管理包括部门管理.成员管理.标签管理三个部分,本篇主要介绍成员的管 ...

  9. C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理

    前面一篇随笔企业号的一些基础信息,以及介绍如何配置企业号的回调方式实现和企业号服务器进行沟通的桥梁.本篇主要还是继续介绍企业号的开发工作的开展,介绍微信企业号通讯录管理开发功能,介绍其中组织机构里面如 ...

随机推荐

  1. Servlet3.1规范和JSP2.3规范

    JSR 340: Java Servlet 3.1 Specification https://jcp.org/en/jsr/detail?id=340 http://files.cnblogs.co ...

  2. ESRI ArcGIS 产品线资源网站大集合

    友情提示:国外网站国内访问速度较慢,可以配合VPN等进行加速访问. 首先给出官方网站,以下所有链接均可在官方找到. http://www.esri.com 紧接着是产品线: http://www.es ...

  3. js精要之对象属性

    // 对象的应用解除 将对象变量置为null(在写插件多大型项目是不要忘记解除对象占用) var object1 = new Object(); var object2 = object1; // 对 ...

  4. css3 3d初入门(一)

    css3 3D.html div.oembedall-githubrepos { border: 1px solid #DDD; list-style-type: none; margin: 0 0 ...

  5. 无限二等分[0,1]这个区间之后还剩下啥?what's left after dividing an unit interval [0,1] infinitely many times?

    Dividing an unit interval \([0,1]\) into two equal subintervals by the midpoint \(\dfrac {0+1} {2}=\ ...

  6. IOS9.0 之后友盟分享详细过程

    一: 申请友盟的AppKey(友盟的Key是根据应用的名称生成的!) 在友盟注册了你自己的开发者账号后就可以申请AppKey了.然后在这个方法里面设置Key - (BOOL)application:( ...

  7. 初学bootstrap ---栅格系统

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Jquery AutoComplete实现搜索自动完成

    AutoComplete控件就是指用户在文本框输入前几个字母或是汉字的时候,该控件就能从存放数据的文本或是数据库里将所有以这些字母开头的数据提示给用户,供用户选择,提供方便. 例子: <!doc ...

  9. Angular2 + Webpack项目搭建Demo

    本文将从头开始编写实际的代码来完成一个angular2的demo. 题外话是其实angular2官网的快速开始项目已经很酷炫了,但其侧重快速二字,只够拿来练习玩耍,倒是github上确实已经有了一些不 ...

  10. Qt 地址薄 (一) 界面设计

    实现一个简单的地址薄,功能包括:地址的添加.浏览.编辑.查找.输出文件等. 1  界面和元素 整个地址薄界面,可视为一个 AddressBook 类.其中的 Name.Address 以及两个编辑栏, ...