微信公众号开发:获取用户发送消息并实现回复(Java)
今天我就给大家说下如何获取用户发送消息并实现回复,自己在弄这个过程走了许多坑。
要实现消息获取和自动回复,需要了解微信是怎么实现这个过程:
我从微信官方文档摘取了下面比较重要的信息
接收普通消息
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
文本消息在请求的输出流中,而不是参数位置,参数是对xml中标签的解释。
文本消息
1 2 3 4 5 6 7 | < 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结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。
回复文本消息
1 2 3 4 5 | < 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请求到我们的服务器上。
可以看下我写的代码来理解这个过程,这个代码有部分利用上一篇文章说过的步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 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()); } } } |
猜您可能还喜欢
- Spring web.xml中contextConfigLocation参数介绍(1140)
- Redis 在 Web 项目中的应用与实践(1116)
- Java Web开发中web.xml文件详细介绍(1114)
- JQuery Ajax访问Spring MVC接口解决跨域请求(1103)
- java.lang.ClassNotFoundException: org.apache.xmlbeans.XmlObject错误解决方法(1001)
- Springboot 系列(一)Spring Boot 入门篇(968)
- MyBatis JdbcType详解(910)
- 基于springboot的web项目最佳实践(833)
- 微信公众号开发:获取用户发送消息并实现回复(Java)(815)
评论列表
发表评论
文章分类
文章归档
阅读排行
- 1. Windows Server 2008 R2永久激活及Chew-WGA v0.9下载(12925)
- 2.Visual Studio 2017中安装visualSVN及使用详解(5012)
- 3.完美解决iis下JWplayer提示Error loading media: File could not be played错误(3898)
- 4.asp.net mvc+jquery easyui开发基础(一)模块首页及增加、修改、删除模块实现(3124)
- 5.Android avax.net.ssl.SSLPeerUnverifiedException: No peer certificate 解决方法(httpClient支持HTTPS的访问方式)(3003)
- 6..Net Mvc中使用Jquery EasyUI控件讲解(一)表格控件datagrid使用介绍(2835)
- 7.asp.net mvc+jquery easyui开发实战教程之网站后台管理系统开发(三)登录模块开发(2741)
- 8.asp.net mvc+jquery easyui开发实战教程之网站后台管理系统开发(七)权限管理模块之系统菜单动态生成(2710)
- 9. asp.net mvc+jquery easyui开发实战教程之网站后台管理系统开发(六)权限管理模块之初始数据准备(2340)
- 10.asp.net mvc+jquery easyui开发实战教程之网站后台管理系统开发(八)权限管理模块之权限管理实现(2309)