1. 內網映射
由于微信企業號回調模式的URL盡支持域名方式訪問,估需要注冊花生殼,做一個內網穿透(需要花16塊錢,購買一個免費版,購買之后,第二天才能添加上域名)
2. 微信企業號
注冊微信企業號:https://qy.weixin.qq.com/ (選擇團隊,團隊不需要認證)
通訊錄:新建組織 - > 關注成員
企業號 -> 應用中心 -> 新建應用 -> 消息型應用 -> 模式選擇(回調模式) -> 開啟微信消息轉發,
回調模式說明:http://qydev.weixin.qq.com/wiki/index.PHP?title=%E5%9B%9E%E8%B0%83%E6%A8%A1%E5%BC%8F
回調模式加密解密代碼:http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8A%A0%E8%A7%A3%E5%AF%86%E5%BA%93%E4%B8%8B%E8%BD%BD%E4%B8%8E%E8%BF%94%E5%9B%9E%E7%A0%81
如圖1:
自定義菜單: 開發應用的請求路徑如圖2:
設置 -> 功能設置 -> 權限管理 -> 新建管理組 -> 應用權限( Secret )
3. 利用Jersey開發web Service服務
3.1 在類中定義token, 隨機密碼43位,公司corpId, secret
3.2 驗證方法
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
|
/* * ------------使用示例一:驗證回調URL---------------企業開啟回調模式時,企業號會向驗證url發送一個get請求 * 假設點擊驗證時,企業收到類似請求: GET * /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3 * ×tamp * =1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho% * 2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D * HTTP/1.1 Host: qy.weixin.qq.com * * 接收到該請求時,企業應 * 1.解析出Get請求的參數,包括消息體簽名(msg_signature),時間戳(timestamp),隨機數字串(nonce * )以及公眾平臺推送過來的隨機加密字符串(echostr), 這一步注意作URL解碼。 2.驗證消息體簽名的正確性 3. * 解密出echostr原文,將原文當作Get請求的response,返回給公眾平臺 第2,3步可以用公眾平臺提供的庫函數VerifyURL來實現。 */ /** * 回調URL,微信調用此方法進行驗證 * * @return */ @GET @Path ( "station" ) public String verify() { String msgSignature = request.getParameter( "msg_signature" ); String timeStamp = request.getParameter( "timestamp" ); String nonce = request.getParameter( "nonce" ); System.out.println(timeStamp + " " + nonce); String echostr = request.getParameter( "echostr" ); String sEchoStr = null ; try { sEchoStr = wxcpt.VerifyURL(msgSignature, timeStamp, nonce, echostr); } catch (Exception e) { e.printStackTrace(); // 驗證URL失敗,錯誤原因請查看異常 } return sEchoStr; } |
3.3 接收用戶信息,并解密
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
|
/* * ------------對用戶回復的消息解密--------------- * 用戶回復消息或者點擊事件響應時,企業會收到回調消息,此消息是經過公眾平臺加密之后的密文以post形式發送給企業,密文格式請參考官方文檔 * 假設企業收到公眾平臺的回調消息如下: POST /cgi-bin/wxpush? * msg_signature=477715d11cdb4164915debcba66cb864d751f3e6 * ×tamp=1409659813&nonce=1372623149 HTTP/1.1 Host: qy.weixin.qq.com * Content-Length: 613 <xml> * <ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName * ><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo * +rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/ * sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT * +6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6 * +kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r * +KqCKIw * +3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0 * +rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS * +/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl * /T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt> * <AgentID><![CDATA[218]]></AgentID> </xml> * * 企業收到post請求之后應該 * 1.解析出url上的參數,包括消息體簽名(msg_signature),時間戳(timestamp)以及隨機數字串(nonce) * 2.驗證消息體簽名的正確性。 * 3.將post請求的數據進行xml解析,并將<Encrypt>標簽的內容進行解密,解密出來的明文即是用戶回復消息的明文,明文格式請參考官方文檔 * 第2,3步可以用公眾平臺提供的庫函數DecryptMsg來實現。 */ @POST @Path ( "station" ) public String receiveMsg(String reqData) { String msgSignature = request.getParameter( "msg_signature" ); String timeStamp = request.getParameter( "timestamp" ); String nonce = request.getParameter( "nonce" ); // post請求的密文數據 // String sReqData = // "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>"; try { String sMsg = wxcpt.DecryptMsg(msgSignature, timeStamp, nonce, reqData); // 解析出明文xml標簽的內容進行處理 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); StringReader sr = new StringReader(sMsg); InputSource is = new InputSource(sr); Document document = db.parse(is); Element root = document.getDocumentElement(); NodeList nodelist1 = root.getElementsByTagName( "Content" ); if (nodelist1.item( 0 ) == null ) return "ok" ; String Content = nodelist1.item( 0 ).getTextContent(); System.out.println( "Content:" + Content); } catch (Exception e) { e.printStackTrace(); // 解密失敗,失敗原因請查看異常 } return "ok" ; } |
3.4 發送信息到微信
設置 -> 功能設置 -> 權限管理 -> 新建管理組; 獲取secret
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
/** * 此方法可以發送任意類型消息 * * @param msgType * text|image|voice|video|file|news * @param touser * 成員ID列表(消息接收者,多個接收者用‘|'分隔,最多支持1000個)。特殊情況:指定為@all, * 則向關注該企業應用的全部成員發送 * @param toparty * 部門ID列表,多個接收者用‘|'分隔,最多支持100個。當touser為@all時忽略本參數 * @param totag * 標簽ID列表,多個接收者用‘|'分隔。當touser為@all時忽略本參數 * @param content * msgType=text時 ,文本消息內容 * @param mediaId * msgType=image|voice|video時 ,對應消息信息ID(--------) * @param title * msgType=news|video時,消息標題 * @param description * msgType=news|video時,消息描述 * @param url * msgType=news時,消息鏈接 * @param picurl * msgType=news時,圖片路徑 * @param safe * 表示是否是保密消息,0表示否,1表示是,默認0 */ public void sendWeChatMsg(String msgType, String touser, String toparty, String totag, String content, String mediaId, String title, String description, String url, String picurl, String safe) { URL uRl; String ACCESS_TOKEN = getAccessToken(); // 拼接請求串 String action = CREATE_SESSION_URL + ACCESS_TOKEN; // 封裝發送消息請求json StringBuffer sb = new StringBuffer(); sb.append( "{" ); sb.append( "\"touser\":" + "\"" + touser + "\"," ); sb.append( "\"toparty\":" + "\"" + toparty + "\"," ); sb.append( "\"totag\":" + "\"" + totag + "\"," ); if (msgType.equals( "text" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"text\":" + "{" ); sb.append( "\"content\":" + "\"" + content + "\"" ); sb.append( "}" ); } else if (msgType.equals( "image" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"image\":" + "{" ); sb.append( "\"media_id\":" + "\"" + mediaId + "\"" ); sb.append( "}" ); } else if (msgType.equals( "voice" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"voice\":" + "{" ); sb.append( "\"media_id\":" + "\"" + mediaId + "\"" ); sb.append( "}" ); } else if (msgType.equals( "video" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"video\":" + "{" ); sb.append( "\"media_id\":" + "\"" + mediaId + "\"," ); sb.append( "\"title\":" + "\"" + title + "\"," ); sb.append( "\"description\":" + "\"" + description + "\"" ); sb.append( "}" ); } else if (msgType.equals( "file" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"file\":" + "{" ); sb.append( "\"media_id\":" + "\"" + mediaId + "\"" ); sb.append( "}" ); } else if (msgType.equals( "news" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"news\":" + "{" ); sb.append( "\"articles\":" + "[" ); sb.append( "{" ); sb.append( "\"title\":" + "\"" + title + "\"," ); sb.append( "\"description\":" + "\"" + description + "\"," ); sb.append( "\"url\":" + "\"" + url + "\"," ); sb.append( "\"picurl\":" + "\"" + picurl + "\"" ); sb.append( "}" ); sb.append( "]" ); sb.append( "}" ); } sb.append( ",\"safe\":" + "\"" + safe + "\"," ); sb.append( "\"agentid\":" + "\"" + 1 + "\"," ); sb.append( "\"debug\":" + "\"" + "1" + "\"" ); sb.append( "}" ); String json = sb.toString(); try { uRl = new URL(action); HttpsURLConnection http = (HttpsURLConnection) uRl.openConnection(); http.setRequestMethod( "POST" ); http.setRequestProperty( "Content-Type" , "application/json;charset=UTF-8" ); http.setDoOutput( true ); http.setDoInput( true ); System.setProperty( "sun.net.client.defaultConnectTimeout" , "30000" ); // // 連接超時30秒 System.setProperty( "sun.net.client.defaultReadTimeout" , "30000" ); // // 讀取超時30秒 http.connect(); OutputStream os = http.getOutputStream(); os.write(json.getBytes( "UTF-8" )); // 傳入參數 InputStream is = http.getInputStream(); int size = is.available(); byte [] jsonBytes = new byte [size]; is.read(jsonBytes); String result = new String(jsonBytes, "UTF-8" ); System.out.println( "請求返回結果:" + result); os.flush(); os.close(); } catch (Exception e) { e.printStackTrace(); } } // 獲取接口訪問權限碼 public String getAccessToken() { HttpClient client = new HttpClient(); PostMethod post = new PostMethod(ACCESS_TOKEN_URL); post.releaseConnection(); post.setRequestHeader( "Content-Type" , "application/x-www-form-urlencoded;charset=UTF-8" ); NameValuePair[] param = { new NameValuePair( "corpid" , corpId), new NameValuePair( "corpsecret" , secret) }; // 設置策略,防止報cookie錯誤 DefaultHttpParams.getDefaultParams().setParameter( "http.protocol.cookie-policy" , CookiePolicy.BROWSER_COMPATIBILITY); // 給post設置參數 post.setRequestBody(param); String result = "" ; try { client.executeMethod(post); result = new String(post.getResponseBodyAsString().getBytes( "gbk" )); } catch (IOException e) { e.printStackTrace(); } // 將數據轉換成json JSONObject jasonObject; jasonObject = JSONObject.fromObject(result); result = (String) jasonObject.get( "access_token" ); post.releaseConnection(); System.out.println(result); return result; } public static void main(String[] args) { StationResource weChat = new StationResource(); // weChat.sendWeChatMsgText("@all", "2", "", "信息中心通知", "0"); weChat.sendWeChatMsg( "news" , "@all" , "" , "" , "測試senMsg" , "" , "測試的" , "真的是測試的" , "http://www.baidu.com" , "http://file27.mafengwo.net/M00/B2/12/wKgB6lO0ahWAMhL8AAV1yBFJDJw20.jpeg" , "0" ); } |
4. 開發完成。 需要將該類在webx.xml中添加到rest中管理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<!-- RESTful支持 --> <!-- webserivce服務,如增加了服務,需要在param-value中增加服務的包路徑 --> <servlet> <servlet-name>JAX-RS REST Servlet</servlet-name> <servlet- class >com.sun.jersey.spi.container.servlet.ServletContainer</servlet- class > <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>com.base.pf.restful</param-value> </init-param> <load-on-startup> 2 </load-on-startup> </servlet> <servlet-mapping> <servlet-name>JAX-RS REST Servlet</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> |
5. 開發完成的全量代碼
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
|
package com.base.pf.restful; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.net.URL; import javax.net.ssl.HttpsURLConnection; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import net.sf.json.JSONObject; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.params.DefaultHttpParams; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import com.qq.weixin.mp.aes.AesException; import com.qq.weixin.mp.aes.WXBizMsgCrypt; /** * 微信企業號開發 * * @author ZHEN.L * */ @Path ( "wx" ) public class StationResource { // http://hichinamobile.xicp.net/security/rest/wx // https://qy.weixin.qq.com private String token = "spm" ; // 企業號 -> 應用中心 -> 新建應用 -> 消息型應用 private String agentId = "1" ; // 企業號 -> 應用中心 -> 點開應用中 -> 應用ID private String encodingAesKey = "nT6ZWTVFlyNXOhFOGGOZWdJpAgeFSV8ln5CNeYw7mwl" ; // 企業號 -> 應用中心 -> 新建應用 -> 消息型應用 private String corpId = "wxe49318eb604cf00b" ; // 企業號 -> 設置 -> 企業號信息 -> 賬號信息 private String secret = "M-YFKmgl_kXBVEtginZH3RQWbz4xb6MFeQXXLk77mkpxZenFDYq-UgerxdUF8rel" ; // 企業號 -> 設置 -> 功能設置 -> 權限管理中 @Context HttpServletRequest request; @Context HttpServletResponse response; WXBizMsgCrypt wxcpt = null ; public StationResource() { try { wxcpt = new WXBizMsgCrypt(token, encodingAesKey, corpId); } catch (AesException e) { e.printStackTrace(); } } // 獲取訪問權限碼URL private final static String ACCESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken" ; // 創建會話請求URL private final static String CREATE_SESSION_URL = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" ; // 獲取接口訪問權限碼 public String getAccessToken() { HttpClient client = new HttpClient(); PostMethod post = new PostMethod(ACCESS_TOKEN_URL); post.releaseConnection(); post.setRequestHeader( "Content-Type" , "application/x-www-form-urlencoded;charset=UTF-8" ); NameValuePair[] param = { new NameValuePair( "corpid" , corpId), new NameValuePair( "corpsecret" , secret) }; // 設置策略,防止報cookie錯誤 DefaultHttpParams.getDefaultParams().setParameter( "http.protocol.cookie-policy" , CookiePolicy.BROWSER_COMPATIBILITY); // 給post設置參數 post.setRequestBody(param); String result = "" ; try { client.executeMethod(post); result = new String(post.getResponseBodyAsString().getBytes( "gbk" )); } catch (IOException e) { e.printStackTrace(); } // 將數據轉換成json JSONObject jasonObject; jasonObject = JSONObject.fromObject(result); result = (String) jasonObject.get( "access_token" ); post.releaseConnection(); System.out.println(result); return result; } /* * ------------使用示例一:驗證回調URL---------------企業開啟回調模式時,企業號會向驗證url發送一個get請求 * 假設點擊驗證時,企業收到類似請求: GET * /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3 * ×tamp * =1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho% * 2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D * HTTP/1.1 Host: qy.weixin.qq.com * * 接收到該請求時,企業應 * 1.解析出Get請求的參數,包括消息體簽名(msg_signature),時間戳(timestamp),隨機數字串(nonce * )以及公眾平臺推送過來的隨機加密字符串(echostr), 這一步注意作URL解碼。 2.驗證消息體簽名的正確性 3. * 解密出echostr原文,將原文當作Get請求的response,返回給公眾平臺 第2,3步可以用公眾平臺提供的庫函數VerifyURL來實現。 */ /** * 回調URL,微信調用此方法進行驗證 * * @return */ @GET @Path("station") public String verify() { String msgSignature = request.getParameter("msg_signature"); String timeStamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); System.out.println(timeStamp + " " + nonce); String echostr = request.getParameter("echostr"); String sEchoStr = null; try { sEchoStr = wxcpt.VerifyURL(msgSignature, timeStamp, nonce, echostr); } catch (Exception e) { e.printStackTrace();// 驗證URL失敗,錯誤原因請查看異常 } return sEchoStr; } /* * ------------對用戶回復的消息解密--------------- * 用戶回復消息或者點擊事件響應時,企業會收到回調消息,此消息是經過公眾平臺加密之后的密文以post形式發送給企業,密文格式請參考官方文檔 * 假設企業收到公眾平臺的回調消息如下: POST /cgi-bin/wxpush? * msg_signature=477715d11cdb4164915debcba66cb864d751f3e6 * ×tamp=1409659813&nonce=1372623149 HTTP/1.1 Host: qy.weixin.qq.com * Content-Length: 613 <xml> * <ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName * ><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo * +rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/ * sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT * +6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6 * +kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r * +KqCKIw * +3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0 * +rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS * +/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl * /T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt> * <AgentID><![CDATA[218]]></AgentID> </xml> * * 企業收到post請求之后應該 * 1.解析出url上的參數,包括消息體簽名(msg_signature),時間戳(timestamp)以及隨機數字串(nonce) * 2.驗證消息體簽名的正確性。 * 3.將post請求的數據進行xml解析,并將<Encrypt>標簽的內容進行解密,解密出來的明文即是用戶回復消息的明文,明文格式請參考官方文檔 * 第2,3步可以用公眾平臺提供的庫函數DecryptMsg來實現。 */ @POST @Path("station") public String receiveMsg(String reqData) { String msgSignature = request.getParameter("msg_signature"); String timeStamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); // post請求的密文數據 // String sReqData = // "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>"; try { String sMsg = wxcpt.DecryptMsg(msgSignature, timeStamp, nonce, reqData); // 解析出明文xml標簽的內容進行處理 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); StringReader sr = new StringReader(sMsg); InputSource is = new InputSource(sr); Document document = db.parse(is); Element root = document.getDocumentElement(); NodeList nodelist1 = root.getElementsByTagName("Content"); if (nodelist1.item(0) == null) return "ok"; String Content = nodelist1.item(0).getTextContent(); System.out.println("Content:" + Content); } catch (Exception e) { e.printStackTrace();// 解密失敗,失敗原因請查看異常 } return "ok"; } /* * ------------使用示例三:企業回復用戶消息的加密--------------- * 企業被動回復用戶的消息也需要進行加密,并且拼接成密文格式的xml串。 假設企業需要回復用戶的明文如下: <xml> * <ToUserName><![CDATA[mycreate]]></ToUserName> * <FromUserName><![CDATA[wx5823bf96d3bd56c7]]></FromUserName> * <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> * <Content><![CDATA[this is a test]]></Content> * <MsgId>1234567890123456</MsgId> <AgentID>128</AgentID> </xml> * * 為了將此段明文回復給用戶,企業應: * 1.自己生成時間時間戳(timestamp),隨機數字串(nonce)以便生成消息體簽名,也可以直接用從公眾平臺的post * url上解析出的對應值。 2.將明文加密得到密文。 * 3.用密文,步驟1生成的timestamp,nonce和企業在公眾平臺設定的token生成消息體簽名。 * 4.將密文,消息體簽名,時間戳,隨機數字串拼接成xml格式的字符串,發送給企業。 * 以上2,3,4步可以用公眾平臺提供的庫函數EncryptMsg來實現。 */ // @GET // @Path("send") public void sendMsg(String timeStamp, String nonce) { String sRespData = "<xml><ToUserName><![CDATA[mycreate]]></ToUserName><FromUserName><![CDATA[wxe49318eb604cf00b]]></FromUserName><CreateTime>1348831860</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[this is a test]]></Content><MsgId>1234567890123456</MsgId><AgentID>1</AgentID></xml>"; try { String sEncryptMsg = wxcpt.EncryptMsg(sRespData, timeStamp, nonce); System.out.println("after encrypt sEncrytMsg: " + sEncryptMsg); response.getWriter().print(sEncryptMsg); } catch (Exception e) { e.printStackTrace();// 加密失敗 } // return sRespData; } /** * 此方法可以發送任意類型消息 * * @param msgType * text|image|voice|video|file|news * @param touser * 成員ID列表(消息接收者,多個接收者用‘|'分隔,最多支持1000個)。特殊情況:指定為@all, * 則向關注該企業應用的全部成員發送 * @param toparty * 部門ID列表,多個接收者用‘|'分隔,最多支持100個。當touser為@all時忽略本參數 * @param totag * 標簽ID列表,多個接收者用‘|'分隔。當touser為@all時忽略本參數 * @param content * msgType=text時 ,文本消息內容 * @param mediaId * msgType=image|voice|video時 ,對應消息信息ID(--------) * @param title * msgType=news|video時,消息標題 * @param description * msgType=news|video時,消息描述 * @param url * msgType=news時,消息鏈接 * @param picurl * msgType=news時,圖片路徑 * @param safe * 表示是否是保密消息,0表示否,1表示是,默認0 */ public void sendWeChatMsg(String msgType, String touser, String toparty, String totag, String content, String mediaId, String title, String description, String url, String picurl, String safe) { URL uRl; String ACCESS_TOKEN = getAccessToken(); // 拼接請求串 String action = CREATE_SESSION_URL + ACCESS_TOKEN; // 封裝發送消息請求json StringBuffer sb = new StringBuffer(); sb.append( "{" ); sb.append( "\"touser\":" + "\"" + touser + "\"," ); sb.append( "\"toparty\":" + "\"" + toparty + "\"," ); sb.append( "\"totag\":" + "\"" + totag + "\"," ); if (msgType.equals( "text" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"text\":" + "{" ); sb.append( "\"content\":" + "\"" + content + "\"" ); sb.append( "}" ); } else if (msgType.equals( "image" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"image\":" + "{" ); sb.append( "\"media_id\":" + "\"" + mediaId + "\"" ); sb.append( "}" ); } else if (msgType.equals( "voice" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"voice\":" + "{" ); sb.append( "\"media_id\":" + "\"" + mediaId + "\"" ); sb.append( "}" ); } else if (msgType.equals( "video" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"video\":" + "{" ); sb.append( "\"media_id\":" + "\"" + mediaId + "\"," ); sb.append( "\"title\":" + "\"" + title + "\"," ); sb.append( "\"description\":" + "\"" + description + "\"" ); sb.append( "}" ); } else if (msgType.equals( "file" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"file\":" + "{" ); sb.append( "\"media_id\":" + "\"" + mediaId + "\"" ); sb.append( "}" ); } else if (msgType.equals( "news" )) { sb.append( "\"msgtype\":" + "\"" + msgType + "\"," ); sb.append( "\"news\":" + "{" ); sb.append( "\"articles\":" + "[" ); sb.append( "{" ); sb.append( "\"title\":" + "\"" + title + "\"," ); sb.append( "\"description\":" + "\"" + description + "\"," ); sb.append( "\"url\":" + "\"" + url + "\"," ); sb.append( "\"picurl\":" + "\"" + picurl + "\"" ); sb.append( "}" ); sb.append( "]" ); sb.append( "}" ); } sb.append( ",\"safe\":" + "\"" + safe + "\"," ); sb.append( "\"agentid\":" + "\"" + agentId + "\"," ); sb.append( "\"debug\":" + "\"" + "1" + "\"" ); sb.append( "}" ); String json = sb.toString(); try { uRl = new URL(action); HttpsURLConnection http = (HttpsURLConnection) uRl.openConnection(); http.setRequestMethod( "POST" ); http.setRequestProperty( "Content-Type" , "application/json;charset=UTF-8" ); http.setDoOutput( true ); http.setDoInput( true ); System.setProperty( "sun.net.client.defaultConnectTimeout" , "30000" ); // // 連接超時30秒 System.setProperty( "sun.net.client.defaultReadTimeout" , "30000" ); // // 讀取超時30秒 http.connect(); OutputStream os = http.getOutputStream(); os.write(json.getBytes( "UTF-8" )); // 傳入參數 InputStream is = http.getInputStream(); int size = is.available(); byte [] jsonBytes = new byte [size]; is.read(jsonBytes); String result = new String(jsonBytes, "UTF-8" ); System.out.println( "請求返回結果:" + result); os.flush(); os.close(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { StationResource weChat = new StationResource(); // weChat.sendWeChatMsgText("@all", "2", "", "信息中心通知", "0"); weChat.sendWeChatMsg( "news" , "@all" , "" , "" , "測試senMsg" , "" , "測試的" , "真的是測試的" , "http://www.baidu.com" , "http://file27.mafengwo.net/M00/B2/12/wKgB6lO0ahWAMhL8AAV1yBFJDJw20.jpeg" , "0" ); } } |
以上所述是小編給大家介紹的微信企業號驗證/發送/接收消息,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
原文鏈接:http://blog.csdn.net/hichinamobile/article/details/51803097