之前介紹了自動回復(fù),下面介紹一些常見的消息處理樣式
開始開發(fā)——關(guān)鍵字回復(fù)
功能描述
當(dāng)我們公眾號發(fā)送一些關(guān)鍵詞的時候,公眾號會回復(fù)自動回復(fù)有關(guān)關(guān)鍵詞的信息。
實現(xiàn)思路
- 消息類型為文本樣式
- 接收的客服端消息中要包含該關(guān)鍵字
代碼開發(fā)
為便于擴展,將消息處理的方法寫到服務(wù)層,新建收發(fā)信息的dto
一、便于擴展為不同類型的消息,修改收發(fā)消息的封裝,改用dto模式
- 基礎(chǔ)消息實體類
@Data
@XmlAccessorType(XmlAccessType.FIELD) // 映射類中的所有字段到XML
public class MsgSendEntity {
/**
* 公有部分
*/
// 開發(fā)者微信號
@XmlElement(name = "ToUserName") // 指定名稱映射
private String toUserName;
// 發(fā)送方帳號(一個OpenID)
@XmlElement(name = "FromUserName")
private String fromUserName;
// 消息創(chuàng)建時間 (整型)
@XmlElement(name = "CreateTime")
private Long createTime;
// 消息類型
@XmlElement(name = "MsgType")
private String msgType;
// 消息id,64位整型
@XmlElement(name = "MsgId")
private Long msgId;
}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class MsgReplyEntity {
// 用戶的OpenID
@XmlElement(name = "ToUserName")
private String toUserName;
// 測試號的微信號
@XmlElement(name = "FromUserName")
private String fromUserName;
// 消息創(chuàng)建時間 (整型)
@XmlElement(name = "CreateTime")
private Long createTime;
// 消息類型
@XmlElement(name = "MsgType")
private String msgType;
// 文本消息內(nèi)容
@XmlElement(name = "Content")
private String content;
}
- 新建消息實體類的dto
@Data
@XmlRootElement(name = "xml") // 根節(jié)點
@XmlAccessorType(XmlAccessType.FIELD) // 映射類中的所有字段到XML
public class MsgSendDto extends MsgSendEntity {
// 文本消息內(nèi)容
@XmlElement(name = "Content")
private String content;
}
@Data
@XmlRootElement(name="xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class MsgReplyDto extends MsgReplyEntity {
}
二、抽取消息處理的服務(wù)類與消息處理的方法到服務(wù)層
@Service
public class MsgHandleServiceImpl implements IMsgHandleService {
@Override
public MsgReplyEntity handle(MsgSendEntity msgSend) {
WeChatUtil.getLogger().info("客戶端接收的內(nèi)容為:{}"+msgSend);
// 服務(wù)端消息回復(fù)的實體類
MsgReplyEntity msgReply = new MsgReplyEntity();
// 根據(jù)接收的信息回復(fù),接收和發(fā)送方相反
msgReply.setFromUserName(msgSend.getToUserName());
msgReply.setToUserName(msgSend.getFromUserName());
msgReply.setCreateTime(new Date().getTime());
String msgType = msgSend.getMsgType();
String contentReply = null;
// 處理不同類型的消息
if (msgType.equals(WeChatConstants.MSG_TYPE_TEXT)) {
// 默認(rèn)回復(fù)相同的類型消息
msgReply.setMsgType(msgType);
String contentSend = msgSend.getContent();
// 關(guān)鍵詞處理
if (contentSend.contains("你好")) {
contentReply = "你好嗎\r\nhow are you";
} else if (contentSend.contains("哈哈")||contentSend.contains("haha")) {
contentReply = "我也喜歡哈哈大笑";
} else if (contentSend.contains("chet")){
msgReply.setMsgType(WeChatConstants.MSG_TYPE_NEWS);
//設(shè)置圖文個數(shù)
msgReply.setArticleCount(1);
//設(shè)置圖文明細列表
ArticleItem item = new ArticleItem();
item.setTitle("chet的github博客");
item.setPicUrl("https://chetwhy.github.io/");
item.setDescription("chet的掘金博客");
item.setUrl("https://juejin.im/timeline");
msgReply.setItem(new ArticleItem[]{item});
}else {
// 非關(guān)鍵字,原樣返回
contentReply = msgSend.getContent();
}
msgReply.setContent(contentReply);
}
WeChatUtil.getLogger().info("服務(wù)端回復(fù)的內(nèi)容為:{}"+msgReply);
return msgReply;
}
}
三、封裝的常量類
public class WeChatConstants {
/**
* 公眾號appid
*/
public static String APP_ID = "wxa02348cd5ec17d28";
/**
* AppSecret
*/
public static String APPSECRET = "***";
/**
* 公眾號配置相關(guān)
*/
public static final String URL = "ups.tiaodu.cn";
public static final String TOKEN = "123qwe";
/**
* 消息類型
*/
public static final String MSG_TYPE_TEXT = "text";
public static final String MSG_TYPE_NEWS = "news";
}
測試樣例
在手機微信或電腦微信直接發(fā)送帶【關(guān)鍵字】的信息即可
開始開發(fā)——接收事件推送
功能描述
微信公眾號有多種不同事件信息,包括其觸發(fā)事件的類型,響應(yīng)處理。最常見的,當(dāng)我們點擊關(guān)注某公眾號之后,公眾號將自動推送給我們介紹信息后者活動宣傳等。
實現(xiàn)思路
一、參考微信公眾平臺技術(shù)文檔->消息管理->接收事件推送
二、查看對應(yīng)消息事件格式,擴展消息實體的dto
三、在原消息基礎(chǔ)上,添加事件的邏輯判斷
下面以關(guān)注/取消事件和自定義菜單事件做演示
代碼開發(fā)
1為MsgSendDto添加事件屬性
...
public class MsgSendDto {
...
// 事件類型 subscribe(訂閱)、unsubscribe(取消訂閱)、CLICK(點擊菜單)
@XmlElement(name = "Event")
private String event;
}
2增加常量類
public class WeChatConstants {
...
public static final String MSG_TYPE_EVENT = "event";
public static final String MSG_TYPE_EVENT_SUBSCRIBE = "subscribe";
}
3消息處理方法,增加判斷邏輯
@Service
public class MsgHandleServiceImpl {
public MsgReplyEntity handle(MsgSendEntity msgSend) {
...
// 處理不同類型的消息
if (msgType.equals(WeChatConstants.MSG_TYPE_TEXT)) {
...
}else if(msgType.equals(WeChatConstants.MSG_TYPE_EVENT)){
// 訂閱事件
if(msgSend.getEvent().equals(WeChatConstants.MSG_TYPE_EVENT_SUBSCRIBE)){
msgReply.setMsgType(WeChatConstants.MSG_TYPE_TEXT);
msgReply.setContent("感謝關(guān)注chetwhy![親親]\r\n現(xiàn)在回復(fù)【chet】\r\n馬上查閱java博客![大兵]");
}
}
WeChatUtil.getLogger().info("服務(wù)端回復(fù)的內(nèi)容為:{}"+msgReply);
return msgReply;
}
}
測試樣例
一、先取消對測試公眾的關(guān)注(斷點調(diào)試依然可以看到消息類型為event)
二、在測試號管理中再次掃描二維碼關(guān)注
代碼開發(fā)
開始開發(fā)——自定義菜單及其事件
功能描述
當(dāng)我們點開一個訂閱的公共號時,點擊聊天輸入框最左側(cè)的按鈕,可以切換到公眾號的菜單欄,有的菜單選項中多個子菜單,有的菜單選擇會自動跳轉(zhuǎn)到其他頁面。這為我們的公眾號提供更為便捷的窗口和功能的擴展。
實現(xiàn)思路——自定義菜單
一、參考微信公眾平臺技術(shù)文檔->自定義菜單->【自定義菜單...接口】和消息管理->接收事件推送->[4-6菜單事件]
二、按照文檔,我們應(yīng)先創(chuàng)建自定義的菜單。簡單的說:
- 菜單分為一級菜單和二級菜單,一級最多3個,二級最多5個;
- 菜單借口大致有10種類型,分為按鈕(click,view),掃碼(scancode_push,scancode_waitmsg),拍照相冊(pic_sysphoto,pic_photo_or_album,pic_weixin),位置(location_select),文件(media_id)等
- post請求,https協(xié)議,請求參數(shù)需攜帶access_token
公眾平臺以access_token為接口調(diào)用憑據(jù),來調(diào)用接口,所有接口的調(diào)用需要先獲取access_token,access_token在2小時內(nèi)有效,過期需要重新獲取,但1天內(nèi)獲取次數(shù)有限,開發(fā)者需自行存儲
三、根據(jù)請求示例,封裝好我們自定義的json數(shù)據(jù)
四、根據(jù)文檔->獲取access_token,編寫工具類獲取返回的token
代碼開發(fā)
1封裝自定義菜單的json數(shù)據(jù)
{
"button":[
{
"type":"click",
"name":"今日歌曲",
"key":"V1001_TODAY_MUSIC"
},
{
"name":"菜單",
"sub_button":[
{
"type":"view",
"name":"搜索",
"url":"http://www.soso.com/"
},
{
"type":"miniprogram",
"name":"wxa",
"url":"http://mp.weixin.qq.com",
"appid":"wx286b93c14bbf93aa",
"pagepath":"pages/lunar/index"
},
{
"type":"click",
"name":"贊一下我們",
"key":"V1001_GOOD"
}]
}]
}
起名字費勁,我這里照搬的微信的菜單名,兩個按鈕型一級菜單,其中有兩個子菜單
2創(chuàng)建獲取access token的工具類方法
public class WeChatUtil {
// 獲取access_token的路徑模板
public static final String GET_ACCESSTOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
public static String accessToken;
public static long expiresTime;
/**
* 獲取access_token
* @return access_token
*/
public static String getAccessToken(){
// 第一次獲取或access token已過期
if(accessToken==null||new Date().getTime()>expiresTime){
// 替換示例種參數(shù),發(fā)送https的get請求
String result = HttpUtil.get(GET_ACCESSTOKEN_URL.replace("APPID", WeChatConstants.APP_ID).replace("APPSECRET", WeChatConstants.APPSECRET));
JSONObject json = JSONObject.parseObject(result);
accessToken = json.getString("access_token");
// 有效事件,單位秒
Long expires_in = json.getLong("expires_in");
// 設(shè)置憑據(jù)的失效時間,默認(rèn)7200s,提前五分鐘過期
expiresTime = new Date().getTime()+((expires_in-60*5)*1000);
WeChatUtil.getLogger().info("access_token={},expires_time={}",accessToken,expiresTime);
}
return accessToken;
}
}
3船艦自定菜單的工具類方法
public class WeChatUtil {
// 自定義菜單接口
public static final String CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
/**
* 創(chuàng)建自定義菜單
* @param menuJson
*/
public static void createMenu(String menuJson){
//發(fā)起請求到指定的接口,并且?guī)喜藛蝚son數(shù)據(jù)
String result = HttpUtil.post(CREATE_MENU_URL.replace("ACCESS_TOKEN",getAccessToken()), menuJson);
WeChatUtil.getLogger().info("創(chuàng)建自定義菜單結(jié)果:{}", result);
}
}
4.寫一個主方法,將之前封裝的json傳入createMenu方法。運行即可
public static void main(String[] args) {
String menu = "...";
createMenu(menu);
}
測試樣例
一、直接運行上述的main方法,查看運行日志,生成成功
二、查看微信客戶端的聊天頁面,點開二級菜單
三、若日志顯示成功,客戶端沒反應(yīng),嘗試重新關(guān)注訂閱號,或重啟natapp
實現(xiàn)思路——自定義菜單事件
一、封裝菜單事件的參數(shù),擴展dto
二、增加消息處理的業(yè)務(wù)邏輯
代碼開發(fā)
一、消息發(fā)送實體類
public class MsgSendDto extends MsgSendEntity {
...
// 菜單的key值
@XmlElement(name = "EventKey")
private String eventKey;
}
二、消息處理方法,key即為json中的"key"鍵
@Service
public class MsgHandleServiceImpl implements IMsgHandleService {
@Override
public MsgReplyEntity handle(MsgSendDto msgSend) {
...
// 處理不同類型的消息
if (msgType.equals(WeChatConstants.MSG_TYPE_TEXT)) {
...
}else if(msgType.equals(WeChatConstants.MSG_TYPE_EVENT)){
// 訂閱事件
if(msgSend.getEvent().equals(WeChatConstants.MSG_TYPE_EVENT_SUBSCRIBE)){
...
}else if(msgSend.getEvent().equals(WeChatConstants.MSG_TYPE_EVENT_CLICK)){
String eventKey = msgSend.getEventKey();
//判斷按鈕的key值
if ("V1001_TODAY_MUSIC".equals(eventKey)){
contentReply = "《年少有為》- 李榮浩\n" +
"《The Spectre》- Alan Walker";
}else if("V1001_GOOD".equals(eventKey)){
contentReply = "謝謝您的點贊關(guān)注[拇指]";
}
msgReply.setMsgType("text");
msgReply.setContent(contentReply);
}
}
WeChatUtil.getLogger().info("服務(wù)端回復(fù)的內(nèi)容為:{}"+msgReply);
return msgReply;
}
}
測試樣例
一、運行springboot
二、點開微信菜單欄,點擊菜單按鈕
開始開發(fā)——發(fā)送模板信息
功能描述
這個也很常見,比如當(dāng)我們在公眾號平臺購買商品后,平臺會發(fā)送下單結(jié)果的通知信息,這個類似與郵寄一樣,也是模板信息。文檔也說,模板消息僅用于公眾號向用戶發(fā)送重要的服務(wù)通知,只能用于符合其要求的服務(wù)場景中,如信用卡刷卡通知,商品購買成功通知等。
實現(xiàn)思路
一、參考微信公眾平臺技術(shù)文檔->消息管理->模板消息接口
二、在測試公眾號中配置新增模板
三、編寫工具類方法,支持https的post請求,url為:
https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=ACCESS_TOKEN
代碼開發(fā)
一、測試公眾號->模板消息接口->新增配置模板
我這里依然使用官方文檔的例子
如圖
)
二、封裝發(fā)送模板信息的json數(shù)據(jù),相關(guān)信息都改成自己的,template_id即上面的【模板ID】
{
"touser":"o50E15lhQXW0SlsYg3bKFrywtKC8",
"template_id":"RXl8FLezLbHaBrPWTwK295CNgkNpR69Et40K3oOoK0",
"url":"http://weixin.qq.com/download",
"miniprogram":{
"appid":"xiaochengxuappid12345",
"pagepath":"index?foo=bar"
},
"data":{
"first": {
"value":"恭喜你購買成功!",
"color":"#173177"
},
"keyword1":{
"value":"巧克力",
"color":"#173177"
},
"keyword2": {
"value":"39.8元",
"color":"#173177"
},
"keyword3": {
"value":"2014年9月22日",
"color":"#173177"
},
"remark":{
"value":"歡迎再次購買!",
"color":"#173177"
}
}
}
三、創(chuàng)建發(fā)送模板信息的方法
// 發(fā)送模板消息的接口
public static final String SEND_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
/**
* 發(fā)送模板信息
* @param data 模板json數(shù)據(jù)
*/
public static void sendTemplate(String data){
String result = HttpUtil.post(SEND_TEMPLATE_URL.replace("ACCESS_TOKEN", getAccessToken()),data);
WeChatUtil.getLogger().info("發(fā)送模板消息結(jié)果:{}",result);
}
測試樣例
使用第二步的json數(shù)據(jù),直接在main方法測試即可
詳細過程,可參考源代碼(持續(xù)更新):https://github.com/chetwhy/cloud-flow