在上一篇文章寫了如何配置服務器:
今天我就給大家說下如何獲取用戶發送消息並實現回復,自己在弄這個過程走了許多坑。
要實現消息獲取和自動回復,需要了解微信是怎么實現這個過程:
我從微信官方文檔摘取了下面比較重要的信息
接收普通消息
當普通微信用戶向公眾賬號發消息時,微信服務器將POST消息的XML數據包到開發者填寫的URL上。
文本消息在請求的輸出流中,而不是參數位置,參數是對xml中標簽的解釋。
文本消息
< ![CDATA[toUser] ]>
< ![CDATA[fromUser] ]>1348831860
< ![CDATA[text] ]>
< ![CDATA[this is a test] ]>
1234567890123456
參數
描述
ToUserName
開發者微信號
FromUserName
發送方帳號(一個OpenID)
CreateTime
消息創建時間 (整型)
MsgType
text
Content
文本消息內容
MsgId
消息id,64位整型
被動回復用戶消息
當用戶發送消息給公眾號時(或某些特定的用戶操作引發的事件推送時),會產生一個POST請求,開發者可以在響應包(Get)中返回特定XML結構,來對該消息進行響應(現支持回復文本、圖片、圖文、語音、視頻、音樂)。嚴格來說,發送被動響應消息其實並不是一種接口,而是對微信服務器發過來消息的一次回復。
回復文本消息
< ![CDATA[toUser] ]>
< ![CDATA[fromUser] ]>12345678
< ![CDATA[text] ]>
< ![CDATA[你好] ]>
參數
是否必須
描述
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 = ""
+ ""//回復用戶時,這里是用戶的openid;但用戶發送過來消息這里是微信公眾號的原始id
+ ""//這里填寫微信公眾號 的原始id;用戶發送過來時這里是用戶的openid
+ "1531553112194"//這里可以填創建信息的時間,目前測試隨便填也可以
+ ""//文本類型,text,可以不改
+ ""//文本內容,我喜歡你
+ "1234567890123456 "//消息id,隨便填,但位數要夠
+ " ";
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 = ""
+ ""//回復用戶時,這里是用戶的openid;但用戶發送過來消息這里是微信公眾號的原始id
+ ""//這里填寫微信公眾號 的原始id;用戶發送過來時這里是用戶的openid
+ "1531553112194"//這里可以填創建信息的時間,目前測試隨便填也可以
+ ""//文本類型,text,可以不改
+ ""//文本內容,我喜歡你
+ "1234567890123456 "//消息id,隨便填,但位數要夠
+ " ";
System.out.println(replyMsg);//打印出來
out.println(replyMsg);//回復
}
catch(Exception e)
{
System.out.println(e.toString());
}
}
}