微信公眾號開發一般是針對企業和組織的,個人一般只能申請訂閱號,并且調用的接口有限,下面我們就來簡單的描述下接入公眾號的步驟:
1、首先你需要一個郵箱在微信公眾號平臺進行注冊;
注冊的方式有訂閱號、公眾號、小程序和企業號,個人我們這里只能選擇訂閱號
2、注冊完后,我們登錄到公眾號平臺--->開發--->基本配置,這里需要填寫URL和token,URL就是我們使用服務器的接口;
3、Java Web服務器程序編譯好且在服務器上部署可以運行的話,可在微信公眾號進行在線接口調試:
1)、選擇合適的接口
2)、系統會生成該接口的參數表,您可以直接在文本框內填入對應的參數值(紅色星號表示該字段必填)
3)、點擊檢查問題按鈕,即可得到相應的調試信息
eg:獲取access_token的步驟:
1)、接口類型:基礎支持
2)、接口列表:獲取access_token接口/token
3)、填寫相應的參數:grant_type、appid、secret
4)、點擊檢查問題
5)、驗證成功會返回結果和提示,結果為:200 ok,提示:Request successful即表示驗證成功
我們這里驗證比較多的是消息接口調試:文本消息、圖片消息、語音消息、視頻消息、etc
4、接口有不理解的地方,可進入開發-->開發者工具-->開發者文檔進行查詢
5、接口權限:訂閱號主要有基礎支持、接收消息及網頁服務里面的一些接口
下面我們主要講訂閱號怎么樣接收消息的案例:
1、需要申請一個個人微信訂閱號
2、url服務器和服務器端代碼部署(可以用騰訊云or阿里云服務器)
1)、AccountsServlet.java類,驗證來自微信服務器和微信服務器的消息處理
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
|
package cn.jon.wechat.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.jon.wechat.service.AccountsService; import cn.jon.wechat.utils.SignUtil; public class AccountsServlet extends HttpServlet { public AccountsServlet() { super (); } public void destroy() { super .destroy(); // Put your code here } /** * 確認請求來自于微信服務器 */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println( "接口測試開始!!!" ); //微信加密簽名 String signature = request.getParameter( "signature" ); //時間戳 String timestamp = request.getParameter( "timestamp" ); //隨機數 String nonce = request.getParameter( "nonce" ); //隨機字符串 String echostr = request.getParameter( "echostr" ); PrintWriter out = response.getWriter(); //通過校驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗 if (SignUtil.checkSignature(signature,timestamp,nonce)){ out.print(echostr); } out.close(); out = null ; // response.encodeRedirectURL("success.jsp"); } /** * 處理微信服務器發來的消息 */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //消息的接受、處理、響應 request.setCharacterEncoding( "utf-8" ); response.setCharacterEncoding( "utf-8" ); //調用核心業務類型接受消息、處理消息 String respMessage = AccountsService.processRequest(request); //響應消息 PrintWriter out = response.getWriter(); out.print(respMessage); out.close(); } public void init() throws ServletException { // Put your code here } } |
2)、SignUtil.java類,請求校驗工具類,token需要和微信中填寫的token一致
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
|
package cn.jon.wechat.utils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * 請求校驗工具類 * @author jon */ public class SignUtil { //與微信配置中的的Token一致 private static String token = "" ; public static boolean checkSignature(String signature, String timestamp, String nonce) { String[] arra = new String[]{token,timestamp,nonce}; //將signature,timestamp,nonce組成數組進行字典排序 Arrays.sort(arra); StringBuilder sb = new StringBuilder(); for ( int i= 0 ;i<arra.length;i++){ sb.append(arra[i]); } MessageDigest md = null ; String stnStr = null ; try { md = MessageDigest.getInstance( "SHA-1" ); byte [] digest = md.digest(sb.toString().getBytes()); stnStr = byteToStr(digest); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } //釋放內存 sb = null ; //將sha1加密后的字符串與signature對比,標識該請求來源于微信 return stnStr!= null ?stnStr.equals(signature.toUpperCase()): false ; } /** * 將字節數組轉換成十六進制字符串 * @param digestArra * @return */ private static String byteToStr( byte [] digestArra) { // TODO Auto-generated method stub String digestStr = "" ; for ( int i= 0 ;i<digestArra.length;i++){ digestStr += byteToHexStr(digestArra[i]); } return digestStr; } /** * 將字節轉換成為十六進制字符串 */ private static String byteToHexStr( byte dByte) { // TODO Auto-generated method stub char [] Digit = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' }; char [] tmpArr = new char [ 2 ]; tmpArr[ 0 ] = Digit[(dByte>>> 4 )& 0X0F ]; tmpArr[ 1 ] = Digit[dByte& 0X0F ]; String s = new String(tmpArr); return s; } public static void main(String[] args) { /*byte dByte = 'A'; System.out.println(byteToHexStr(dByte));*/ Map<String,String> map = new ConcurrentHashMap<String, String>(); map.put("4", "zhangsan"); map.put("100", "lisi"); Set set = map.keySet(); Iterator iter = set.iterator(); while(iter.hasNext()){ // String keyV = (String) iter.next(); String key =(String)iter.next(); System.out.println(map.get(key)); // System.out.println(map.get(iter.next())); } /*for(int i=0;i<map.size();i++){ }*/ } } |
3)、AccountsService.java服務類,主要是消息的請求和響應處理,并且當用戶關注你的公眾號的時候,可以設置默認推送消息
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
|
package cn.jon.wechat.service; import java.util.Date; import java.util.Map; import javax.servlet.http.HttpServletRequest; import cn.jon.wechat.message.req.ImageMessage; import cn.jon.wechat.message.req.LinkMessage; import cn.jon.wechat.message.req.LocationMessage; import cn.jon.wechat.message.req.VideoMessage; import cn.jon.wechat.message.req.VoiceMessage; import cn.jon.wechat.message.resp.TextMessage; import cn.jon.wechat.utils.MessageUtil; /** * 解耦,使控制層與業務邏輯層分離開來,主要處理請求,響應 * @author jon */ public class AccountsService { public static String processRequest(HttpServletRequest request) { String respMessage = null ; //默認返回的文本消息內容 String respContent = "請求處理異常,請稍后嘗試!" ; try { //xml請求解析 Map<String,String> requestMap = MessageUtil.pareXml(request); //發送方賬號(open_id) String fromUserName = requestMap.get( "FromUserName" ); //公眾賬號 String toUserName = requestMap.get( "ToUserName" ); //消息類型 String msgType = requestMap.get( "MsgType" ); //默認回復此文本消息 TextMessage defaultTextMessage = new TextMessage(); defaultTextMessage.setToUserName(fromUserName); defaultTextMessage.setFromUserName(toUserName); defaultTextMessage.setCreateTime( new Date().getTime()); defaultTextMessage.setMsgType(MessageUtil.MESSSAGE_TYPE_TEXT); defaultTextMessage.setFuncFlag( 0 ); // 由于href屬性值必須用雙引號引起,這與字符串本身的雙引號沖突,所以要轉義 defaultTextMessage.setContent( "歡迎訪問<a href=\"http://blog.csdn.net/j086924\">jon的博客</a>!" ); // defaultTextMessage.setContent(getMainMenu()); // 將文本消息對象轉換成xml字符串 respMessage = MessageUtil.textMessageToXml(defaultTextMessage); //文本消息 if (msgType.equals(MessageUtil.MESSSAGE_TYPE_TEXT)){ //respContent = "Hi,您發送的是文本消息!"; //回復文本消息 TextMessage textMessage = new TextMessage(); // textMessage.setToUserName(toUserName); // textMessage.setFromUserName(fromUserName); //這里需要注意,否則無法回復消息給用戶了 textMessage.setToUserName(fromUserName); textMessage.setFromUserName(toUserName); textMessage.setCreateTime( new Date().getTime()); textMessage.setMsgType(MessageUtil.MESSSAGE_TYPE_TEXT); textMessage.setFuncFlag( 0 ); respContent = "Hi,你發的消息是:" +requestMap.get( "Content" ); textMessage.setContent(respContent); respMessage = MessageUtil.textMessageToXml(textMessage); } //圖片消息 else if (msgType.equals(MessageUtil.MESSSAGE_TYPE_IMAGE)){ ImageMessage imageMessage= new ImageMessage(); imageMessage.setToUserName(fromUserName); imageMessage.setFromUserName(toUserName); imageMessage.setCreateTime( new Date().getTime()); imageMessage.setMsgType(MessageUtil.MESSSAGE_TYPE_IMAGE); //respContent=requestMap.get("PicUrl"); imageMessage.setPicUrl( "http://img24.pplive.cn//2013//07//24//12103112092_230X306.jpg" ); respMessage = MessageUtil.imageMessageToXml(imageMessage); } //地理位置 else if (msgType.equals(MessageUtil.MESSSAGE_TYPE_LOCATION)){ LocationMessage locationMessage= new LocationMessage(); locationMessage.setToUserName(fromUserName); locationMessage.setFromUserName(toUserName); locationMessage.setCreateTime( new Date().getTime()); locationMessage.setMsgType(MessageUtil.MESSSAGE_TYPE_LOCATION); locationMessage.setLocation_X(requestMap.get( "Location_X" )); locationMessage.setLocation_Y(requestMap.get( "Location_Y" )); locationMessage.setScale(requestMap.get( "Scale" )); locationMessage.setLabel(requestMap.get( "Label" )); respMessage = MessageUtil.locationMessageToXml(locationMessage); } //視頻消息 else if (msgType.equals(MessageUtil.MESSSAGE_TYPE_VIDEO)){ VideoMessage videoMessage= new VideoMessage(); videoMessage.setToUserName(fromUserName); videoMessage.setFromUserName(toUserName); videoMessage.setCreateTime( new Date().getTime()); videoMessage.setMsgType(MessageUtil.MESSSAGE_TYPE_VIDEO); videoMessage.setMediaId(requestMap.get( "MediaId" )); videoMessage.setThumbMediaId(requestMap.get( "ThumbMediaId" )); respMessage = MessageUtil.videoMessageToXml(videoMessage); } //鏈接消息 else if (msgType.equals(MessageUtil.MESSSAGE_TYPE_LINK)){ LinkMessage linkMessage= new LinkMessage(); linkMessage.setToUserName(fromUserName); linkMessage.setFromUserName(toUserName); linkMessage.setCreateTime( new Date().getTime()); linkMessage.setMsgType(MessageUtil.MESSSAGE_TYPE_LINK); linkMessage.setTitle(requestMap.get( "Title" )); linkMessage.setDescription(requestMap.get( "Description" )); linkMessage.setUrl(requestMap.get( "Url" )); respMessage = MessageUtil.linkMessageToXml(linkMessage); } //語音消息 else if (msgType.equals(MessageUtil.MESSSAGE_TYPE_VOICE)){ VoiceMessage voiceMessage= new VoiceMessage(); voiceMessage.setToUserName(fromUserName); voiceMessage.setFromUserName(toUserName); voiceMessage.setCreateTime( new Date().getTime()); voiceMessage.setMsgType(MessageUtil.MESSSAGE_TYPE_VOICE); voiceMessage.setMediaId(requestMap.get( "MediaId" )); voiceMessage.setFormat(requestMap.get( "Format" )); respMessage = MessageUtil.voiceMessageToXml(voiceMessage); } //事件推送 else if (msgType.equals(MessageUtil.MESSSAGE_TYPE_EVENT)){ //事件類型 String eventType = requestMap.get( "Event" ); //訂閱 if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)){ respContent = "謝謝關注!" ; } //取消訂閱 else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)){ // System.out.println( "取消訂閱" ); } else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)){ //自定義菜單消息處理 System.out.println( "自定義菜單消息處理" ); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return respMessage; } public static String getMainMenu() { StringBuffer buffer = new StringBuffer(); buffer.append( "您好,我是jon,請回復數字選擇服務:" ).append( "\n" ); buffer.append( "1、我的博客" ).append( "\n" ); buffer.append( "2、 歌曲點播" ).append( "\n" ); buffer.append( "3、 經典游戲" ).append( "\n" ); buffer.append( "4 、聊天打牌" ).append( "\n\n" ); buffer.append( "回復" + "0" + "顯示幫助菜單" ); return buffer.toString(); } } |
4)、MessageUtil.java幫助類,包括常量的定義和xml消息轉換和處理
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
|
package cn.jon.wechat.utils; import java.io.InputStream; import java.io.Writer; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import cn.jon.wechat.message.req.ImageMessage; import cn.jon.wechat.message.req.LinkMessage; import cn.jon.wechat.message.req.LocationMessage; import cn.jon.wechat.message.req.VideoMessage; import cn.jon.wechat.message.req.VoiceMessage; import cn.jon.wechat.message.resp.Article; import cn.jon.wechat.message.resp.MusicMessage; import cn.jon.wechat.message.resp.NewsMessage; import cn.jon.wechat.message.resp.TextMessage; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.core.util.QuickWriter; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; import com.thoughtworks.xstream.io.xml.XppDriver; /** * 各種消息的處理類 * @author jon */ public class MessageUtil { /** * 文本類型 */ public static final String MESSSAGE_TYPE_TEXT = "text" ; /** * 音樂類型 */ public static final String MESSSAGE_TYPE_MUSIC = "music" ; /** * 圖文類型 */ public static final String MESSSAGE_TYPE_NEWS = "news" ; /** * 視頻類型 */ public static final String MESSSAGE_TYPE_VIDEO = "video" ; /** * 圖片類型 */ public static final String MESSSAGE_TYPE_IMAGE = "image" ; /** * 鏈接類型 */ public static final String MESSSAGE_TYPE_LINK = "link" ; /** * 地理位置類型 */ public static final String MESSSAGE_TYPE_LOCATION = "location" ; /** * 音頻類型 */ public static final String MESSSAGE_TYPE_VOICE = "voice" ; /** * 推送類型 */ public static final String MESSSAGE_TYPE_EVENT = "event" ; /** * 事件類型:subscribe(訂閱) */ public static final String EVENT_TYPE_SUBSCRIBE = "subscribe" ; /** * 事件類型:unsubscribe(取消訂閱) */ public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe" ; /** * 事件類型:click(自定義菜單點擊事件) */ public static final String EVENT_TYPE_CLICK= "CLICK" ; /** * 解析微信發來的請求 XML */ @SuppressWarnings ( "unchecked" ) public static Map<String,String> pareXml(HttpServletRequest request) throws Exception { //將解析的結果存儲在HashMap中 Map<String,String> reqMap = new HashMap<String, String>(); //從request中取得輸入流 InputStream inputStream = request.getInputStream(); //讀取輸入流 SAXReader reader = new SAXReader(); Document document = reader.read(inputStream); //得到xml根元素 Element root = document.getRootElement(); //得到根元素的所有子節點 List<Element> elementList = root.elements(); //遍歷所有的子節點取得信息類容 for (Element elem:elementList){ reqMap.put(elem.getName(),elem.getText()); } //釋放資源 inputStream.close(); inputStream = null ; return reqMap; } /** * 響應消息轉換成xml返回 * 文本對象轉換成xml */ public static String textMessageToXml(TextMessage textMessage) { xstream.alias( "xml" , textMessage.getClass()); return xstream.toXML(textMessage); } /** * 語音對象的轉換成xml * */ public static String voiceMessageToXml(VoiceMessage voiceMessage) { xstream.alias( "xml" , voiceMessage.getClass()); return xstream.toXML(voiceMessage); } /** * 視頻對象的轉換成xml * */ public static String videoMessageToXml(VideoMessage videoMessage) { xstream.alias( "xml" , videoMessage.getClass()); return xstream.toXML(videoMessage); } /** * 音樂對象的轉換成xml * */ public static String musicMessageToXml(MusicMessage musicMessage) { xstream.alias( "xml" , musicMessage.getClass()); return xstream.toXML(musicMessage); } /** * 圖文對象轉換成xml * */ public static String newsMessageToXml(NewsMessage newsMessage) { xstream.alias( "xml" , newsMessage.getClass()); xstream.alias( "item" , new Article().getClass()); return xstream.toXML(newsMessage); } /** * 圖片對象轉換成xml * */ public static String imageMessageToXml(ImageMessage imageMessage) { xstream.alias( "xml" ,imageMessage.getClass()); return xstream.toXML(imageMessage); } /** * 鏈接對象轉換成xml * */ public static String linkMessageToXml(LinkMessage linkMessage) { xstream.alias( "xml" ,linkMessage.getClass()); return xstream.toXML(linkMessage); } /** * 地理位置對象轉換成xml * */ public static String locationMessageToXml(LocationMessage locationMessage) { xstream.alias( "xml" ,locationMessage.getClass()); return xstream.toXML(locationMessage); } /** * 拓展xstream,使得支持CDATA塊 * */ private static XStream xstream = new XStream( new XppDriver(){ public HierarchicalStreamWriter createWriter(Writer out){ return new PrettyPrintWriter(out){ //對所有的xml節點的轉換都增加CDATA標記 boolean cdata = true ; @SuppressWarnings ( "unchecked" ) public void startNode(String name,Class clazz){ super .startNode(name,clazz); } protected void writeText(QuickWriter writer,String text){ if (cdata){ writer.write( "<![CDATA[" ); writer.write(text); writer.write( "]]>" ); } else { writer.write(text); } } }; } }); } |
5)、BaseMessage.java消息基類(包括:開發者微信號、用戶賬戶、創建時間、消息類型、消息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
|
package cn.jon.wechat.message.req; /** * 消息基類 (普通用戶-公眾號) * @author jon */ public class BaseMessage { //開發者微信號 private String ToUserName; //發送方賬號(一個openId) private String FromUserName; //消息創建時間(整型) private long CreateTime; //消息類型(text/image/location/link...) private String MsgType; //消息id 64位整型 private String MsgId; public BaseMessage() { super (); // TODO Auto-generated constructor stub } public BaseMessage(String toUserName, String fromUserName, long createTime, String msgType, String msgId) { super (); ToUserName = toUserName; FromUserName = fromUserName; CreateTime = createTime; MsgType = msgType; MsgId = msgId; } 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 getMsgId() { return MsgId; } public void setMsgId(String msgId) { MsgId = msgId; } } |
6)、TextMessage.java文本消息,繼承自5中基類,擴展內容屬性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package cn.jon.wechat.message.req; /** * 文本消息 * @author jon */ public class TextMessage extends BaseMessage{ //消息內容 private String content; public String getContent() { return content; } public void setContent(String content) { this .content = content; } } |
7)、ImageMessage.java圖片消息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package cn.jon.wechat.message.req; /** * 圖片消息 * @author jon */ public class ImageMessage extends BaseMessage{ //圖片鏈接 private String PicUrl; public String getPicUrl() { return PicUrl; } public void setPicUrl(String picUrl) { PicUrl = picUrl; } } |
8)、VideoMessage.java視頻消息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package cn.jon.wechat.message.req; public class VideoMessage extends BaseMessage { private String mediaId; private String thumbMediaId; public String getMediaId() { return mediaId; } public void setMediaId(String mediaId) { this .mediaId = mediaId; } public String getThumbMediaId() { return thumbMediaId; } public void setThumbMediaId(String thumbMediaId) { this .thumbMediaId = thumbMediaId; } } |
其他消息類可根據開發者文檔自行進行完成,另外,開發者也可以申請公眾平臺測試賬號,對開發的相關內容進行測試。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。