原文: 微信開發(fā)四篇
date: 2017-11-02 12:39:04
[TOC]
序言
上一篇微信相關(guān)的開發(fā)是《基于WEB微信通信實現(xiàn)智能聊天機器人》.
而怎么保持機器人穩(wěn)定在線, 不被微信封號, 是一直遺留的問題…
網(wǎng)上一個穩(wěn)定版本的IOS微信協(xié)議已經(jīng)賣到2000! 所以無力研究了.
相比之下, 微信公眾號開發(fā)和小程序更加火爆.
本篇將通過微信公眾平臺, 微信開放平臺, 微信商戶平臺. 分為四篇來完成以下幾個常用功能.
第一篇: 微信網(wǎng)頁授權(quán)
第二篇: 微信支付
第三篇: 網(wǎng)站應(yīng)用微信登錄
第四篇: 推送微信模版消息
相關(guān)文檔 (必須了解)
- 微信公眾平臺技術(shù)文檔: https://mp.weixin.qq.com/wiki
- 微信支付開發(fā)文檔(公眾號支付): https://pay.weixin.qq.com/wiki/doc/api/index.html
- 微信開放平臺: https://open.weixin.qq.com/
使用SDK (開發(fā)效率事半功倍)
- 微信支付、小程序、公眾號&企業(yè)號開發(fā)Java SDK: https://github.com/Wechat-Group/weixin-java-tools
- 可能是目前最好的支付SDK: https://github.com/Pay-Group/best-pay-sdk
你需要知道的事
通過閱讀微信公眾平臺文檔: 可以知道公眾平臺賬號分為:
- 訂閱號
- 服務(wù)號
- 企業(yè)號
每類賬號的適用人群不同, 開放的接口權(quán)限不同, 申請門檻也不同.
公眾號接口權(quán)限說明
可以看到, 微信授權(quán)和支付功能這兩項權(quán)限只有微信認(rèn)證服務(wù)號才有.
服務(wù)號一般人沒有企業(yè)資質(zhì)很難申請到, 更別說微信認(rèn)證了.
好的一點是微信公眾平臺提供了一個測試號, 可以通過手機掃描二維碼來獲得測試號.
申請地址: https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
注意: 測試公眾號有很多體驗接口, 包括網(wǎng)頁授權(quán)獲取(無支付權(quán)限).
你需要準(zhǔn)備
微信開發(fā)需要手機電腦來回調(diào)試, 過程還是比較繁瑣. 如何在本地方便的進(jìn)行調(diào)試, 就要依賴一些東西.
域名
微信網(wǎng)頁授權(quán)的回調(diào)地址不能是ip地址. 這一點在官方文檔中有提到. 所以在回調(diào)到我們的應(yīng)用程序接口時要支持
域名/接口路徑
的方式, 例如:http://thank.mynatapp.cc/wechat/xxx
內(nèi)網(wǎng)映射
在手機上調(diào)試微信客戶端時, 調(diào)用PC接口, 肯定無法用http://localhost:8888/wechat/xxx
的方式了, 為了在本地方便的調(diào)試, 就需要用到內(nèi)網(wǎng)穿透工具. 可以參考我的另一篇: 內(nèi)網(wǎng)穿透介紹-
抓包工具
在手機上點擊時, 無法像電腦瀏覽器中的F12一樣看到詳細(xì)的網(wǎng)絡(luò)請求.所以使用fiddler或charles等抓包工具來抓取網(wǎng)絡(luò)請求.
手機Wi-Fi中的HTTP代理中填寫主機的ip地址和8888端口(默認(rèn))即可.
-
微信web開發(fā)者工具
這是微信官方提供給開發(fā)者的工具, 很方便.
不用下載抓包工具, 也不用設(shè)置手機代理.
可以像電腦瀏覽器一樣模擬手機發(fā)送請求. 支持公眾號網(wǎng)頁調(diào)試和小程序調(diào)試.
微信開發(fā)-開發(fā)者工具注意: 微信支付相關(guān)的調(diào)試在授權(quán)時需要在微信公眾平臺的賬號中綁定開發(fā)者.
第一篇: 微信網(wǎng)頁授權(quán)
網(wǎng)頁授權(quán)是指用戶在微信客戶端訪問第三方網(wǎng)頁時, 公眾號可通過授權(quán)機制來獲取用戶的基本信息. 從而實現(xiàn)業(yè)務(wù)邏輯.
授權(quán)流程: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
通過了解授權(quán)流程, 可以看到. 網(wǎng)頁授權(quán)流程主要分為四步:
- 引導(dǎo)用戶進(jìn)入授權(quán)頁面同意授權(quán),獲取code
- 通過code換取網(wǎng)頁授權(quán)access_token(與基礎(chǔ)支持中的access_token不同)
- 如果需要,開發(fā)者可以刷新網(wǎng)頁授權(quán)access_token, 避免過期
- 通過網(wǎng)頁授權(quán)access_token和openid獲取用戶基本信息(支持UnionID機制)
主要來看前2步:
# 替換相關(guān)參數(shù),相關(guān)參數(shù)說明在文檔中有詳細(xì)介紹...
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
# 例如:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxdcb894a6a375ed25&redirect_uri=http://thank.mynatapp.cc/sell/weixin/auth&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect
在微信客戶端訪問該url后, 會進(jìn)行跳轉(zhuǎn), redirect_uri
會重定向到我們的應(yīng)用.
在跳轉(zhuǎn)之前, 需要用戶同意授權(quán). 而用戶同意授權(quán)的方式, 取決于上面的 scope
參數(shù):
snsapi_base: 靜默授權(quán), 微信端用戶會在無感知的情況下同意授權(quán), 但是拿到的信息也較少, 只有用戶openid.
-
snsapi_userinfo: 微信端會彈出授權(quán)頁面點擊確認(rèn). 這種情況下拿到的openid可以再繼續(xù)拿到用戶的更多信息
如昵稱, 性別, 所在地等.
當(dāng)微信客戶端用戶同意授權(quán)后, 頁面將跳轉(zhuǎn)路徑為: redirect_uri/?code=CODE&state=STATE
也就是攜帶著code參數(shù)進(jìn)入我們的應(yīng)用接口中, 從而在應(yīng)用接口中獲取到code.
code作為換取access_token的票據(jù),每次用戶授權(quán)帶上的code將不一樣,code只能使用一次,5分鐘未被使用自動過期。
編碼實現(xiàn)
@GetMapping("/auth")
public void auth(@RequestParam("code") String code){
//第一步: 用戶同意授權(quán), 通過回調(diào), 進(jìn)入該方法, 獲取到code
log.info("-----進(jìn)入auth方法: code={}", code);
//第二步:通過code換取網(wǎng)頁授權(quán)access_token
String getTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
+appid+"&secret="
+appsecret+"&code="
+code+"&grant_type=authorization_code";
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(getTokenUrl, String.class);
log.info("-----response={}", response );
Map<String, Object> map = new Gson().fromJson(response,
new TypeToken<HashMap<String,Object>>(){}.getType());
log.info("--- accessToken={}", map.get("access_token"));
log.info("--- openid={}", map.get("openid"));
log.info("--- scope={}", map.get("scope"));
}
授權(quán)過程是可以用手工編寫代碼來完成, 但比較繁瑣. 而github上有很多現(xiàn)成的SDK提供, 所以不需要重復(fù)造輪子.
sdk實現(xiàn)
Github地址: 微信支付、小程序、企業(yè)號和公眾號(包括服務(wù)號和訂閱號) Java SDK開發(fā)工具包
-
Maven依賴
<dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-mp</artifactId> <version>2.7.0</version> </dependency>
-
完成微信公眾號相關(guān)配置讀取
@Component public class WechatMpConfig { // 配置讀取類 @Autowired private WechatAccountConfig wechatAccountConfig; @Bean public WxMpService wxMpService(){ WxMpService wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(wxMpConfigStorage()); return wxMpService; } @Bean public WxMpConfigStorage wxMpConfigStorage(){ WxMpInMemoryConfigStorage wxMpConfigStorage = new WxMpInMemoryConfigStorage(); wxMpConfigStorage.setAppId(wechatAccountConfig.getMpAppId()); wxMpConfigStorage.setSecret(wechatAccountConfig.getMpAppSecret()); return wxMpConfigStorage; } }
-
找到該項目的github 開發(fā)wiki: 公眾號開發(fā) -> OAuth2網(wǎng)頁授權(quán)
授權(quán)過程分為這幾步:
-
首先構(gòu)造網(wǎng)頁授權(quán)url,然后構(gòu)成超鏈接讓用戶點擊
wxMpService.oauth2buildAuthorizationUrl(redirectURI, WxConsts.OAUTH2_SCOPE_USER_INFO, URLEncoder.encode(returnUrl));
該方法返回一個url, 讓微信客戶端用戶點擊, 當(dāng)用戶同意授權(quán), 會回調(diào)至設(shè)置的redirectURI. 并把code攜帶過去. 用戶點擊的頁面如下:
微信開發(fā)-用戶點擊授權(quán)WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code); String openid = wxMpOAuth2AccessToken.getOpenId();
再通過該方法獲取openid. (除了openid以外, 還可以獲得用戶其它信息), 如下圖:
WxMpUser wxMpUser = this.wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, null);
微信開發(fā)-獲取用戶信息
第二篇: 微信支付
雖然微信官方有提供SDK和DEMO, 但是并不好用
這款SDK是在github中找的, 里面有很詳細(xì)的視頻說明, 而且還提供支付賬號借用, 對于拿不到公眾號認(rèn)證資格的開發(fā)者來說很方便學(xué)習(xí).
<!--微信支付相關(guān)SDK-->
<dependency>
<groupId>cn.springboot</groupId>
<artifactId>best-pay-sdk</artifactId>
<version>1.1.0</version>
</dependency>
支付流程
下面來描述一個最基本的支付流程, 包括以下幾個環(huán)節(jié):
- 統(tǒng)一下單
- 微信客戶端H5支付
- 接收微信異步通知
- 退款
1. 統(tǒng)一下單API
應(yīng)用場景
除被掃支付場景以外,商戶系統(tǒng)先調(diào)用該接口在微信支付服務(wù)后臺生成預(yù)支付交易單,返回正確的預(yù)支付交易回話標(biāo)識后再按掃碼、JSAPI、APP等不同場景生成交易串調(diào)起支付。
-
配置WxPayH5Config
@Component public class WechatPayConfig { // 配置讀取類 @Autowired private WechatAccountConfig accountConfig; @Bean public BestPayServiceImpl bestPayService() { BestPayServiceImpl bestPayService = new BestPayServiceImpl(); bestPayService.setWxPayH5Config(wxPayH5Config()); return bestPayService; } @Bean public WxPayH5Config wxPayH5Config() { WxPayH5Config wxPayH5Config = new WxPayH5Config(); wxPayH5Config.setAppId(accountConfig.getMpAppId()); wxPayH5Config.setAppSecret(accountConfig.getMpAppSecret()); wxPayH5Config.setMchId(accountConfig.getMchId()); wxPayH5Config.setMchKey(accountConfig.getMchKey()); wxPayH5Config.setKeyPath(accountConfig.getKeyPath()); wxPayH5Config.setNotifyUrl(accountConfig.getNotifyUrl()); return wxPayH5Config; } }
-
設(shè)置發(fā)起支付的相關(guān)參數(shù)
PayRequest
, 調(diào)用創(chuàng)建支付接口PayResponse payResponse = this.bestPayService.pay(payRequest);
這樣就完成了生成預(yù)付單.
payResponse
返回結(jié)果中攜帶預(yù)付單信息(prepay_id及其他信息)
2. 微信內(nèi)H5調(diào)起支付
注意: 必須在微信客戶端瀏覽器中
下單的返回對象 payResponse
會返回 getBrandWCPayRequest
中的參數(shù)
參數(shù)列表詳細(xì)描述:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":"wx2421b1c4370ec43b", //公眾號名稱,由商戶傳入
"timeStamp":"1395712654", //時間戳,自1970年以來的秒數(shù)
"nonceStr":"e61463f8efa94090b1f366cccfbbb444", //隨機串
"package":"prepay_id=u802345jgfjsdfgsdg888",
"signType":"MD5", //微信簽名方式:
"paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功后返回 ok,但并不保證它絕對可靠。
}
);
}
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
此時在微信客戶端生成JSAPI頁面, 用戶點擊即可發(fā)起支付.
關(guān)于支付成功的判斷
后臺的商戶系統(tǒng)通常會根據(jù)支付狀態(tài)去修改商品的狀態(tài), 庫存等.
如何判斷用戶是否支付成功呢?
在H5調(diào)起支付中, 網(wǎng)頁支付接口中在完成后會返回 err_msg
.
返回值 | 描述 |
---|---|
get_brand_wcpay_request:ok | 支付成功 |
get_brand_wcpay_request:cancel | 支付過程中用戶取消 |
get_brand_wcpay_request:fail | 支付失敗 |
但是這種方式并不可靠, 微信團隊也有說明.
所以, 可靠的方式是通過微信返回給我們的支付結(jié)果通知 .
3. 支付結(jié)果通知API
-
微信異步通知
支付完成后,微信會把相關(guān)支付結(jié)果和用戶信息發(fā)送給商戶,商戶需要接收處理,并返回應(yīng)答。
注意微信的異步通知需要設(shè)置 notify_url , 否則無法接收.
關(guān)于
notify_url
: 微信沒有設(shè)置白名單, 所以只要外網(wǎng)能訪問到的地址即可.例如: http://thank.mynatapp.cc/wechat/pay/notify
微信返回給商戶系統(tǒng)的數(shù)據(jù)如下: (SUCCESS情況下)
<xml> <appid><![CDATA[wx2421b1c4370ec43b]]></appid> <attach><![CDATA[支付測試]]></attach> <bank_type><![CDATA[CFT]]></bank_type> <fee_type><![CDATA[CNY]]></fee_type> <is_subscribe><![CDATA[Y]]></is_subscribe> <mch_id><![CDATA[10000100]]></mch_id> <nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str> <openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid> <out_trade_no><![CDATA[1409811653]]></out_trade_no> <result_code><![CDATA[SUCCESS]]></result_code> <return_code><![CDATA[SUCCESS]]></return_code> <sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign> <sub_mch_id><![CDATA[10000100]]></sub_mch_id> <time_end><![CDATA[20140903131540]]></time_end> <total_fee>1</total_fee> <trade_type><![CDATA[JSAPI]]></trade_type> <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id> </xml>
具體的參數(shù)信息在官方API中都有詳細(xì)描述
接受到微信異步通知后, 通過SDK來接收微信支付結(jié)果消息
// 1. 驗證簽名 (SDK已做) // 2. 驗證支付狀態(tài) (SDK已做) PayResponse payResponse = this.bestPayService.asyncNotify(notifyData); // 3. 商戶系統(tǒng)自己做驗證金額, 支付人等處理. // 4. 驗證完成后即可修改商品和訂單的相關(guān)狀態(tài) // 5. 返回微信處理結(jié)果
-
商戶同步返回處理結(jié)果
商戶系統(tǒng)在接收到微信的異步通知后, 就可以進(jìn)行商品狀態(tài)/庫存修改等操作了,
處理完成后需要告訴微信處理結(jié)果, 否則微信會一直發(fā)送異步通知過來.
<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> </xml>
4. 申請退款A(yù)PI
當(dāng)交易發(fā)生之后一段時間內(nèi),由于買家或者賣家的原因需要退款時,賣家可以通過退款接口將支付款退還給買家,微信支付將在收到退款請求并且驗證成功之后,按照退款規(guī)則將支付款按原路退到買家?guī)ぬ柹稀?/p>
與統(tǒng)一下單接口很類似, 不同的是申請退款請求需要雙向證書, 開發(fā)者需要微信商戶平臺下載相關(guān)證書文件.
# 設(shè)置RefundRequest
RefundResponse refundResponse = this.bestPayService.refund(refundRequest);
第三篇: 微信登錄功能
這里介紹網(wǎng)站應(yīng)用的微信登錄功能, 該功能是在微信開放平臺下.
網(wǎng)站應(yīng)用微信登錄是基于OAuth2.0協(xié)議標(biāo)準(zhǔn)構(gòu)建的微信OAuth2.0授權(quán)登錄系統(tǒng).
微信OAuth2.0授權(quán)登錄是讓微信用戶以微信身份安全登錄第三方應(yīng)用或網(wǎng)站.
掃碼登錄體驗: 一號店
需要注意!
- 微信登錄相關(guān)的授權(quán)除了要有開放平臺開發(fā)者賬號, 還需要用戶號有企業(yè)資質(zhì)的認(rèn)證. 普通賬號無法授權(quán)!
- 開放平臺的授權(quán)流程和公眾平臺類似, 但是
AppID
和AppSecret
不同, 所以獲得的openid
也不同. - 每個用戶針對每個公眾號會產(chǎn)生一個安全的
OpenID
. 一個微信號在不同公眾號下的openid
是不同的
授權(quán)流程
- 第三方發(fā)起微信授權(quán)登錄請求,微信用戶允許授權(quán)第三方應(yīng)用后,微信會拉起應(yīng)用或重定向到第三方網(wǎng)站,并且?guī)鲜跈?quán)臨時票據(jù)code參數(shù);
- 通過code參數(shù)加上AppID和AppSecret等,通過API換取access_token;
- 通過access_token進(jìn)行接口調(diào)用,獲取用戶基本數(shù)據(jù)資源或幫助用戶實現(xiàn)基本操作。
詳細(xì)的流程參考開發(fā)指南, 這里我使用sdk方式:best-pay-sdk
sdk實現(xiàn)
首先完成微信開放平臺相關(guān)配置, 配置 AppID
和 AppSecret
@Component
public class WechatOpenConfig {
// 配置讀取類
@Autowired
private WechatAccountConfig wechatAccountConfig;
@Bean
public WxMpService wxOpenService(){
WxMpService wxOpenService = new WxMpServiceImpl();
wxOpenService.setWxMpConfigStorage(wxOpenConfigStorage());
return wxOpenService;
}
@Bean
public WxMpConfigStorage wxOpenConfigStorage(){
WxMpInMemoryConfigStorage wxMpInMemoryConfigStorage = new WxMpInMemoryConfigStorage();
wxMpInMemoryConfigStorage.setAppId(wechatAccountConfig.getOpenAppId());
wxMpInMemoryConfigStorage.setSecret(wechatAccountConfig.getOpenAppSecret());
return wxMpInMemoryConfigStorage;
}
}
第一步: 請求code
用戶向第三方應(yīng)用發(fā)起登錄請求:
@GetMapping("qrAuthorize")
public String qrAuthorize(@RequestParam("state") String state){
String redirectUrl = this.projectUrlConfig.getWechatOpenAuthorize()
+ "/wechat/qrUserInfo";
String qrPageUrl = wxOpenService.buildQrConnectUrl(redirectUrl,
WxConsts.QRCONNECT_SCOPE_SNSAPI_LOGIN, state);
return "redirect:" + qrPageUrl;
}
跳轉(zhuǎn)至微信登錄的二維碼界面, 等待用戶掃碼授權(quán)后, 會重定向到 redirectUrl
, 并攜帶 code
和 state
參數(shù).
redirect_uri?code=CODE&state=STATE
第二步: 通過code換取access_token
@GetMapping("qrUserInfo")
public String qrUserInfo(@RequestParam("code") String code,
@RequestParam("state") String state) {
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken();
try {
wxMpOAuth2AccessToken = this.wxOpenService.oauth2getAccessToken(code);
} catch (WxErrorException e) {
log.error("[微信網(wǎng)頁授權(quán)錯誤: {}]", e);
}
log.info("state={}", state);
log.info("wxMpOAuth2AccessToken={}", wxMpOAuth2AccessToken);
log.info("accessToken={}", wxMpOAuth2AccessToken.accessToken);
log.info("openid={}", wxMpOAuth2AccessToken.getOpenId());
return "redirect:";
}
獲取到用戶的 openid
, 授權(quán)完成.
第四篇: 微信模版消息推送
這里用到微信公眾平臺中消息管理功能.
模板消息僅用于公眾號向用戶發(fā)送重要的服務(wù)通知,只能用于符合其要求的服務(wù)場景中,如信用卡刷卡
通知,商品購買成功通知等。不支持廣告等營銷類消息以及其它所有可能對用戶造成騷擾的消息。
官方文檔: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277
通過閱讀文檔: 這種容易產(chǎn)生騷擾, 欺騙功能的接口肯定還是需要公眾賬號, 認(rèn)證服務(wù)號的.
還好的一點是測試號有模版消息(業(yè)務(wù)通知)的接口. 所以這里我用測試賬號.
1. 設(shè)置模版
在公眾號管理中添加模版(測試號也類似)
模版標(biāo)題: 隨意填寫
-
模版內(nèi)容: 如果是公眾號可以選擇現(xiàn)有的模版, 測試號只能自己輸入(需要遵循格式), 例如:
{{first.DATA}} 收款方:{{keyword1.DATA}} 支付方:{{keyword2.DATA}} 支付方式:{{keyword3.DATA}} 交易狀態(tài):{{keyword4.DATA}} {{remark.DATA}}
模版ID: 自動生成(用于接口調(diào)用)
2. 發(fā)送模版消息
http請求方式: POST
https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
post發(fā)送模版內(nèi)容data數(shù)據(jù)
使用sdk 實現(xiàn)
@Autowired
private WxMpService wxMpService;
public void pushTemplateMessage() {
String templateId = "f-wEkgooC6My0792dHeoEZ-Zd85cOXYJShMB45sCdV4";
String openId = "ol4h7wot1fneGq1RN0LfWaNBtsYQ";
WxMpTemplateMessage templateMessage = new WxMpTemplateMessage();
templateMessage.setTemplateId(templateId);
templateMessage.setToUser(openId);
List<WxMpTemplateData> data = Arrays.asList(
new WxMpTemplateData("first", "微信支付憑證哈哈哈!"),
new WxMpTemplateData("keyword1", "謝謝謝", "#173177"),
new WxMpTemplateData("keyword2", "可口可樂"),
new WxMpTemplateData("keyword3", "支付寶轉(zhuǎn)賬"),
new WxMpTemplateData("keyword4", "$10000 欠款未付", "#CD2626"),
new WxMpTemplateData("remark", "歡迎再次購買!")
);
templateMessage.setData(data);
try {
wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
} catch (WxErrorException e) {
log.error("微信模版消息發(fā)送失敗, {}", e);
}
}
用了SDK, 就非常簡單吧! 效果如圖: