zoukankan      html  css  js  c++  java
  • 微信公众号开发:获取用户发送消息并实现回复(Java)

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

    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());
    		}
    	}
    
    }
    

      

    多一份坚持,少一份懒惰
  • 相关阅读:
    perimeter of squares
    map
    django路由
    for的骚用法
    3和5的倍数相加和
    PeteCake 字典和最小值
    Find the missing letter
    实现简单的ssh功能
    开源运维工具体系
    vsftp在iptables中的配置
  • 原文地址:https://www.cnblogs.com/somelog/p/9309908.html
Copyright © 2011-2022 走看看