目錄
概述
公眾號給關(guān)注用戶推送自定義消息
一、申請公眾號模板消息
二、獲取安裝“web開發(fā)者工具”
三、微信網(wǎng)頁授權(quán)說明
四、微信網(wǎng)頁授權(quán) - 流程時序圖
五、HTTPClient 實現(xiàn)微信公眾號消息推送與發(fā)布(四步走)
六、通過weixin-java-mp SDK實現(xiàn)微信公眾號消息推送與發(fā)布(七步走)
七、抽取與封裝
概述
本篇文章主要基于Java+Spring Boot+Spring Cloud的應(yīng)用中接入微信公眾號,調(diào)用微信的JavaSDK > weixin-java-mp進(jìn)行應(yīng)用消息推送,實現(xiàn)業(yè)務(wù)數(shù)據(jù)推送到指定的微信用戶客戶端。通過本篇博客,將快速上手,從0到1構(gòu)建起消息推送與發(fā)布。
公眾號給關(guān)注用戶推送自定義消息
一、申請公眾號模板消息
1、開通微信公眾號平臺的“模板消息”欄
提交申請:
添加功能插件>功能詳情>申請開通模板接口> 填寫業(yè)務(wù)服務(wù)目標(biāo)所屬的行業(yè),申請理由,
如果是新申請的消息模板,需要注意規(guī)范,否則會被封號的可能!??!
等待審核通過就可以使用了!
“模板消息”開通審核通過后,在微信公眾號平臺>左邊欄>廣告與服務(wù)>就可以看到模板消息欄了,
接著,就可以添加用于業(yè)務(wù)系統(tǒng)推送公眾號的模板消息內(nèi)容了,
如下圖:?
?添加完成后,就可以在,模板消息>我的模板,中進(jìn)行查看了,如下圖:
關(guān)于推送的模板消息內(nèi)容,用兩種定義方式:
1、用公眾號模板庫已經(jīng)存在的,也就是別人之前申請過的,
2、如果在模板消息庫中檢索不到符合當(dāng)下業(yè)務(wù)系統(tǒng)需求的消息模板內(nèi)容,則可以自定義,在模板庫中選擇“幫助我們完善模板庫”
如下圖:
?添加自定義的微信公眾號模板的內(nèi)容的注意事項:
1、添加模版前,需要先仔細(xì)閱讀《模版消息申請?zhí)砑忧氨刈x指引》。請勿違反運營規(guī)則,否則可能被停用模版消息接口甚至封號的可能;
2、貢獻(xiàn)新模版需要等待“7-15”天審核期,且內(nèi)容可能被審核人員修改。每月只可申請新建3個新模版;
3、審核通過后,模版將放入模版庫以供他人使用,會被官方共享出去,也就是這里的消息模板,沒有私有這一說,之前博主的客戶提需求,說必須要私有的,不能共享,因為這不是自己能控制的,遂進(jìn)行了多輪溝通后最終才說服了客戶;
二、獲取安裝“web開發(fā)者工具”
《web開發(fā)者工具穩(wěn)定版下載》
微信web開發(fā)者工具,安裝完成后,打開應(yīng)用程序,選擇“公眾號網(wǎng)頁項目”,
如下圖;
為公眾號綁定開發(fā)者:
如果出現(xiàn) “?該微信用戶未開啟“公眾號安全助手”的消息接收功能,請先開啟后再綁定 ”
參考:
《該微信用戶未開啟“公眾號安全助手”的消息接收功能,請先開啟后再綁定》
邀請綁定,
設(shè)置完成后,再次邀請綁定即可完成綁定了,如下圖:
綁定成功后,再打開,微信公眾號平臺>設(shè)置與開發(fā)>開發(fā)者工具>選擇“web開發(fā)者工具”>如下圖(web開發(fā)者工具最多可綁定50人),
如下圖:
三、微信網(wǎng)頁授權(quán)說明
1、微信開發(fā)網(wǎng)頁授權(quán)五步走
第一步:用戶同意授權(quán),獲取code
在確保微信公眾賬號擁有授權(quán)作用域(scope參數(shù))的權(quán)限的前提下(已認(rèn)證服務(wù)號,默認(rèn)擁有 scope 參數(shù)中的snsapi_base和snsapi_userinfo 權(quán)限),引導(dǎo)關(guān)注者打開如下頁面:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
若提示“該鏈接無法訪問”,請檢查參數(shù)是否填寫錯誤,是否擁有 scope 參數(shù)對應(yīng)的授權(quán)作用域權(quán)限。
注意:由于授權(quán)操作安全等級較高,所以在發(fā)起授權(quán)請求時,微信會對授權(quán)鏈接做正則強(qiáng)匹配校驗,如果鏈接的參數(shù)順序不對,授權(quán)頁面將無法正常訪問,跳轉(zhuǎn)回調(diào)redirect_uri,應(yīng)當(dāng)使用 https 鏈接來確保授權(quán) code 的安全性。
參考鏈接(請在微信客戶端中打開此鏈接體驗):
scope為snsapi_base:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect
scope為snsapi_userinfo:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
用戶同意授權(quán)后
如果用戶同意授權(quán),頁面將跳轉(zhuǎn)至 redirect_uri/?code=CODE&state=STATE。
code說明:
code作為換取access_token的票據(jù),每次用戶授權(quán)帶上的 code 將不一樣,code只能使用一次,5分鐘未被使用自動過期。
請求參數(shù)說明:
回調(diào)錯誤碼說明:
第二步:通過 code 換取網(wǎng)頁授權(quán)access_token
首先請注意,這里通過 code 換取的是一個特殊的網(wǎng)頁授權(quán)access_token,與基礎(chǔ)支持中的access_token(該access_token用于調(diào)用其他接口)不同。公眾號可通過下述接口來獲取網(wǎng)頁授權(quán)access_token。如果網(wǎng)頁授權(quán)的作用域為snsapi_base,則本步驟中獲取到網(wǎng)頁授權(quán)access_token的同時,也獲取到了openid,snsapi_base式的網(wǎng)頁授權(quán)流程即到此為止。
注意:由于公眾號的 secret 和獲取到的access_token安全級別都非常高,必須只保存在服務(wù)器,不允許傳給客戶端。后續(xù)刷新access_token、通過access_token獲取用戶信息等步驟,也必須從服務(wù)器發(fā)起。
請求方法
獲取 code 后,請求以下鏈接獲取access_token:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
請求參數(shù)說明:
??
回調(diào)參數(shù)說明:
回調(diào)錯誤碼說明:
?
更多返回碼說明請參看:
【全局返回碼說明】
第三步:刷新access_token(可選項)
由于access_token擁有較短的有效期,當(dāng)access_token超時后,可以使用refresh_token進(jìn)行刷新,refresh_token有效期為30天,當(dāng)refresh_token失效之后,需要用戶重新授權(quán)。
請求方法
獲取第二步的refresh_token后,請求以下鏈接獲取access_token:
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
請求參數(shù)說明:
回調(diào)參數(shù)說明:
回調(diào)錯誤碼說明:參看第二步回調(diào)錯誤碼說明!
第四步:拉取用戶信息(scope 為 snsapi_userinfo)
如果網(wǎng)頁授權(quán)作用域為snsapi_userinfo,則此時開發(fā)者可以通過access_token和 openid 拉取用戶信息了。
請求方法
http:GET(請使用 https 協(xié)議):
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
關(guān)于scope授權(quán)作用域:
/**
* oauth2網(wǎng)頁授權(quán)的scope.
*/
public static class OAuth2Scope {
/**
* 不彈出授權(quán)頁面,直接跳轉(zhuǎn),只能獲取用戶openid.
*/
public static final String SNSAPI_BASE = "snsapi_base";
/**
* 彈出授權(quán)頁面,可通過openid拿到昵稱、性別、所在地。并且,即使在未關(guān)注的情況下,只要用戶授權(quán),也能獲取其信息.
*/
public static final String SNSAPI_USERINFO = "snsapi_userinfo";
/**
* 手動授權(quán),可獲取成員的詳細(xì)信息,包含手機(jī)、郵箱。只適用于企業(yè)微信或企業(yè)號.
*/
public static final String SNSAPI_PRIVATEINFO = "snsapi_privateinfo";
}
請求參數(shù)說明:
回調(diào)參數(shù)說明:
回調(diào)錯誤碼說明:參看第二步回調(diào)錯誤碼說明!
第五步:檢驗授權(quán)憑證(access_token)是否有效(可選項)
請求方法
http:GET(請使用 https 協(xié)議):
https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID
請求參數(shù)說明:
回調(diào)參數(shù)說明:
兩個參數(shù)(errcode、errmsg)
回調(diào)錯誤碼說明:參看第二步回調(diào)錯誤碼說明!
2、其它說明
一、關(guān)于網(wǎng)頁授權(quán)回調(diào)域名的說明
1、在微信公眾號請求用戶網(wǎng)頁授權(quán)之前,開發(fā)者需要先到公眾平臺官網(wǎng)中的“開發(fā) - 接口權(quán)限 - 網(wǎng)頁服務(wù) - 網(wǎng)頁帳號 - 網(wǎng)頁授權(quán)獲取用戶基本信息”的配置選項中,修改授權(quán)回調(diào)域名。請注意,這里填寫的是域名(是一個字符串),而不是URL,因此請勿加 http:// 等協(xié)議頭。
2、授權(quán)回調(diào)域名配置規(guī)范為全域名,比如需要網(wǎng)頁授權(quán)的域名為:www.qq.com,配置以后此域名下面的頁面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以進(jìn)行OAuth2.0鑒權(quán)。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com 無法進(jìn)行OAuth2.0鑒權(quán)。
3、如果公眾號登錄授權(quán)給了第三方開發(fā)者來進(jìn)行管理,則不必做任何設(shè)置,由第三方代替公眾號實現(xiàn)網(wǎng)頁授權(quán)即可。
二、關(guān)于網(wǎng)頁授權(quán)的兩種 scope 的區(qū)別說明
1、以snsapi_base為 scope 發(fā)起的網(wǎng)頁授權(quán),是用來獲取進(jìn)入頁面的用戶的 openid 的,并且是靜默授權(quán)并自動跳轉(zhuǎn)到回調(diào)頁的。用戶感知的就是直接進(jìn)入了回調(diào)頁(往往是業(yè)務(wù)頁面)。
2、以snsapi_userinfo為 scope 發(fā)起的網(wǎng)頁授權(quán),是用來獲取用戶的基本信息的。但這種授權(quán)需要用戶手動同意,并且由于用戶同意過,所以無須關(guān)注,就可在授權(quán)后獲取該用戶的基本信息。
3、用戶管理類接口中的“獲取用戶基本信息接口”,是在用戶和公眾號產(chǎn)生消息交互或關(guān)注后事件推送后,才能根據(jù)用戶 OpenID 來獲取用戶基本信息。這個接口,包括其他微信接口,都是需要該用戶(即openid)關(guān)注了公眾號后,才能調(diào)用成功的。
三、關(guān)于網(wǎng)頁授權(quán)access_token和普通access_token的區(qū)別
1、微信網(wǎng)頁授權(quán)是通過OAuth2.0機(jī)制實現(xiàn)的,在用戶授權(quán)給公眾號后,公眾號可以獲取到一個網(wǎng)頁授權(quán)特有的接口調(diào)用憑證(網(wǎng)頁授權(quán)access_token),通過網(wǎng)頁授權(quán)access_token可以進(jìn)行授權(quán)后接口調(diào)用,如獲取用戶基本信息。
2、其他微信接口,需要通過基礎(chǔ)支持中的“獲取access_token”接口來獲取到的普通access_token調(diào)用。
四、微信網(wǎng)頁授權(quán) - 流程時序圖
五、HTTPClient 實現(xiàn)微信公眾號消息推送與發(fā)布(四步走)
第一步:獲取微信公眾號CODE
/**
* Description:[獲取公眾號CODE]
*
* @date 2019-05-19
* @author huazai
*/
@GetMapping("/getWeChatCode")
@ApiOperation(value = "/getWeChatCode", notes = "獲取公眾號CODE")
public void getWeChatCode(HttpServletResponse response) {
try {
// 構(gòu)建公眾號消息體
String weChatGetCodeUrl = String.format(this.WE_CHAT_CODE_URL, this.WE_CHAT_APP_ID, this.WE_CHAT_CALL_BACK_DOMAIN_URL, WxConsts.OAuth2Scope.SNSAPI_BASE);
log.info("we_chat_get_code_url:" + weChatGetCodeUrl);
response.sendRedirect(weChatGetCodeUrl);
} catch (Exception e) {
log.info("異常信息:{}", e);
}
}
?請求回調(diào)獲取的用戶授權(quán)CODE,如下圖:
第二部:根據(jù)Code獲取用戶OpenId
/**
* Description:[根據(jù)Code獲取用戶OpenId]
*
* @return JSONResult
* @date 2019-05-19
* @author huazai
*/
@GetMapping("/getWeChatOpenId")
@ApiOperation(value = "/getWeChatOpenId", notes = "根據(jù)Code獲取用戶OpenId")
public JSONResult getWeChatOpenId(@RequestParam String code, @RequestParam String state) {
try {
log.info("we_chat_code: " + code);
String weChatDomain = String.format(this.WE_CHAT_AUTHORIZATION_URL, this.WE_CHAT_APP_ID, this.WE_CHAT_SECRET, code);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(weChatDomain, String.class);
String openid = JSONObject.parseObject(responseEntity.getBody()).getString("openid");
String access_token = JSONObject.parseObject(responseEntity.getBody()).getString("access_token");
// 用戶的OpenId,用戶的微信授權(quán)Access_Token
log.info("we_chat_open_id: " + openid);
log.info("we_chat_access_token: " + access_token);
return JSONResult.success(openid);
} catch (Exception e) {
log.info("異常信息:{}", e);
}
return null;
}
?獲取的openid如下圖:
第三步:根據(jù)Code獲取用戶Access_Token(可選)
/**
* Description:[根據(jù)Code獲取用戶Access_Token]
*
* @return JSONResult
* @date 2019-05-19
* @author huazai
*/
@GetMapping("/getUserAccessToken")
@ApiOperation(value = "/getUserAccessToken", notes = "根據(jù)Code獲取用戶Access_Token")
public JSONResult getUserAccessToken(@RequestParam String code, @RequestParam String state) {
try {
String weChatDomain = String.format(this.WE_CHAT_AUTHORIZATION_URL, this.WE_CHAT_APP_ID, this.WE_CHAT_SECRET, code);
log.info("we_chat_authorization_url:{}" + weChatDomain);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(weChatDomain, String.class);
String accessToken = JSONObject.parseObject(responseEntity.getBody()).getString("access_token");
log.info("we_chat_access_token: " + accessToken);
return JSONResult.success(accessToken);
} catch (Exception e) {
log.info("異常信息:{}", e);
}
return null;
}
第四步:獲取微信公眾號的Access_Token
/**
* Description:[獲取微信公眾號的Access_Token]
*
* @return JSONResult
* @date 2019-05-19
* @author huazai
*/
@GetMapping("/getWeChatAccessToken")
@ApiOperation(value = "/getWeChatAccessToken", notes = "微信公眾號的Access_Token")
public JSONResult getWeChatAccessToken() {
try {
// 微信公眾號官方獲取AccessToken
RestTemplate restTemplate = new RestTemplate();
String requestParams = String.format(this.WE_CHAT_ACCESS_TOKEN_URL, this.WE_CHAT_APP_ID, this.WE_CHAT_SECRET);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(requestParams, String.class);
String accessToken = JSONObject.parseObject(responseEntity.getBody()).getString("access_token");
log.info("we_chat_access_token: " + accessToken);
return JSONResult.success(accessToken);
} catch (Exception e) {
log.info("異常信息:{}", e);
}
return null;
}
第五步:微信公眾號指定用戶消息推送與發(fā)布
/**
* Description:[公眾號指定用戶消息推送]
*
* @return JSONResult
* @date 2019-05-19
* @author huazai
*/
@GetMapping("/sendWeChatRecharge")
@ApiOperation(value = "/sendWeChatRecharge", notes = "公眾號指定用戶消息推送")
public JSONResult sendWeChatRecharge() {
// 1、構(gòu)建公眾號消息體
WeChatRechargeTemplateParamsDTO weChatRechargeTemplateParamsDTO = WeChatRechargeTemplateParamsDTO.builder()
.first("尊敬用戶您好,你的繳費結(jié)果如下:")
.keyword1("HuaZai")
.keyword2("10010110010001")
.keyword3(BigDecimal.valueOf(2000))
.keyword4(BigDecimal.valueOf(10000182.92))
.keyword5(DateUtil.getDateTime())
.remark("繳費成功,祝您生活愉快!")
.touser("**********")
.customerNumber("549527")
.build();
// 2、組裝消息數(shù)據(jù)
Map<String, WeChatMsgDTO> weChatMsgMap = new HashMap<>();
weChatMsgMap.put("first", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getFirst()));
weChatMsgMap.put("keyword1", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getKeyword1()));
weChatMsgMap.put("keyword2", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getKeyword2()));
weChatMsgMap.put("keyword3", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getKeyword3().toString()));
weChatMsgMap.put("keyword4", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getKeyword4().toString()));
weChatMsgMap.put("keyword5", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getKeyword5()));
weChatMsgMap.put("remark", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getRemark()));
String customerCallUrl = String.format(this.WE_CHAT_CUSTOMER_CALL_URL, weChatRechargeTemplateParamsDTO.getCustomerNumber());
//3、構(gòu)建模板消息體
WeChatTemplateParamsDTO weChatTemplateParamsDTO = WeChatTemplateParamsDTO.builder()
.touser(weChatRechargeTemplateParamsDTO.getTouser())
.template_id(this.WE_CHAT_TEMPLATE_ID)
.url(customerCallUrl)
.topcolor(this.WE_CHAT_TOP_COLOR)
.data(weChatMsgMap)
.build();
// 4、微信公眾號消息推送與發(fā)布
RestTemplate restTemplate = new RestTemplate();
String resultUrl = String.format(this.WE_CHAT_REQUEST_URL, this.WE_CHAT_ACCESS_TOKEN);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(resultUrl, weChatTemplateParamsDTO, String.class);
if (!OK.equals(responseEntity.getStatusCode())) {
log.error("公眾號消息推送失敗!", responseEntity.getBody());
}
return JSONResult.success();
}
消息推送,返回code為0,即表示消息已成功推送(否則失敗,需要code碼和上面的錯誤信息說明進(jìn)行對比,針對性問題處理),如下圖:
再打開微信公眾號,就可以看到推送的消息了,如下圖:
?
常量說明:
// 微信公眾號的 app_id
String WE_CHAT_APP_ID = "**********";
// 微信公眾號的 secret
String WE_CHAT_SECRET = "**********";
// 微信公眾號的 access_token
String WE_CHAT_ACCESS_TOKEN = "**********";
// 微信公眾號code獲取地址
String WE_CHAT_CODE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=STATE#wechat_redirect";
// 回調(diào)地址,獲取open_id
String WE_CHAT_CALL_BACK_DOMAIN_URL = "https://***.***.***.***/***/***/getWeChatOpenId";
// 微信公眾號的token獲取地址
String WE_CHAT_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
// 微信公眾號消息推送地址
String WE_CHAT_REQUEST_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";
// 微信公眾號推送消息模板id
String WE_CHAT_TEMPLATE_ID = "**********";
// 微信公眾號的消息回調(diào)地址(這兒可根據(jù)業(yè)務(wù)需求自定義動作,可選)
String WE_CHAT_CUSTOMER_CALL_URL = "https://***.***.***.***/***/***/accountInfo?keyword=%s";
// 微信公眾號的主題顏色
String WE_CHAT_TOP_COLOR = "#A349A4";
// 微信公眾號微信用戶授權(quán)地址
String WE_CHAT_AUTHORIZATION_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
六、通過weixin-java-mp SDK實現(xiàn)微信公眾號消息推送與發(fā)布(七步走)
第一步:pom.xml新增依賴
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.3.0</version>
</dependency>
第二步:配置WxMpService
配置me.chanjar.weixin.mp.api.WxMpService,可以通過@Component組件注入交由Spring進(jìn)行管理,或者直接在啟動類@SpringBootApplication中@Bean注入,
注入的內(nèi)容如下:
@Bean
public WxMpService wxMpService() {
WxMpMapConfigImpl wxMpMapConfig = new WxMpMapConfigImpl();
wxMpMapConfig.setAppId(Constant.WE_CHAT_APP_ID);
wxMpMapConfig.setSecret(Constant.WE_CHAT_SECRET);
val wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(wxMpMapConfig);
return wxMpService;
}
?第三步:獲取微信公眾號CODE
@Autowired
private WxMpService wxMpService;
/**
* Description:[獲取公眾號CODE]
*
* @date 2019-05-19
* @author huazai
*/
@GetMapping("/getWeChatCode")
@ApiOperation(value = "/getWeChatCode", notes = "獲取公眾號CODE")
public RedirectView getWeChatCode() {
try {
// 構(gòu)造網(wǎng)頁授權(quán)url
String authorizationUrl = wxMpService.getOAuth2Service().buildAuthorizationUrl(this.WE_CHAT_CALL_BACK_DOMAIN_URL, WxConsts.OAuth2Scope.SNSAPI_BASE, null);
log.info("we_chat_get_code_url:" + authorizationUrl);
return new RedirectView(authorizationUrl);
} catch (Exception e) {
log.info("異常信息:{}", e);
}
return null;
}
第四步:根據(jù)Code獲取用戶OpenId
/**
* Description:[根據(jù)Code獲取用戶OpenId]
*
* @return JSONResult
* @date 2019-05-19
* @author huazai
*/
@GetMapping("/getWeChatOpenId")
@ApiOperation(value = "/getWeChatOpenId", notes = "根據(jù)Code獲取用戶OpenId")
public JSONResult getWeChatOpenId(@RequestParam String code, @RequestParam String state) {
try {
log.info("we_chat_code: " + code);
// 通過微信回調(diào)過來的code獲得access token,其中也包含用戶的openid等信息
WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
String openid = wxOAuth2AccessToken.getOpenId();
String access_token = wxOAuth2AccessToken.getAccessToken();
// 用戶的OpenId,用戶的微信授權(quán)Access_Token
log.info("we_chat_open_id: " + openid);
log.info("we_chat_access_token: " + access_token);
return JSONResult.success(openid);
} catch (Exception e) {
log.info("異常信息:{}", e);
}
return null;
}
第五步:根據(jù)Code獲取用戶Access_Token(可選)
/**
* Description:[根據(jù)Code獲取用戶Access_Token]
*
* @return JSONResult
* @date 2019-05-19
* @author huazai
*/
@GetMapping("/getUserAccessToken")
@ApiOperation(value = "/getUserAccessToken", notes = "根據(jù)Code獲取用戶Access_Token")
public JSONResult getUserAccessToken(@RequestParam String code, @RequestParam String state) {
try {
// 根據(jù)Code獲取用戶Access_Token
WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
String accessToken = wxOAuth2AccessToken.getAccessToken();
log.info("we_chat_user_access_token: " + accessToken);
return JSONResult.success(accessToken);
} catch (Exception e) {
log.info("異常信息:{}", e);
}
return null;
}
第六步:獲取微信公眾號的Access_Token
?
/**
* Description:[獲取微信公眾號的Access_Token]
*
* @return JSONResult
* @date 2019-05-19
* @author huazai
*/
@GetMapping("/getWeChatAccessToken")
@ApiOperation(value = "/getWeChatAccessToken", notes = "微信公眾號的Access_Token")
public JSONResult getWeChatAccessToken() {
try {
// 微信公眾號官方獲取AccessToken
String accessToken = wxMpService.getAccessToken();
log.info("we_chat_access_token: " + accessToken);
return JSONResult.success(accessToken);
} catch (Exception e) {
log.info("異常信息:{}", e);
}
return null;
}
第七步:微信公眾號指定用戶消息推送與發(fā)布
/**
* Description:[公眾號指定用戶消息推送]
*
* @return JSONResult
* @date 2019-05-19
* @author huazai
*/
@GetMapping("/sendWeChatRecharge")
@ApiOperation(value = "/sendWeChatRecharge", notes = "公眾號指定用戶消息推送")
public JSONResult sendWeChatRecharge() {
try {
// 1、構(gòu)建公眾號消息體
WeChatRechargeTemplateParamsDTO weChatRechargeTemplateParamsDTO = WeChatRechargeTemplateParamsDTO.builder()
.first("尊敬用戶您好,你的繳費結(jié)果如下:")
.keyword1("HuaZai")
.keyword2("10010110010001")
.keyword3(BigDecimal.valueOf(2000))
.keyword4(BigDecimal.valueOf(10000182.92))
.keyword5(DateUtil.getDateTime())
.remark("繳費成功,祝您生活愉快!")
.touser("**********")
.customerNumber("549527")
.build();
// 2、組裝消息數(shù)據(jù)
List<WxMpTemplateData> wxMpTemplateDataList = new ArrayList<>();
wxMpTemplateDataList.add(new WxMpTemplateData("first", weChatRechargeTemplateParamsDTO.getFirst(), this.WE_CHAT_TOP_COLOR));
wxMpTemplateDataList.add(new WxMpTemplateData("keyword1", weChatRechargeTemplateParamsDTO.getKeyword1(), this.WE_CHAT_TOP_COLOR));
wxMpTemplateDataList.add(new WxMpTemplateData("keyword2", weChatRechargeTemplateParamsDTO.getKeyword2(), this.WE_CHAT_TOP_COLOR));
wxMpTemplateDataList.add(new WxMpTemplateData("keyword3", weChatRechargeTemplateParamsDTO.getKeyword3().toString(), this.WE_CHAT_TOP_COLOR));
wxMpTemplateDataList.add(new WxMpTemplateData("keyword4", weChatRechargeTemplateParamsDTO.getKeyword4().toString(), this.WE_CHAT_TOP_COLOR));
wxMpTemplateDataList.add(new WxMpTemplateData("keyword5", weChatRechargeTemplateParamsDTO.getKeyword5(), this.WE_CHAT_TOP_COLOR));
wxMpTemplateDataList.add(new WxMpTemplateData("remark", weChatRechargeTemplateParamsDTO.getRemark(), this.WE_CHAT_TOP_COLOR));
String customerCallUrl = String.format(this.WE_CHAT_CUSTOMER_CALL_URL, weChatRechargeTemplateParamsDTO.getCustomerNumber());
//3、構(gòu)建模板消息體
WxMpTemplateMessage wxMpTemplateMessage = WxMpTemplateMessage.builder()
.toUser(weChatRechargeTemplateParamsDTO.getTouser())
.templateId(this.WE_CHAT_TEMPLATE_ID)
.url(customerCallUrl)
.data(wxMpTemplateDataList)
.build();
// 4、微信公眾號消息推送與發(fā)布
String msgId = wxMpService.getTemplateMsgService().sendTemplateMsg(wxMpTemplateMessage);
log.error("公眾號模板消息推送與發(fā)布結(jié)果:{}", msgId);
} catch (Exception e) {
log.info("異常信息:{}", e);
}
return JSONResult.success();
}
七、抽取與封裝
這兒的封裝需要更具自身業(yè)務(wù)的不同,封裝的深度也不同,需要自由抽取封裝,但萬變不離其宗,
1、簡單工廠-普通模式
建立一個工廠類,對實現(xiàn)了同一接口的一些類進(jìn)行實例的創(chuàng)建。
如下圖:
2、簡單工廠-多方法模式
對普通工廠方法模式的改進(jìn),在普通工廠方法模式中,如果傳遞的字符串出錯,則不能正確創(chuàng)建對象,而多個工廠方法模式是提供多個工廠方法,分別創(chuàng)建對象。
如下圖:
3、簡單工廠-多靜態(tài)方法模式
將多工廠方法模式里的方法置為靜態(tài)的,不需要創(chuàng)建實例,直接調(diào)用即可。
4、工廠方法模式
簡單工廠模式有一個問題就是,類的創(chuàng)建依賴工廠類,也就是說,如果想要拓展程序,必須對工廠類進(jìn)行修改,這違背了閉包原則,所以,從設(shè)計角度考慮,有一定的問題,如何解決?
解決這個問題就用到工廠方法模式,創(chuàng)建一個工廠接口和創(chuàng)建多個工廠實現(xiàn)類,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的代碼。
5、抽象工廠模式
工廠方法模式:
- 一個抽象產(chǎn)品類,可以派生出多個具體產(chǎn)品類;
- 一個抽象工廠類,可以派生出多個具體工廠類;?
- 每個具體工廠類只能創(chuàng)建一個具體產(chǎn)品類的實例;
抽象工廠模式:
- 多個抽象產(chǎn)品類,每個抽象產(chǎn)品類可以派生出多個具體產(chǎn)品類;
- 一個抽象工廠類,可以派生出多個具體工廠類;
- 每個具體工廠類可以創(chuàng)建多個具體產(chǎn)品類的實例,也就是創(chuàng)建的是一個產(chǎn)品線下的多個產(chǎn)品;
區(qū)別:
- 工廠方法模式只有一個抽象產(chǎn)品類,而抽象工廠模式有多個;
- 工廠方法模式的具體工廠類只能創(chuàng)建一個具體產(chǎn)品類的實例,而抽象工廠模式可以創(chuàng)建多個;
- 工廠方法創(chuàng)建 "一種" 產(chǎn)品,他的著重點在于"怎么創(chuàng)建",也就是說如果你開發(fā),你的大量代碼很可能圍繞著這種產(chǎn)品的構(gòu)造,初始化這些細(xì)節(jié)上面。也因為如此,類似的產(chǎn)品之間有很多可以復(fù)用的特征,所以會和模版方法相隨;
- 抽象工廠需要創(chuàng)建一些列產(chǎn)品,著重點在于"創(chuàng)建哪些"產(chǎn)品上,也就是說,如果你開發(fā),你的主要任務(wù)是劃分不同差異的產(chǎn)品線,并且盡量保持每條產(chǎn)品線接口一致,從而可以從同一個抽象工廠繼承;
對于Java應(yīng)用程序來說,能見到的大部分抽象工廠模式都是這樣的:里面是一堆工廠方法,每個工廠方法返回某種類型的對象。
例如:工廠可以生產(chǎn)鼠標(biāo)和鍵盤。那么抽象工廠的實現(xiàn)類(它的某個具體子類)的對象都可以生產(chǎn)鼠標(biāo)和鍵盤,但可能工廠 A 生產(chǎn)的是先科的鍵盤和鼠標(biāo),工廠 B 是Microsoft的。這樣 A 和 B 就是工廠,對應(yīng)于抽象工廠;每個工廠生產(chǎn)的鼠標(biāo)和鍵盤就是產(chǎn)品,對應(yīng)于工廠方法;用了工廠方法模式,你替換生成鍵盤的工廠方法,就可以把鍵盤從先科如絲滑般的切換到Microsoft。但是用了抽象工廠模式,要想切換工廠 C 的雷蛇,就可以同時替換鼠標(biāo)和鍵盤一套。如果產(chǎn)品有幾十個,當(dāng)然用抽象工廠模式一次替換全部最方便快捷(工廠會替換相應(yīng)的工廠方法)
所以抽象工廠就像工廠,而工廠方法則像是工廠的一種產(chǎn)品生產(chǎn)線?。?!
微信公眾號開發(fā)注意兩點:
1、公眾號開發(fā)獲取調(diào)用auoth2授權(quán)接口獲取,Token_assecc授權(quán)時,需要授權(quán)IP,
參考:
《errcode“:40164,“errmsg“:“invalid ip ...微信公眾號開發(fā)調(diào)用失敗的解決辦法》
2、在發(fā)布時,由于是基于Web頁面開發(fā)的,需要授權(quán)域名的綁定驗證,
參考:
《微信公眾號開發(fā)redirect_uri 參數(shù)錯誤 的解決辦法,Oauth2授權(quán)重定向域名參數(shù)錯誤解決辦法》
3、SpringBoot整合調(diào)用微信模板方法實現(xiàn)微信公眾號消息通知推送
《?HTTPClient 實現(xiàn)微信公眾號消息推送與發(fā)布(四步走) 》
4、SpringBoot整合調(diào)用微信模板方法實現(xiàn)微信公眾號消息通知推送
《?通過weixin-java-mp SDK實現(xiàn)微信公眾號消息推送與發(fā)布(七步走) 》
參考:
【公眾號模板消息接口文檔】
【微信網(wǎng)頁開發(fā)-Web開發(fā)者工具下載】
【微信開發(fā)包】更多內(nèi)容查看WIKI,MP_OAuth2網(wǎng)頁授權(quán)
【模板消息接口文檔】
【MP_OAuth2網(wǎng)頁授權(quán)】文章來源:http://www.zghlxwxcb.cn/news/detail-688833.html
?好了,關(guān)于?SpringBoot整合調(diào)用微信模板方法實現(xiàn)微信公眾號消息通知推送,Java實現(xiàn)微信公眾號給關(guān)注用戶推送自定義消息通知(從0到1) ?就寫到這兒了,如果還有什么疑問或遇到什么問題歡迎掃碼提問,也可以給我留言哦,我會一一詳細(xì)的解答的。?
歇后語:“ 共同學(xué)習(xí),共同進(jìn)步 ”,也希望大家多多關(guān)注CSND的IT社區(qū)。文章來源地址http://www.zghlxwxcb.cn/news/detail-688833.html
作? ? ? ?者: | 華 ? ?仔 |
聯(lián)系作者: | who.seek.me@java98k.vip |
來? ? ? ? 源: | CSDN (Chinese Software Developer Network) |
原? ? ? ? 文: | https://blog.csdn.net/Hello_World_QWP/article/details/125871196 |
版權(quán)聲明: | 本文為博主原創(chuàng)文章,請在轉(zhuǎn)載時務(wù)必注明博文出處! |
到了這里,關(guān)于SpringBoot整合調(diào)用微信模板方法實現(xiàn)微信公眾號消息通知推送,Java實現(xiàn)微信公眾號給關(guān)注用戶推送自定義消息通知(手把手從0到1)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!