Spring Boot 開(kāi)發(fā)微信公眾號(hào)
在講微信公眾號(hào)開(kāi)發(fā)之前,先來(lái)大概了解一下微信公眾號(hào)。微信公眾號(hào)大體上可以分為服務(wù)號(hào)和訂閱號(hào),訂閱號(hào)和服務(wù)號(hào)的區(qū)別如下:
服務(wù)號(hào)可以申請(qǐng)微信支付功能。 服務(wù)號(hào)只能由企業(yè)申請(qǐng),訂閱號(hào)可以由企業(yè)或個(gè)人申請(qǐng)。 訂閱號(hào)和服務(wù)號(hào)每月推送消息次數(shù)不同,訂閱號(hào)每天可以推送一次,服務(wù)號(hào)每月可以推送四次。 服務(wù)號(hào)推送的消息會(huì)出現(xiàn)在用戶(hù)的聊天列表中,而訂閱號(hào)推送的消息顯示在訂閱號(hào)文件夾中。 還有一些其他接口功能的區(qū)別和限制,總的來(lái)說(shuō)服務(wù)號(hào)支持更高級(jí)的功能開(kāi)發(fā)。
訂閱號(hào)更加偏向于向用戶(hù)傳遞咨詢(xún),一般各種技術(shù)類(lèi)公眾號(hào)都屬于訂閱號(hào),訂閱號(hào)的消息推送并不會(huì)有太顯眼的提醒,如果你想讓某個(gè)公眾號(hào)的推送內(nèi)容更加顯眼,可以選擇將公眾號(hào)置為星標(biāo)。置為星標(biāo)后公眾號(hào)會(huì)顯示在所有訂閱號(hào)的最頂部,同時(shí)收到消息后會(huì)有黃色五角星星標(biāo)提醒。
一 公眾號(hào)配置服務(wù)器
微信官方提供了非常完善的接入文檔,如果想了解文檔的具體內(nèi)容,直接瀏覽器搜索微信開(kāi)發(fā)文檔就可以了。但是為了方便開(kāi)發(fā),一般不會(huì)直接去根據(jù)微信開(kāi)發(fā)文檔進(jìn)行開(kāi)發(fā),github上有許多開(kāi)源項(xiàng)目對(duì)微信開(kāi)發(fā)文檔進(jìn)行了封裝,這里我使用mica-weixin開(kāi)發(fā)包進(jìn)行演示,mica-weixin是jfinal-weixin的boot版本。
配置服務(wù)器信息很簡(jiǎn)單,具體流程就是微信服務(wù)發(fā)送請(qǐng)求一個(gè)請(qǐng)求給業(yè)務(wù)服務(wù)器,業(yè)務(wù)服務(wù)器驗(yàn)證請(qǐng)求后給微信服務(wù)一個(gè)響應(yīng)。
1.1 搭建業(yè)務(wù)服務(wù)
本地搭建一個(gè)spring-boot-weixin的項(xiàng)目,使用內(nèi)網(wǎng)穿透工具進(jìn)行穿透,使其可以與外網(wǎng)進(jìn)行通信。
1.1.1 引入mica-weixin依賴(lài)
<dependency>
<groupId>net.dreamlu</groupId>
<artifactId>mica-weixin</artifactId>
<version>2.0.1</version>
</dependency>
1.1.2 配置公眾號(hào)信息
mica-weixin通過(guò)配置文件進(jìn)行公眾號(hào)信息的配置:
dream:
weixin:
wx-configs:
- appId: xxxxxx
appSecret: xxxxxx
token: javatrip
encodingAesKey: xxxxxx
appId和appSecret可在公眾號(hào)后臺(tái)進(jìn)行查看,具體位置在菜單開(kāi)發(fā)—>基本配置中,其中appSecret要妥善保管,現(xiàn)在公眾號(hào)已經(jīng)不支持查看appSecret了,如果你忘了appSecret,只能進(jìn)行重置。
1.1.3 開(kāi)發(fā)消息校驗(yàn)接口
mica-weixin已經(jīng)為我們提供好了消息校驗(yàn)接口,只需要繼承DreamMsgControllerAdapter就可以了。
@WxMsgController("/weixin/wx")
public class WeiXinMsgController extends DreamMsgControllerAdapter {
@Override
protected void processInFollowEvent(InFollowEvent inFollowEvent) {
}
@Override
protected void processInTextMsg(InTextMsg inTextMsg) {
}
@Override
protected void processInMenuEvent(InMenuEvent inMenuEvent) {
}
}
同時(shí),需要開(kāi)啟緩存,由于mica-weixin的將access_token等信息放在了緩存中。在啟動(dòng)類(lèi)上加@EnableCaching就開(kāi)啟了。
@SpringBootApplication
@EnableCaching
public class WeixinApplication {
public static void main(String[] args) {
SpringApplication.run(WeixinApplication.class, args);
}
}
1.1.4 公眾號(hào)后臺(tái)配置服務(wù)器信息
使用內(nèi)網(wǎng)穿透工具穿透內(nèi)網(wǎng)地址,然后在公眾號(hào)后臺(tái)菜單開(kāi)發(fā)—>基本配置中填寫(xiě)服務(wù)器配置信息。

填寫(xiě)完成后點(diǎn)擊啟用,這樣就完成了微信服務(wù)器和業(yè)務(wù)服務(wù)器的關(guān)系配置。開(kāi)啟開(kāi)發(fā)者配置后,自動(dòng)回復(fù)、自定義菜單等功能都不能正常使用了。這時(shí)候就需要去調(diào)用對(duì)應(yīng)的接口實(shí)現(xiàn)這些功能。

二 實(shí)現(xiàn)各種消息接口
2.1 關(guān)注消息
在一步中,自定義類(lèi)WeiXinMsgController中需要重寫(xiě)三個(gè)父類(lèi)中的方法,其中processInFollowEvent()就是關(guān)注和取消關(guān)注的方法,取消關(guān)注后用戶(hù)雖然不能收到消息,但是后臺(tái)可以接收到用戶(hù)取消關(guān)注的事件。
@Override
protected void processInFollowEvent(InFollowEvent inFollowEvent) {
OutTextMsg defaultMsg = new OutTextMsg(inFollowEvent);
// 關(guān)注
if(InFollowEvent.EVENT_INFOLLOW_SUBSCRIBE.equals(inFollowEvent.getEvent())){
// 可將關(guān)注用戶(hù)錄入db,此處可以獲取到用戶(hù)openid
String openId = inFollowEvent.getFromUserName();
// 查詢(xún)db,根據(jù)響應(yīng)消息類(lèi)型封裝消息體
if("文本消息"){
OutTextMsg otm = new OutTextMsg(inFollowEvent);
otm.setContent("消息內(nèi)容");
render(otm);
return;
}else if("圖片消息"){
OutImageMsg oim = new OutImageMsg(inFollowEvent);
// 這里需要調(diào)用微信提供的素材接口,將圖片上傳至素材庫(kù)。
oim.setMediaId("圖片素材id");
render(oim);
return;
}else if("圖文消息"){
OutNewsMsg onm = new OutNewsMsg(inFollowEvent);
onm.addNews("標(biāo)題","簡(jiǎn)介","圖片地址","圖文鏈接");
render(onm);
return;
}else if("視頻消息"){
OutVideoMsg ovm = new OutVideoMsg(inFollowEvent);
ovm.setTitle("標(biāo)題");
ovm.setDescription("簡(jiǎn)介");
ovm.setMediaId("視頻素材id");
render(ovm);
return;
}else{
defaultMsg.setContent("感謝關(guān)注");
}
}
// 取消關(guān)注
if(InFollowEvent.EVENT_INFOLLOW_UNSUBSCRIBE.equals(inFollowEvent.getEvent())){
log.info("用戶(hù)取消關(guān)注了");
// 此處可以將取消關(guān)注的用戶(hù)更新db
}
}
2.2 關(guān)鍵詞消息
響應(yīng)內(nèi)容跟關(guān)注消息一樣,查詢(xún)db去匹配關(guān)鍵詞,然會(huì)根據(jù)消息內(nèi)容封裝對(duì)應(yīng)的消息體進(jìn)行返回,如果沒(méi)匹配到關(guān)鍵詞則回復(fù)統(tǒng)一的消息內(nèi)容。processInTextMsg()方法就是用來(lái)回復(fù)關(guān)鍵詞消息的。
@Override
protected void processInTextMsg(InTextMsg inTextMsg) {
String content = inTextMsg.getContent();
// 根據(jù)用戶(hù)發(fā)送的content去查詢(xún)db中的響應(yīng)內(nèi)容
if("文本消息"){
OutTextMsg otm = new OutTextMsg(inTextMsg);
otm.setContent("消息內(nèi)容");
render(otm);
return;
}else if("圖片消息"){
OutImageMsg oim = new OutImageMsg(inTextMsg);
// 這里需要調(diào)用微信提供的素材接口,將圖片上傳至素材庫(kù)。
oim.setMediaId("圖片素材id");
render(oim);
return;
}else if("圖文消息"){
OutNewsMsg onm = new OutNewsMsg(inTextMsg);
onm.addNews("標(biāo)題","簡(jiǎn)介","圖片地址","圖文鏈接");
render(onm);
return;
}else if("視頻消息"){
OutVideoMsg ovm = new OutVideoMsg(inTextMsg);
ovm.setTitle("標(biāo)題");
ovm.setDescription("簡(jiǎn)介");
ovm.setMediaId("視頻素材id");
render(ovm);
return;
}else{
OutTextMsg otm = new OutTextMsg(inTextMsg);
otm.setContent("暫未查到關(guān)鍵詞...");
}
}
2.3 菜單消息
點(diǎn)擊菜單后也是一樣,通過(guò)processInMenuEvent()方法進(jìn)行響應(yīng)內(nèi)容的回復(fù)。
@Override
protected void processInMenuEvent(InMenuEvent inMenuEvent) {
String eventKey = inMenuEvent.getEventKey();
// 根據(jù)用戶(hù)發(fā)送的content去查詢(xún)db中的響應(yīng)內(nèi)容
if("文本消息"){
OutTextMsg otm = new OutTextMsg(inMenuEvent);
otm.setContent("消息內(nèi)容");
render(otm);
return;
}else if("圖片消息"){
OutImageMsg oim = new OutImageMsg(inMenuEvent);
// 這里需要調(diào)用微信提供的素材接口,將圖片上傳至素材庫(kù)。
oim.setMediaId("圖片素材id");
render(oim);
return;
}else if("圖文消息"){
OutNewsMsg onm = new OutNewsMsg(inMenuEvent);
onm.addNews("標(biāo)題","簡(jiǎn)介","圖片地址","圖文鏈接");
render(onm);
return;
}else if("視頻消息"){
OutVideoMsg ovm = new OutVideoMsg(inMenuEvent);
ovm.setTitle("標(biāo)題");
ovm.setDescription("簡(jiǎn)介");
ovm.setMediaId("視頻素材id");
render(ovm);
return;
}else{
OutTextMsg otm = new OutTextMsg(inMenuEvent);
otm.setContent("無(wú)效鏈接,請(qǐng)重試...");
}
}
三 接口API調(diào)用
目前,微信提供的接口對(duì)訂閱號(hào)的限制比較大,未認(rèn)證的訂閱號(hào)基本上只有接收消息的幾個(gè)功能接口。
調(diào)用接口的時(shí)候需要傳遞token,獲取token需要在微信后臺(tái)中配置業(yè)務(wù)服務(wù)器的白名單。如下:
如果需要配置多個(gè)白名單ip,使用回車(chē)鍵將多個(gè)ip分隔開(kāi)。
mica-weixin提供了所有的接口封裝,具體可參考它的官方文檔,如果要獲取微信菜單,可以這樣寫(xiě):
@WxApi("weixin/api")
public class WeiXinApiController {
@GetMapping("menu")
@ResponseBody
public String getMenu(){
ApiResult menu = MenuApi.getMenu();
return menu.getJson();
}
}
@WxApi這個(gè)是它的自定義注解,其實(shí)就是包含了@RequestMapping和@Controller。
四 其他事項(xiàng)
4.1 多公眾號(hào)配置
mica-weixin提供了多公眾號(hào)配置的功能,使用ThreadLocal和appid進(jìn)行綁定。只需要簡(jiǎn)單配置即可實(shí)現(xiàn)多公眾號(hào)配置。
dream:
weixin:
wx-configs:
- appId: xxxxxx
appSecret: xxxxxx
token: javatrip
encodingAesKey: xxxxxx
- appId: xxxxxx
appSecret: xxxxxx
token: javatrip
encodingAesKey: xxxxxx
4.2 redis配置
access_token的有效期是2小時(shí),并且該接口有調(diào)用次數(shù)限制,mica-weixin將access_token存儲(chǔ)在redis中,避免每次調(diào)用接口都去獲取access-token,因此項(xiàng)目需要配置redis。
spring:
redis:
host: localhost
port: 6379
4.3 手動(dòng)選擇ThreadLocal
如果想要開(kāi)發(fā)微信公眾號(hào)的后臺(tái)管理功能,多公眾號(hào)的時(shí)候就需要手動(dòng)去指定當(dāng)前線程使用哪個(gè)公眾號(hào)信息。如下:
ApiConfigKit.setThreadLocalAppId(appid);
至此,SpringBoot開(kāi)發(fā)微信公眾號(hào)就算完成了,由于訂閱號(hào)開(kāi)放的接口太少了,好多功能不能正常演示。還有mica-weixin也許不是最好的選擇,如果想試著開(kāi)發(fā)微信公眾號(hào),可以在github上找一下開(kāi)發(fā)包。至于我為什么會(huì)使用mica-weixin,是因?yàn)槲以眠^(guò)一段時(shí)間的jfinal框架,與之配套的微信開(kāi)發(fā)包就是jfinal-weixin,也就是jfinal版的mica-weixin。
< END >
github:https://github.com/binzh303/spring-boot-route
1. 面試官:公司項(xiàng)目中Java的多線程一般用在哪些場(chǎng)景?
2. 微博千萬(wàn)級(jí)規(guī)模高性能高并發(fā)的網(wǎng)絡(luò)架構(gòu)設(shè)計(jì)
最近面試BAT,整理一份面試資料《Java面試BATJ通關(guān)手冊(cè)》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。
獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) Java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。
謝謝支持喲 (*^__^*)

