公众号开发(三)----接收事件推送之关注/取消关注事件

版权声明:本文为博主原创文章,未经博主允许不得转载。 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);
			}
			
		}
	}
}

猜你喜欢

转载自blog.csdn.net/w_t_y_y/article/details/86647059