この記事では、主に Java WeChat 開発の第 2 ステップ API を分析して、メッセージを取得して返信する方法を説明します。
1. 説明* この例は、WeChat 開発ドキュメントに基づいています:http://mp.weixin.qq.com/wiki/home/index.html最新バージョン (2016 年 4 月 3 日 5:34:午後 36 時) 開発デモを実施します。 * 編集プラットフォーム: myeclipse10.7+win32+jdk1.7+tomcat7.0
* サーバー: Alibaba Cloud Windows Server 2008 64 ビット* プラットフォーム要件: サーブレット
アノテーション メソッドを使用、プラットフォーム要件: j2ee6.0+、jdk6。 0+、tomcat7.0+
* このデモでは、API 分析に重点を置いています。
* テストの説明を容易にするために、各テスト ケースは独立しており、他のメソッドに依存しません。梱包についてはあまり考えないでください。 * デモは、可能な限り API 要件に従って実行する必要があります。その目的は、ドキュメントの使用方法を理解し、1 つの例から推測する効果を達成することです。 * 知識要件: しっかりした Java の基礎、http ネットワーク通信の知識、javaweb の十分な理解、
json
解析
* 各記事の最後に、この部分のデモ ソース コードが示されます。 API を分析した後、すべてのデモ ソース コードはソース コード パッケージの形式で提供されます。
* 現在時刻: 2016 年 4 月 3 日 5:32:57 PM、今回の対象となります。
2. 元のドキュメント - メッセージ管理 (
要約
•ドキュメントのアドレス: http://mp.weixin.qq.com/wiki/17/f298879f8fb29ab98b2f2971d42552fd.html
•メッセージ管理
◦ メッセージの受信 - イベントプッシュの受信 ◦ メッセージの送信 - パッシブ応答メッセージ ◦ メッセージの送信 - パッシブ応答中の暗号化と復号化
◦ メッセージの送信 - カスタマーサービスメッセージ
◦ メッセージの送信 - グループ送信インターフェース
◦ メッセージ送信 - テンプレートメッセージインターフェース
◦ メッセージ送信 - テンプレートメッセージ動作仕様
◦ 公開アカウントの自動返信設定の取得
3. 文書理解
• メッセージ受信
◦ 文書通常の WeChat ユーザーが公開アカウントにメッセージを送信すると、WeChat サーバーは POST メッセージの XML
データを開発者が入力した URL にパッケージ化します。 理解: WeChat サーバーは、ユーザーが req に送信したメッセージをポスト ストリームの形式で返します。ユーザーが送信したメッセージを取得したい場合は、req.getInputStream() を通じて取得できます。もちろん、ドキュメントで返されたメッセージの XML 形式に基づいて必要な解析を実行できます。 ◦実装:
/* * 该部分我们获取用户发送的信息,并且解析成<K,V>的形式进行显示 */ // 解析用户发送过来的信息 InputStream is = req.getInputStream();// 拿取请求流 // 将解析结果存储在HashMap中 Map<String, String> map = new HashMap<String, String>(); // 解析xml,将获取到的返回结果xml进行解析成我们习惯的文字信息 SAXReader reader = new SAXReader();// 第三方jar:dom4j【百度:saxreader解析xml】 Document document = null; try { document = reader.read(is); } catch (DocumentException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } // 得到xml根元素 Element root = document.getRootElement(); // 得到根元素的所有子节点 List<Element> elementList = root.elements(); // 遍历所有子节点 for (Element e : elementList) map.put(e.getName(), e.getText()); // 测试输出 Set<String> keySet = map.keySet(); // 测试输出解析后用户发过来的信息 System.out.println(TAG + ":解析用户发送过来的信息开始"); for (String key : keySet) { System.out.println(key + ":" + map.get(key)); } System.out.println(TAG + ":解析用户发送过来的信息结束");
◦ドキュメントでは次のように説明されています: ユーザーが公式アカウントにメッセージを送信するとき (または特定のユーザー操作によりイベントがプッシュされるとき)、POSTリクエストが生成されると、開発者は応答パッケージ (Get) で特定の XML 構造を返すことでメッセージに応答できます (応答テキスト、
写真、グラフィックス、テキスト、音声、ビデオ、音楽をサポートするようになりました)。厳密に言えば、受動的応答メッセージの送信は実際にはインターフェイスではなく、WeChat サーバーによって送信されたメッセージに対する応答です。 理解: ユーザーがリクエストを送信すると、POST リクエストが生成され、Respone を通じてメッセージに返信できます。ただし、返信コンテンツには厳密な形式要件があり、形式要件が満たされている場合にのみ、WeChat サーバーはそれを処理してユーザーに返します。ドキュメントの「メッセージ管理」モジュールを見ると、WeChat にはさまざまなメッセージがあることがわかります。メッセージの種類ごとに、特定の情報をユーザーに正常に返すための要件に従う必要があります。ユーザーのテキスト メッセージとグラフィック メッセージには、ドキュメントで必要な形式で返信するよう努めます。キーポイント: ドキュメントの要件に従って必要なパラメータを構築します。特記事項: パラメータでは大文字と小文字が区別されます。 ◦ 実装 1-通常のテキストメッセージへの返信:
//实例1:发送普通文本消息,请查看文档关于“回复文本消息”的xml格式 // 第一步:按照回复文本信息构造需要的参数 TextMsg textMsg = new TextMsg(); textMsg.setToUserName(map.get("FromUserName"));// 发送和接收信息“User”刚好相反 textMsg.setFromUserName(map.get("ToUserName")); textMsg.setCreateTime(new Date().getTime());// 消息创建时间 (整型) textMsg.setMsgType("text");// 文本类型消息 textMsg.setContent("我是服务器回复给用户的信息"); // // 第二步,将构造的信息转化为微信识别的xml格式【百度:xstream bean转xml】 XStream xStream = new XStream(); xStream.alias("xml", textMsg.getClass()); String textMsg2Xml = xStream.toXML(textMsg); System.out.println(textMsg2Xml); // // 第三步,发送xml的格式信息给微信服务器,服务器转发给用户 PrintWriter printWriter = resp.getWriter(); printWriter.print(textMsg2Xml);
//实例2,发送图文消息。请查看文档关于“回复图文消息”的xml格式 // 第一步:按照回复图文信息构造需要的参数 List<Article> articles = new ArrayList<Article>(); Article a = new Article(); a.setTitle("我是图片标题"); a.setUrl("www.baidu.com");// 该地址是点击图片跳转后 a.setPicUrl("http://b.hiphotos.baidu.com/image/pic/item/08f790529822720ea5d058ba7ccb0a46f21fab50.jpg");// 该地址是一个有效的图片地址 a.setDescription("我是图片的描述"); articles.add(a); PicAndTextMsg picAndTextMsg = new PicAndTextMsg(); picAndTextMsg.setToUserName(map.get("FromUserName"));// 发送和接收信息“User”刚好相反 picAndTextMsg.setFromUserName(map.get("ToUserName")); picAndTextMsg.setCreateTime(new Date().getTime());// 消息创建时间 (整型) picAndTextMsg.setMsgType("news");// 图文类型消息 picAndTextMsg.setArticleCount(1); picAndTextMsg.setArticles(articles); // 第二步,将构造的信息转化为微信识别的xml格式【百度:xstream bean转xml】 XStream xStream = new XStream(); xStream.alias("xml", picAndTextMsg.getClass()); xStream.alias("item", a.getClass()); String picAndTextMsg2Xml = xStream.toXML(picAndTextMsg); System.out.println(picAndTextMsg2Xml); // 第三步,发送xml的格式信息给微信服务器,服务器转发给用户 PrintWriter printWriter = resp.getWriter(); printWriter.print(picAndTextMsg2Xml);
•CoreServlet.java (サーバーアクセス、受信を含む)ユーザーメッセージ メッセージ、通常のテキストメッセージへの返信、グラフィックメッセージへの返信 サードパーティの jar が必要: dom4j、xstream)
package com.gist.servlet; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; 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 org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import com.gist.bean.Article; import com.gist.bean.PicAndTextMsg; import com.thoughtworks.xstream.XStream; /** * @author 高远</n> 邮箱:wgyscsf@163.com</n> 博客 //m.sbmmt.com/;/n> * 编写时期 2016-4-3 下午4:34:05 */ @WebServlet("/CoreServlet") public class CoreServlet extends HttpServlet { private static final long serialVersionUID = 1L; String TAG = "CoreServlet"; /* * 第二步:验证服务器地址的有效性 开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上, * GET请求携带四个参数:signature、timestamp、nonce、echostr * 开发者通过检验signature对请求进行校验(下面有校验方式)。 若确认此次GET请求来自微信服务器,请原样返回echostr参数内容, * 则接入生效, 成为开发者成功,否则接入失败。 * * 加密/校验流程如下: 1. 将token、timestamp、nonce三个参数进行字典序排序 2. * 将三个参数字符串拼接成一个字符串进行sha1加密 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 */ /* * 字典排序(lexicographical * order)是一种对于随机变量形成序列的排序方法。其方法是,按照字母顺序,或者数字小大顺序,由小到大的形成序列。 */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 设置编码 req.setCharacterEncoding("utf-8"); resp.setContentType("html/text;charset=utf-8"); resp.setCharacterEncoding("utf-8"); // 获取输出流 PrintWriter printWriter = resp.getWriter(); // 设置一个全局的token,开发者自己设置。api这样解释:Token可由开发者可以任意填写, // 用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性) String token = "wgyscsf"; // 根据api说明,获取上述四个参数 String signature = req.getParameter("signature"); String timestamp = req.getParameter("timestamp"); String nonce = req.getParameter("nonce"); String echostr = req.getParameter("echostr"); // // temp:临时打印,观看返回参数情况 // System.out.println(TAG + ":signature:" + signature + ",timestamp:" // + timestamp + ",nonce:" + nonce + ",echostr:" + echostr); // 根据api所说的“加密/校验流程”进行接入。共计三步 // 第一步:将token、timestamp、nonce三个参数进行字典序排序 String[] parms = new String[] { token, timestamp, nonce };// 将需要字典序排列的字符串放到数组中 Arrays.sort(parms);// 按照api要求进行字典序排序 // 第二步:将三个参数字符串拼接成一个字符串进行sha1加密 // 拼接字符串 String parmsString = "";// 注意,此处不能=null。 for (int i = 0; i < parms.length; i++) { parmsString += parms[i]; } // sha1加密 String mParms = null;// 加密后的结果 MessageDigest digest = null; try { digest = java.security.MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } digest.update(parmsString.getBytes()); byte messageDigest[] = digest.digest(); // Create Hex String StringBuffer hexString = new StringBuffer(); // 字节数组转换为 十六进制 数 for (int i = 0; i < messageDigest.length; i++) { String shaHex = Integer.toHexString(messageDigest[i] & 0xFF); if (shaHex.length() < 2) { hexString.append(0); } hexString.append(shaHex); } mParms = hexString.toString();// 加密结果 /* * api要求: 若确认此次GET请求来自微信服务器,请原样返回echostr参数内容, 则接入生效, 成为开发者成功,否则接入失败。 */ // 第三步: 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信接入成功。 // System.out.println(TAG + ":" + mParms + "---->" + signature); if (mParms.equals(signature)) { // System.out.println(TAG + ":" + mParms + "---->" + signature); printWriter.write(echostr); } else { // 接入失败,不用回写 // System.out.println(TAG + "接入失败"); } } /* * 查看api文档关于收发消息推送的消息格式基本一致。 如以下格式: <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> 那么,我们就可以进行统一处理。 */ /* * 我们先获取输入流,看输入流里面的信息。通过测试打印输出流,我们可以看到每次用户请求,都会收到req请求,请求格式是xml格式,该信息在文档中有说明。 */ /* * 特别注意,req.getInputStream()只能获取一次,并且只能读取一次。如果想要多次读取,需要另外想办法。为了简单起见, * 我们只获取一次req.getInputStream(),不再打印输出流信息。直接打印解析后的信息。 */ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 设置编码 req.setCharacterEncoding("utf-8"); resp.setContentType("html/text;charset=utf-8"); resp.setCharacterEncoding("utf-8"); /* * 该部分我们获取用户发送的信息,并且解析成<K,V>的形式进行显示 */ // 解析用户发送过来的信息 InputStream is = req.getInputStream();// 拿取请求流 // 将解析结果存储在HashMap中 Map<String, String> map = new HashMap<String, String>(); // 解析xml,将获取到的返回结果xml进行解析成我们习惯的文字信息 SAXReader reader = new SAXReader();// 第三方jar:dom4j【百度:saxreader解析xml】 Document document = null; try { document = reader.read(is); } catch (DocumentException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } // 得到xml根元素 Element root = document.getRootElement(); // 得到根元素的所有子节点 List<Element> elementList = root.elements(); // 遍历所有子节点 for (Element e : elementList) map.put(e.getName(), e.getText()); // 测试输出 Set<String> keySet = map.keySet(); // 测试输出解析后用户发过来的信息 System.out.println(TAG + ":解析用户发送过来的信息开始"); for (String key : keySet) { System.out.println(key + ":" + map.get(key)); } System.out.println(TAG + ":解析用户发送过来的信息结束"); /* * 该部分我们尝试按照文档的要求格式给用户回复文本信息、图文消息。重点:按照文档要求构造需要的参数。特别注意:参数区分大小写。 */ // //实例1:发送普通文本消息,请查看文档关于“回复文本消息”的xml格式 // // // 第一步:按照回复文本信息构造需要的参数 // TextMsg textMsg = new TextMsg(); // textMsg.setToUserName(map.get("FromUserName"));// 发送和接收信息“User”刚好相反 // textMsg.setFromUserName(map.get("ToUserName")); // textMsg.setCreateTime(new Date().getTime());// 消息创建时间 (整型) // textMsg.setMsgType("text");// 文本类型消息 // textMsg.setContent("我是服务器回复给用户的信息"); // // // // 第二步,将构造的信息转化为微信识别的xml格式【百度:xstream bean转xml】 // XStream xStream = new XStream(); // xStream.alias("xml", textMsg.getClass()); // String textMsg2Xml = xStream.toXML(textMsg); // System.out.println(textMsg2Xml); // // // // 第三步,发送xml的格式信息给微信服务器,服务器转发给用户 // PrintWriter printWriter = resp.getWriter(); // printWriter.print(textMsg2Xml); // //实例2,发送图文消息。请查看文档关于“回复图文消息”的xml格式 // 第一步:按照回复图文信息构造需要的参数 List<Article> articles = new ArrayList<Article>(); Article a = new Article(); a.setTitle("我是图片标题"); a.setUrl("www.baidu.com");// 该地址是点击图片跳转后 a.setPicUrl("http://b.hiphotos.baidu.com/image/pic/item/08f790529822720ea5d058ba7ccb0a46f21fab50.jpg");// 该地址是一个有效的图片地址 a.setDescription("我是图片的描述"); articles.add(a); PicAndTextMsg picAndTextMsg = new PicAndTextMsg(); picAndTextMsg.setToUserName(map.get("FromUserName"));// 发送和接收信息“User”刚好相反 picAndTextMsg.setFromUserName(map.get("ToUserName")); picAndTextMsg.setCreateTime(new Date().getTime());// 消息创建时间 (整型) picAndTextMsg.setMsgType("news");// 图文类型消息 picAndTextMsg.setArticleCount(1); picAndTextMsg.setArticles(articles); // 第二步,将构造的信息转化为微信识别的xml格式【百度:xstream bean转xml】 XStream xStream = new XStream(); xStream.alias("xml", picAndTextMsg.getClass()); xStream.alias("item", a.getClass()); String picAndTextMsg2Xml = xStream.toXML(picAndTextMsg); System.out.println(picAndTextMsg2Xml); // 第三步,发送xml的格式信息给微信服务器,服务器转发给用户 PrintWriter printWriter = resp.getWriter(); printWriter.print(picAndTextMsg2Xml); } }
•TestMsg.java (通常のテキストメッセージ Bean) package com.gist.bean;
/**
* @author 高远</n> 邮箱:wgyscsf@163.com</n> 博客 //m.sbmmt.com/;/n>
* 编写时期 2016-4-4 下午2:09:27
*/
public class TextMsg {
private String ToUserName;
private String FromUserName;
private long CreateTime;
private String MsgType;
@Override
public String toString() {
return "TextMsg [ToUserName=" + ToUserName + ", FromUserName="
+ FromUserName + ", CreateTime=" + CreateTime + ", MsgType="
+ MsgType + ", Content=" + Content + "]";
}
private String Content;
public TextMsg(String toUserName, String fromUserName, long createTime,
String msgType, String content) {
super();
ToUserName = toUserName;
FromUserName = fromUserName;
CreateTime = createTime;
MsgType = msgType;
Content = content;
}
public TextMsg() {
super();
}
public String getToUserName() {
return ToUserName;
}
public void setToUserName(String toUserName) {
ToUserName = toUserName;
}
public String getFromUserName() {
return FromUserName;
}
public void setFromUserName(String fromUserName) {
FromUserName = fromUserName;
}
public long getCreateTime() {
return CreateTime;
}
public void setCreateTime(long createTime) {
CreateTime = createTime;
}
public String getMsgType() {
return MsgType;
}
public void setMsgType(String msgType) {
MsgType = msgType;
}
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
}
•Article.java (グラフィック内のアーティクル Bean)メッセージ)
package com.gist.bean; /** * @author 高远</n> 邮箱:wgyscsf@163.com</n> 博客 //m.sbmmt.com/;/n> * 编写时期 2016-4-4 下午2:47:08 */ public class Article { private String Title; @Override public String toString() { return "item [Title=" + Title + ", Description=" + Description + ", PicUrl=" + PicUrl + ", Url=" + Url + "]"; } public String getTitle() { return Title; } public void setTitle(String title) { Title = title; } public String getDescription() { return Description; } public void setDescription(String description) { Description = description; } public String getPicUrl() { return PicUrl; } public void setPicUrl(String picUrl) { PicUrl = picUrl; } public String getUrl() { return Url; } public void setUrl(String url) { Url = url; } private String Description; private String PicUrl; private String Url; }
package com.gist.bean; import java.util.List; /** * @author 高远</n> 邮箱:wgyscsf@163.com</n> 博客 //m.sbmmt.com/;/n> * 编写时期 2016-4-4 下午2:47:08 */ public class PicAndTextMsg { private String ToUserName; private String FromUserName; private long CreateTime; private String MsgType; private int ArticleCount; private List<Article> Articles; @Override public String toString() { return "PicAndTextMsg [ToUserName=" + ToUserName + ", FromUserName=" + FromUserName + ", CreateTime=" + CreateTime + ", MsgType=" + MsgType + ", ArticleCount=" + ArticleCount + ", Articles=" + Articles + "]"; } public String getToUserName() { return ToUserName; } public void setToUserName(String toUserName) { ToUserName = toUserName; } public String getFromUserName() { return FromUserName; } public void setFromUserName(String fromUserName) { FromUserName = fromUserName; } public long getCreateTime() { return CreateTime; } public void setCreateTime(long createTime) { CreateTime = createTime; } public String getMsgType() { return MsgType; } public void setMsgType(String msgType) { MsgType = msgType; } public int getArticleCount() { return ArticleCount; } public void setArticleCount(int articleCount) { ArticleCount = articleCount; } public List<Article> getArticles() { return Articles; } public void setArticles(List<Article> articles) { Articles = articles; } }
以上がJava WeChat 開発 API の 2 番目のステップを分析して、メッセージを取得して返信するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。