微信公众号开发:获取用户发送消息并实现回复(Java)

时间:2024-02-16 08:46:08

在上一篇文章写了如何配置服务器:

https://blog.csdn.net/qq_36313726/article/details/81027366

今天我就给大家说下如何获取用户发送消息并实现回复,自己在弄这个过程走了许多坑。

要实现消息获取和自动回复,需要了解微信是怎么实现这个过程:

我从微信官方文档摘取了下面比较重要的信息

接收普通消息

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。

文本消息在请求的输出流中,而不是参数位置,参数是对xml中标签的解释。

文本消息

<xml>  
<ToUserName>< ![CDATA[toUser] ]></ToUserName>  
<FromUserName>< ![CDATA[fromUser] ]></FromUserName>  <CreateTime>1348831860</CreateTime>  
<MsgType>< ![CDATA[text] ]></MsgType>  
<Content>< ![CDATA[this is a test] ]></Content>  
<MsgId>1234567890123456</MsgId>  
</xml>
 

  

参数描述
ToUserName 开发者微信号
FromUserName 发送方帐号(一个OpenID)
CreateTime 消息创建时间 (整型)
MsgType text
Content 文本消息内容
MsgId 消息id,64位整型

被动回复用户消息

当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。

 

回复文本消息

<xml> <ToUserName>< ![CDATA[toUser] ]></ToUserName> 
<FromUserName>< ![CDATA[fromUser] ]></FromUserName> <CreateTime>12345678</CreateTime> 
<MsgType>< ![CDATA[text] ]></MsgType> 
<Content>< ![CDATA[你好] ]></Content> 
</xml>

  

参数是否必须描述
ToUserName 接收方帐号(收到的OpenID)
FromUserName 开发者微信号
CreateTime 消息创建时间 (整型)
MsgType text
Content 回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示)

 

在网上看到这张图片很好理解

 

微信公众号开发文档说了,只有对服务器进行验证的时候才会使用到get请求到服务器的url中,其它一律使用post请求。

因此用户发送消息时,微信服务器是通过post请求到我们的服务器上。

可以看下我写的代码来理解这个过程,这个代码有部分利用上一篇文章说过的步骤:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.SHA1;

/**
 * Servlet implementation class test
 */
@WebServlet("/test")
public class test extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		String token = "jylife";
		String jiami = "";
		String openid=request.getParameter("openid");
		String body=request.getParameter("body");
		System.out.println(body);
		Date date=new Date();
        try {
            jiami=SHA1.getSHA1(token, timestamp, nonce,"");//这里是对三个参数进行加密
       } catch (AesException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }
        System.out.println("加密"+jiami);
        System.out.println("本身"+signature);
           PrintWriter out=response.getWriter();
           if(jiami.equals(signature))
           out.print(echostr);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        //获取服务器发送过来的信息,因为不是参数,得用输入流读取
		BufferedReader reader = null;
        StringBuilder sb = new StringBuilder();
        try{
            reader = new BufferedReader(new InputStreamReader(request.getInputStream(), "utf-8"));
            String line = null;
            while ((line = reader.readLine()) != null){
                sb.append(line);
            }
        } catch (IOException e){
            e.printStackTrace();
        } finally {
            try{
                if (null != reader){ reader.close();}
            } catch (IOException e){
            	e.printStackTrace();
            }
        }
        System.out.println("用户发送过来信息:"+sb);//将用户发送得消息打印出来
        /*	可以request看出所有的参数信息
         * 	Enumeration enu=request.getParameterNames();  
			while(enu.hasMoreElements()){  
			String paraName=(String)enu.nextElement();  
			System.out.println(paraName+": "+request.getParameter(paraName));  
			}
         */
		String openid=request.getParameter("openid");//获取参数中的openid
		PrintWriter out=response.getWriter();
			String replyMsg = "<xml>"
					+ "<ToUserName><![CDATA["+openid+"]]></ToUserName>"//回复用户时,这里是用户的openid;但用户发送过来消息这里是微信公众号的原始id
					+ "<FromUserName><![CDATA["+"这里微信公众号的原始id"+"]]></FromUserName>"//这里填写微信公众号 的原始id;用户发送过来时这里是用户的openid
					+ "<CreateTime>1531553112194</CreateTime>"//这里可以填创建信息的时间,目前测试随便填也可以
					+ "<MsgType><![CDATA[text]]></MsgType>"//文本类型,text,可以不改
					+ "<Content><![CDATA[我喜欢你]]></Content>"//文本内容,我喜欢你
					+ "<MsgId>1234567890123456</MsgId> "//消息id,随便填,但位数要够
					+ " </xml>";
			System.out.println(replyMsg);//打印出来
			out.println(replyMsg);//回复

	}

}

  

这里还是强调一下,文本消息在输出流中,获取参数是看不到的;如果还是有点犯晕,可以将里面注释掉的输出全部request参数代码部分运行一下。

 最后我参考微信官方给的实例,对代码做了一点适配,可以不需要手动配置微信开发者的初始id

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.SHA1;

/**
 * Servlet implementation class test
 */
@WebServlet("/test")
public class test extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		String token = "jylife";
		String jiami = "";
		String openid=request.getParameter("openid");
		String body=request.getParameter("body");
		System.out.println(body);
		Date date=new Date();
        try {
            jiami=SHA1.getSHA1(token, timestamp, nonce,"");//这里是对三个参数进行加密
       } catch (AesException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }
           PrintWriter out=response.getWriter();
           if(jiami.equals(signature))
           out.print(echostr);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
		PrintWriter out=response.getWriter();
		try
		{
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document document = db.parse(request.getInputStream());
			Element root = document.getDocumentElement();
			String  wechatId = root.getElementsByTagName("ToUserName").item(0).getTextContent();
			String 	openid = root.getElementsByTagName("FromUserName").item(0).getTextContent();
			String 	msg = root.getElementsByTagName("Content").item(0).getTextContent();//用户发送的内容
			System.out.println(msg);//打印用户发送的消息
			String content="";
			//对用户发送过来的内容选择要回复的内容
			if(msg.matches("喜欢"))
			{
				content="我也喜欢你";
			}
			else
			{
				content="我也不喜欢你";
			}
			String replyMsg = "<xml>"
					+ "<ToUserName><![CDATA["+openid+"]]></ToUserName>"//回复用户时,这里是用户的openid;但用户发送过来消息这里是微信公众号的原始id
					+ "<FromUserName><![CDATA["+wechatId+"]]></FromUserName>"//这里填写微信公众号 的原始id;用户发送过来时这里是用户的openid
					+ "<CreateTime>1531553112194</CreateTime>"//这里可以填创建信息的时间,目前测试随便填也可以
					+ "<MsgType><![CDATA[text]]></MsgType>"//文本类型,text,可以不改
					+ "<Content><![CDATA["+content+"]]></Content>"//文本内容,我喜欢你
					+ "<MsgId>1234567890123456</MsgId> "//消息id,随便填,但位数要够
					+ " </xml>";
			System.out.println(replyMsg);//打印出来
			out.println(replyMsg);//回复
		}
		catch(Exception e)
		{
			System.out.println(e.toString());
		}
	}

}