版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/w_t_y_y/article/details/86647059
接收消息,首先需要一个公网url。并在微信公众平台测试账号管理后台配置:
这个url就是自己服务器的地址(具体到某一个controller接口),Token是用于验证的,可由我们自行定义,主要作用是参与生成签名,与微信请求的签名进行比较。配置后开发者和微信服务器所有的交互都是通过这个url。至于url可以自己购买一个服务器,也可以使用其他途径把自己的代码映射成公网可以访问到的,如natapp
https://blog.csdn.net/qq_34207422/article/details/86666161,这种方法还可以本地断点调试哦。按照微信公众平台的要求,把本地端口设成80,之后映射到公网上:
如我本地的是localhost:8080/wechat/message/wechatMessage,映射后在后台配置如下:
接下来就可以写代码了:
如现在把所有扫描二维码关注的用户信息存入数据库:
1、数据库设计:
2、DTO:
消息对象封装:
package com.demo.wechat.domain;
import java.io.StringReader;
import java.util.Date;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class WechatMsg {
/**
* 发送者
*/
private String fromUserName;
/**
* 接收者
*/
private String toUserName;
/**
* 消息类型
*/
private String msgType;
/**
* 事件(消息类型为事件)
*/
private String event;
/**
* 事件Key(消息类型为事件)
*/
private String eventKey;
/**
* 消息内容(消息类型为文本)
*/
private String content;
/**
* 图文消息
*/
private NewsMessage newsMessage;
public WechatMsg(String fromUserName, String toUserName) {
this.fromUserName = fromUserName;
this.toUserName = toUserName;
}
/**
* 同构XML构造方法
*
* @param msgXml 消息体
*/
public WechatMsg(String msgXml) {
try {
HashMap<String, String> map = new HashMap<String, String>();
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(msgXml)));
Element root = doc.getDocumentElement();
NodeList nodes = root.getChildNodes();
if (nodes != null) {
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
map.put(node.getNodeName(), node.getTextContent());
}
}
this.fromUserName = map.get("FromUserName");
this.toUserName = map.get("ToUserName");
this.msgType = map.get("MsgType");
if("event".equals(this.msgType)) {
this.event = map.get("Event");
this.eventKey = map.get("EventKey");
} else if("text".equals(this.msgType)) {
this.content = map.get("Content");
} else {
// 未知消息类型
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取回复消息
* @return 消息XML
*/
public String createResponseMsg() {
if("text".equals(this.msgType)) {
return "<xml>" +
"<ToUserName><![CDATA[" + this.toUserName + "]]></ToUserName>" +
"<FromUserName><![CDATA[" + this.fromUserName + "]]></FromUserName>" +
"<CreateTime>" + (new Date()).getTime() + "</CreateTime>" +
"<MsgType><![CDATA[" + this.msgType + "]]></MsgType>" +
"<Content><![CDATA[" + this.content + "]]></Content>" +
"</xml>";
} else if("news".equals(this.msgType)) {
String contentXml = "";
contentXml += "<xml>";
contentXml += "<ToUserName><![CDATA[" + this.toUserName + "]]></ToUserName>";
contentXml += "<FromUserName><![CDATA[" + this.fromUserName + "]]></FromUserName>";
contentXml += "<CreateTime>" + (new Date()).getTime() + "</CreateTime>";
contentXml += "<MsgType><![CDATA[" + this.msgType + "]]></MsgType>";
contentXml += "<ArticleCount>"+this.newsMessage.getArticleCount()+"</ArticleCount>";
contentXml += "<Articles>";
for(Article article : this.newsMessage.getArticles()){
contentXml += "<item>";
contentXml += "<Title><![CDATA["+article.getTitle()+"]]></Title>";
contentXml += "<Description><![CDATA["+article.getDescription()+"]]></Description>";
contentXml += "<PicUrl><![CDATA["+article.getPicUrl()+"]]></PicUrl>";
contentXml += "<Url><![CDATA["+article.getUrl()+"]]></Url>";
contentXml += "</item>";
}
contentXml += "</Articles>";
contentXml += "</xml>";
return contentXml;
} else {
return null;
}
}
/**
省略get和set方法
*/
}
package com.demo.wechat.domain;
import java.util.List;
public class NewsMessage extends BaseMessage {
/**
* 图文消息个数,限制为10条以内
*/
private int articleCount;
/**
* 多条图文消息信息,默认第一个item为大图
*/
private List<Article> articles;
}
package com.demo.wechat.domain;
public class BaseMessage {
/**
* 接收方帐号(收到的OpenID)
*/
private String toUserName;
//
/**
* 开发者微信号
*/
private String fromUserName;
/**
* 消息创建时间 (整型)
*/
private long createTime;
/**
* 消息类型(text/music/news)
*/
private String msgType;
}
package com.demo.wechat.domain;
public class Article {
/**
* 图文消息名称
*/
private String title;
/**
* 图文消息描述
*/
private String description;
/**
* 图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80,限制图片链接的域名需要与开发者填写的基本资料中的Url一致
*/
private String picUrl;
/**
* 点击图文消息跳转链接
*/
private String url;
}
2、接收消息:
(1)第一步,验证消息来自于微信服务器:
/**
*
* @param request 请求
* @param response 回复
* @return 验证消息的确来自微信服务器
*/
@RequestMapping(value = "/wechatMessage", method = RequestMethod.GET)
@ResponseBody
public String getMthodHandler(HttpServletRequest request, HttpServletResponse response){
try {
// 微信加密签名
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
if (!StringUtils.isEmpty(signature) && !StringUtils.isEmpty(nonce) && !StringUtils.isEmpty(timestamp) &&
SignUtil.checkSignature(signature, timestamp, nonce)) {
return echostr;
}else{
return "fail";
}
} catch (Exception e) {
return "fail";
}
}
(2)接收消息并处理消息:
/**
* [接受消息,并处理消息]
* @param request 请求
* @param response 回复
*/
@RequestMapping(value = "/wechatMessage", method = RequestMethod.POST)
public void postMthodHandler(HttpServletRequest request, HttpServletResponse response){
try {
// 将请求、响应的编码均设置为UTF-8(防止中文乱码)
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
InputStream inputStream = request.getInputStream();
String msgXml = IOUtils.toString(inputStream, "UTF-8");
String remoteIp = null;
try {
remoteIp = WebUtil.getIP(request);
} catch (Exception e) {
System.err.println("未能获取远端ip");
}
if(null == remoteIp){
remoteIp = "";
}
// 调用核心业务类接收消息、处理消息
String respMessage = processMsg(request, msgXml, remoteIp);
// 响应消息
PrintWriter out = response.getWriter();
out.print(respMessage);
out.close();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
这里处理消息封装了单独的方法,完整的代码如下:
package com.demo.wechat.controller;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.demo.wechat.domain.WechatMsg;
import com.demo.wechat.module.WechatUser;
import com.demo.wechat.service.WechatUserService;
import com.demo.wechat.util.SignUtil;
import com.demo.wechat.util.WebUtil;
@RequestMapping("/message")
@Controller
public class MessageController {
@Autowired
private WechatUserService wechatUserService;
/**
*
* @param request 请求
* @param response 回复
* @return 验证消息的确来自微信服务器
*/
@RequestMapping(value = "/wechatMessage", method = RequestMethod.GET)
@ResponseBody
public String getMthodHandler(HttpServletRequest request, HttpServletResponse response){
try {
// 微信加密签名
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
if (!StringUtils.isEmpty(signature) && !StringUtils.isEmpty(nonce) && !StringUtils.isEmpty(timestamp) &&
SignUtil.checkSignature(signature, timestamp, nonce)) {
return echostr;
}else{
return "fail";
}
} catch (Exception e) {
return "fail";
}
}
/**
* [接受消息,并返回消息]
* @param request 请求
* @param response 回复
*/
@RequestMapping(value = "/wechatMessage", method = RequestMethod.POST)
public void postMthodHandler(HttpServletRequest request, HttpServletResponse response){
try {
// 将请求、响应的编码均设置为UTF-8(防止中文乱码)
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
InputStream inputStream = request.getInputStream();
String msgXml = IOUtils.toString(inputStream, "UTF-8");
String remoteIp = null;
try {
remoteIp = WebUtil.getIP(request);
} catch (Exception e) {
System.err.println("未能获取远端ip");
}
if(null == remoteIp){
remoteIp = "";
}
// 调用核心业务类接收消息、处理消息
String respMessage = processMsg(request, msgXml, remoteIp);
// 响应消息
PrintWriter out = response.getWriter();
out.print(respMessage);
out.close();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
/**
* @param request
* @param msgXml
* @param remoteIp
* @return result
*/
public String processMsg(HttpServletRequest request, String msgXml, String remoteIp) {
WechatMsg resqMsg = new WechatMsg(msgXml);
handleMessage(request, resqMsg, remoteIp);
if(resqMsg.getMsgType() != null)
return resqMsg.createResponseMsg();
else
return "";
}
/**
* 处理微信消息
* @param request request
* @param reqMsg 请求消息
* @param respMsg 回复消息
* @param remoteIp remoteIp
*/
private void handleMessage(HttpServletRequest request, WechatMsg reqMsg, String remoteIp){
String type = reqMsg.getMsgType();
String fromUserName = reqMsg.getFromUserName();
//关注/取消关注事件
if(type.equals("event")){
WechatUser dbWechatUser = wechatUserService.getByOpenId(fromUserName);
if(dbWechatUser == null){
//还没有关注过
System.out.println("还没有关注过");
WechatUser wechatUser = new WechatUser();
wechatUser.setCreateTime(new Date());
wechatUser.setIsDelete(false);
wechatUser.setUpdateTime(new Date());
wechatUser.setUserOpenId(fromUserName);
wechatUserService.insert(wechatUser);
}
}
}
}