# 微信公眾號自動回復功能開發
本篇主要講解 微信公眾號自動回復功能開發,讓我們自己去托管公眾號回復的功能,這樣可以更加靈活的根據公眾號收到的信息來制定特定的回復信息,一起來了解吧!
###  1.注冊公眾號
 如果你從來沒創建過請先注冊 [微信公眾平台](https://mp.weixin.qq.com/)
 請選擇訂閱號,然后填寫一些基本信息即可 ,具體注冊流程這里就展開說了。
 **注意 郵箱作為登錄帳號,請填寫未被微信公眾平台注冊,未被微信開放平台注冊,未被個人微信號綁定的郵箱 建議直接注冊一個新郵箱使用**

###  2.微信托管自動回復功能
 微信提供了自動回復功能,也就是直接在微信上配置
 **分別提供了3種配置 1.關鍵詞回復 2.收到消息回復 3.被關注回復**
 使用方法很簡單 只需要在對應的回復類型上面配置即可 這里不做詳細說明


###  3.自己開發服務托管自動回復功能
 本篇重點講解自己去托管自動回復功能,微信只做轉發
####   3.1 關閉微信的自動回復功能
  要想自己托管自動回復功能首先要講微信的自動回復功能關閉 關閉方式如下

####   3.2 開發者中心配置托管的服務器信息
  **在開始服務器端開發之前,我先介紹一個natapp 內網穿透工具**,有了它你可以直接將其本地映射一個地址配置到該URL地址上面,那么方便你調試 具體關於natapp的使用 請看我另一篇博客 [natapp 內網穿透工具](https://www.askajohnny.com/#/blog/111)
  主要配置URL地址 和Token信息 EncodingAESKey 可以隨機生成

####   3.3 服務端開發(驗證消息來來自微信服務器)
  開發者提交信息后,微信服務器將發送GET請求到填寫的服務器地址URL上,GET請求攜帶參數如下表所示:
參數 描述
signature 微信加密簽名,signature結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。
timestamp 時間戳
nonce 隨機數
echostr 隨機字符串
  開發者通過檢驗signature對請求進行校驗(下面有校驗方式)。若確認此次GET請求來自微信服務器,請原樣返回echostr參數內容,則接入生效,成為開發者成功,否則接入失敗。加密/校驗流程如下:
1)將token、timestamp、nonce三個參數進行字典序排序 2)將三個參數字符串拼接成一個字符串進行sha1加密 3)開發者獲得加密后的字符串可與signature對比,標識該請求來源於微信
**你也可以簡單粗暴的直接返回echostr 我暫時就是這樣做的**
/**
* 微信成為開發者 接口
* @param signature : 簽名
* @param timestamp : 時間戳
* @param nonce : 隨機數
* @param echostr : 隨機字符串
* @return
*/
@GetMapping("/authorize")
public String authorize(@RequestParam("signature") String signature,
@RequestParam("timestamp") Long timestamp,
@RequestParam("nonce") String nonce,
@RequestParam("echostr") String echostr) {
log.info("【signature:{}】", signature);
log.info("【timestamp:{}】", timestamp);
log.info("【nonce:{}】", nonce);
log.info("【echostr:{}】", echostr);
return echostr;
}
  在上圖中點擊提交微信會發送請求到該接口 只要該接口正確返回了echostr,微信公眾號管理平台就會如下顯示 提交成功

  微信驗證 開發者成功后點擊 啟用 服務器配置信息

####   3.4 服務器端開發 (接收消息)
  附上微信關於消息的開發文檔 [微信公眾平台開發文檔](https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html)
  當普通微信用戶向公眾賬號發消息時,微信服務器將POST消息的XML數據包到開發者填寫的URL上,也就是你剛剛配置的驗證接口的URL地址,只不過是POST方式提交,所以你需要寫一個POST接口
文本消息
<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
  **接受到的消息格式:**

  **封裝接收微信消息的實體**
  **這里我使用了 XStream 來解析XML** 它非常好用,不了解的自行百度 后期可能會寫一篇關於XStream的用法
@Data
@XStreamAlias("xml")
public class WxXmlData implements Serializable {
@XStreamAlias("ToUserName")
private String toUserName;
@XStreamAlias("FromUserName")
private String fromUserName;
@XStreamAlias("CreateTime")
private Long createTime;
@XStreamAlias("MsgType")
private String msgType;
@XStreamAlias("Content")
private String content;
@XStreamAlias("MsgId")
private String msgId;
//
@XStreamAlias("Title")
private String title;
@XStreamAlias("Description")
private String description;
@XStreamAlias("Url")
private String url;
/**
* 訂閱或者取消訂閱的事件
*/
@XStreamAlias("Event")
private String event;
@XStreamAlias("EventKey")
private String eventkey;
}
  從InputStream流中讀取到xml字符串(inputstream從 post接口的 request.getInputStream()獲取),然后通過XStream解析到封裝的實體對象WxXmlData中
@Override
public WxXmlData resolveXmlData(InputStream in) throws IOException {
String xmlData = FileUtils.getInputToString(in);
log.info("【receive xmlData str : {}】", xmlData);
WxXmlData wxXmlData = null;
try {
XStream xstream = new XStream();
//這個必須要加 不然無法轉換成WxXmlData對象
xstream.setClassLoader(WxXmlData.class.getClassLoader());
xstream.processAnnotations(WxXmlData.class);
xstream.alias("xml", WxXmlData.class);
wxXmlData = (WxXmlData) xstream.fromXML(xmlData);
log.info("【wxXmlData: {}】 ", wxXmlData);
} catch (Exception e) {
log.error("【error】{}", e.getMessage());
}
return wxXmlData;
}
  **編寫自動回復接口,這里有判斷 event,如果是訂閱可以做相應的回復,如果是 普通消息可以做相應的回復等等。。具體怎么實現回復邏輯看你自己的需求**
  **注意:你的回復的人是 發送給你消息的人**
@Override
public String autoResponse(WxXmlData wxData) {
WxXmlData resultXmlData = new WxXmlData();
resultXmlData.setToUserName(wxData.getFromUserName()); //收到的消息是誰發來的再發給誰
resultXmlData.setFromUserName(wxData.getToUserName()); //
if (!StringUtils.isEmpty(wxData.getEvent())) {
if (WxSubscribeEnum.SUBSCRIBE.getValue().equals(wxData.getEvent())) {
resultXmlData.setMsgType("text");
resultXmlData.setCreateTime(System.currentTimeMillis());
resultXmlData.setContent("歡迎來到Johnny屋,本公眾號會定期更新技術干貨,願與 讀者共同成長。\n\n" +
"-<a href=\"https://www.askajohnny.com\">我的博客(建議PC端打開,移動端適配正在緊張開發中)</a>");
}
} else if(wxData.getContent().equalsIgnoreCase("vip")){
resultXmlData.setMsgType("text");
resultXmlData.setCreateTime(System.currentTimeMillis());
resultXmlData.setContent("<a href=\"https://my.openwrite.cn/code/generate?blogId=18931-1576559666626-322\">點擊該鏈接,獲取博客解鎖驗證碼</a>");
} else {
resultXmlData.setMsgType("text");
resultXmlData.setCreateTime(System.currentTimeMillis());
resultXmlData.setContent("公眾號正在開發中。后期請多多關注!");
}
XStream xstream = new XStream();
xstream.processAnnotations(WxXmlData.class);
xstream.setClassLoader(WxXmlData.class.getClassLoader());
return xstream.toXML(resultXmlData); //XStream的方法,直接將對象轉換成 xml數據
**效果如下:**

### <a id="4_235"></a>4.總結
**本篇主要講解微信公眾號自動回復功能的開發,實現自己托管消息回復,能夠更加靈活的根據不同的消息進行回復,主要就是對XML的報文解析並且發送對應的報文即可,后期可能會有其他關於微信公眾號開發的文章包括 自定義菜單 等等 多多關注**