從零開始講解Java微信公眾號消息推送實現(xiàn)
1.前期準備
1. 首先需要的是一個能正常運營的微信公眾號或者訂閱號,根據(jù)微信公眾平臺,使用已授權(quán)的用戶登錄,獲取對應的appId 和 開發(fā)者密碼 appSecret
得到appId和AppSecret是為了后續(xù)調(diào)用微信官方接口必不可少的參數(shù),例如獲取微信基礎accessToken則需要以上入?yún)?
2. 設置域名以及ip白名單
ip白名單主要是針對獲取acces_token,一般設置成自己服務器的ip地址,因為還需要設置自定義域名,可以關聯(lián)到服務器地址,從而微信接口請求返回可以有對應的請求地址,例如, 我服務器的ip地址是222.13.11.103 ,那么ip白名單就填入這個地址即可;
設置域名主要做回調(diào)地址使用,例如:pay.company.cn,需要根據(jù)官方指引,將對應的txt文件放到web服務器的根目錄下即可
在微信授權(quán)的時候需要用到其域名
3. 選擇合適的消息模板,記住其模板id和點擊詳情后的內(nèi)容格式,因為發(fā)送模板消息,需要模板id以及內(nèi)容格式
2.用戶微信授權(quán),獲取其openId(重要)
這一步非常重要,只有是跟微信對接,都需要得到用戶的openId,才能把模板消息發(fā)送到對應的用戶中,且每個微信用戶都有一個唯一的openId,當獲取到openId后,建議保存入庫;
可參考微信官方文檔:開發(fā)前必讀 | 微信開放文檔
這里將會指引你如何將用戶進行網(wǎng)頁授權(quán)也是就
1. 引導用戶進入授權(quán)頁面同意授權(quán),獲取code
2. 通過 code 換取網(wǎng)頁授權(quán)access_token
3. 根據(jù)通過網(wǎng)頁授權(quán)access_token和 openid 獲取用戶基本信息
以下代碼,邏輯跟指引一樣,先是構(gòu)建url地址,然后回調(diào)自己定義的方法地址,同時微信會自動帶出當前用戶的code,然后根據(jù)code再次調(diào)用授權(quán)地址,帶出對應的openId,而我們的目的就是獲取用戶的openId,例如官方示例地址;
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
代碼如下;(敏感的appid和密碼以及域名地址需要自己替換)
@Controller public class MyController { private static final Logger log = LoggerFactory.getLogger(MyController .class); // appId private static final String appId = "wxc8xxxxcxxxxxx"; // appIdSecret private static final String appIdSecret = "60b429xxxxxxxxxxxxxxx"; //1.先查詢code @RequestMapping("/getCode") public String getCode() { // 官方地址 String urlFir = "redirect:https://open.weixin.qq.com/connect/oauth2/authorize?appid="; // 微信申請的域名(提前準備) String domain = "http://pay.xxx.cn/wxpay"; // 自定義跳轉(zhuǎn)方法 String redirectMethod = "/weixinoauth"; // 地址進行encode轉(zhuǎn)譯 (未轉(zhuǎn)譯的地址是:http://pay.xxx.cn/wxpay/weixinoauth) // 轉(zhuǎn)譯后的地址是: http%3A%2F%2Fpay.xxx.cn%2Fwxpay%2Fweixinoauth String encoderUrl = getURLEncoderString(domain + redirectMethod); log.info(urlFir +appId + "&redirect_uri=" + encoderUrl +"&response_type=code&scope=snsapi_base" + "&state=STATE" + "#wechat_redirect"); return urlFir + appId + "&redirect_uri=" + encoderUrl +"&response_type=code&scope=snsapi_base" + "&state=STATE" + "#wechat_redirect"; } /** * 編碼 * @param str * @return */ public static String getURLEncoderString(String str) { String result = ""; if (null == str) { return ""; } try { result = java.net.URLEncoder.encode(str, "GBK"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return result; } //2.根據(jù)code獲取openId @GetMapping("/wxpay/weixinoauth") public void weixinOauth(@RequestParam String code,@RequestParam String state) throws Exception { log.info("獲取code:{}",code); String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + appIdSecret + "&code=" + code + "&grant_type=authorization_code"; Map<String, Object> paramMap = null; String res = HttpUtil.get(url, paramMap); String openid = JSONObject.parseObject(res).getString("openid"); log.info("根據(jù)code查詢得到openId:{}",openid); } }
需要在微信開發(fā)工具輸入127.0.0.1/getCode,因為授權(quán)頁面必須要在微信客戶端中打開,所以需要下載微信開發(fā)工具,微信開發(fā)工具地址:開發(fā)前必讀 | 微信開放文檔
下載安裝后,需要使用已配置了開發(fā)者權(quán)限的微信賬號登錄
然后系統(tǒng)會打印出跳轉(zhuǎn)地址和openId ,該工具會自動跳轉(zhuǎn)/getCode返回的Url并且回調(diào)我們的方法 /wxpay/weixinoauth 進行獲取用戶code,再構(gòu)建授權(quán)url地址j獲取openId
打印情況如下(敏感信息已打碼):
如果正常到了這里,則說明成功了一半了。
3.獲取微信基礎accessToken
需要獲取微信的基礎accessToken用于構(gòu)建模板消息發(fā)送的url入?yún)ⅲ以揳ccessToken有效期只有兩小時(下面簡稱token),因此當調(diào)用一下方法一次后,就可以將其放入redis中,設置過期時間(低于兩小時);
@GetMapping("/getToken") public void getAccessToken() throws Exception{ String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ appId +"&secret=" + appIdSecret; String res = HttpUtil.get(url); JSONObject jsonObject = JSONObject.parseObject(res); String accessToken = jsonObject.getString("access_token"); log.info("accessToken:{}", accessToken); }
代碼會報錯,但不影響獲取token,日志打印如下; 保存token后續(xù)調(diào)用發(fā)送微信模板消息需要用到;
若出現(xiàn)了無效的ip地址錯誤,則確認ip白名單是否設置再去
4. 調(diào)用微信模板方法發(fā)送消息
這一步很簡單,通過以上獲取的 openId, accessToken 和 前期準備的模板id即可,我們只需要封裝模板內(nèi)容,再調(diào)用官方url即可
自定義DTO
@Data @ToString public class WeChatTemplateMsg { /** * 消息 */ private String value; /** * 消息顏色 */ private String color; public WeChatTemplateMsg(String value) { this.value = value; this.color = "#173177"; } public WeChatTemplateMsg(String value, String color) { this.value = value; this.color = color; } }
@GetMapping("/sendMessage") public String sendMessage() { // 模板參數(shù) Map<String, WeChatTemplateMsg> sendMag = new HashMap<String, WeChatTemplateMsg>(); // openId代表一個唯一微信用戶,即微信消息的接收人 String openId = "oNB9p1BpVJEquxxxxxxxxx"; // 公眾號的模板id(也有相應的接口可以查詢到) String templateId = "B0YStqTYdjHhY9Da9Sy2NM7xxxxxxxxxxx"; // 微信的基礎accessToken String accessToken = "57_LubK-8NKQc6C7jsLMxvdHaI0ju4x3-HPWEFhh7GKkw9fKbWhuxxoZyX4GaVIn6y4yO7RKfSlCyHdedKJlHUMZkd8457nKm0TOoaVkbzK1HCZ4g4gZdrmAGBylGBOZu9yxxxxxxxxxxxxxxxx"; String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken; /** * 其他模板可以從模板庫中自己添加 * 模板ID * B0YStqTYdjHhY9Da9Sy2NM7HXxxxxxxxxxxxxxx * 開發(fā)者調(diào)用模板消息接口時需提供模板ID * 標題 * 產(chǎn)品兌付成功提醒 * 行業(yè) * 金融業(yè) - 證券|基金|理財|信托 * 詳細內(nèi)容 * {{first.DATA}} * 產(chǎn)品名稱:{{keyword1.DATA}} * 當期兌付本金:{{keyword2.DATA}} * 當期兌付利息:{{keyword3.DATA}} * 已兌付期數(shù):{{keyword4.DATA}} * 兌付日期:{{keyword5.DATA}} * {{remark.DATA}} */ sendMag.put("first", new WeChatTemplateMsg("f123")); sendMag.put("keyword1", new WeChatTemplateMsg("111")); sendMag.put("keyword2", new WeChatTemplateMsg("222")); sendMag.put("keyword3", new WeChatTemplateMsg("333")); sendMag.put("keyword4", new WeChatTemplateMsg("444")); sendMag.put("remark", new WeChatTemplateMsg("r555")); RestTemplate restTemplate = new RestTemplate(); //拼接base參數(shù) Map<String, Object> sendBody = new HashMap<>(); sendBody.put("touser", openId); // openId sendBody.put("url", "www.baidu.com"); // 點擊模板信息跳轉(zhuǎn)地址 sendBody.put("topcolor", "#FF0000"); // 頂色 sendBody.put("data", sendMag); // 模板參數(shù) sendBody.put("template_id", templateId); // 模板Id ResponseEntity<String> forEntity = restTemplate.postForEntity(url, sendBody, String.class); log.info("結(jié)果是: {}",forEntity.getBody()); JSONObject jsonObject = JSONObject.parseObject(forEntity.getBody()); // 0 String messageCode = jsonObject.getString("errcode"); // 2431260672639467520 String msgId = jsonObject.getString("msgid"); System.out.println("messageCode : " + messageCode + ", msgId: " +msgId); return forEntity.getBody(); }
結(jié)果是:
可能需要的依賴:
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.4.0</version> </dependency>
總結(jié)
到此這篇關于Java微信公眾號消息推送實現(xiàn)的文章就介紹到這了,更多相關Java微信公眾號消息推送內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JavaEE SpringMyBatis是什么? 它和Hibernate的區(qū)別及如何配置MyBatis
這篇文章主要介紹了JavaEE Spring MyBatis是什么? 它和Hibernate的區(qū)別有哪些?如何配置MyBatis?本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08Spring中的之啟動過程obtainFreshBeanFactory詳解
這篇文章主要介紹了Spring中的之啟動過程obtainFreshBeanFactory詳解,在refresh時,prepareRefresh后,馬上就調(diào)用了obtainFreshBeanFactory創(chuàng)建beanFactory以及掃描bean信息(beanDefinition),并通過BeanDefinitionRegistry注冊到容器中,需要的朋友可以參考下2024-02-02JUC并發(fā)編程LinkedBlockingQueue隊列深入分析源碼
LinkedBlockingQueue 是一個可選有界阻塞隊列,這篇文章主要為大家詳細介紹了Java中LinkedBlockingQueue的實現(xiàn)原理與適用場景,感興趣的可以了解一下2023-04-04Java中FilterInputStream和FilterOutputStream的用法詳解
這篇文章主要介紹了Java中FilterInputStream和FilterOutputStream的用法詳解,這兩個類分別用于封裝輸入和輸出流,需要的朋友可以參考下2016-06-06