SpringBoot實戰項目精華總結 -- 微信公衆號(三)
注:這裏的總結僅供自己以後參考,遊客還請以微信官方文檔爲主
一、微信特性
1.微信授權
1.1 網頁域名授權配置
1.2 獲取openid
手工方式
利用第三方SDK(github上 => weixin-java-tools)
1.3 前後端聯調
二、微信支付
1.官網文檔
2.公衆號裏發起支付
3.第三方SDK
4.支付時序
4.1 發起統一下單
4.2 利用預付單信息+freemarker完成動態參數注入js簽名,喚起前端支付
4.3 最後通過微信內置對象WeixinJSBridge喚起支付密碼輸入彈窗
5.處理微信異步通知(API列表=>支付結果通知)
三、微信退款
1.基於SDK的方法代碼
2.退款微信也會調用異步通知(與支付異步通知同一接口)需要處理
四、其他
1.基於Gson的Json格式化工具
一、微信特性
1.微信授權
官網文檔:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html
1.1 網頁域名授權配置
-> 本地開發環境使用內網穿透:https://natapp.cn/ 將本地的8080端口映射到購買的可用於微信開發的二級域名,注意要買備案的
-> 在微信公衆平臺=>功能設置=>網頁授權域名,下載文件存放至 resource/static 目錄下
-> 啓動natapp.exe(參考natapp1分鐘教程),啓動本地項目(臨時去掉 server.context-path 設置)
-> 微信公衆平臺填寫買到的二級域名,完成保存。設置後即可刪除txt文件
1.2 獲取openid
手工方式
-> 先調微信授權接口並指定回調地址,用戶端彈出授權框,同意後可獲取code
-> 回調地址接口接收到微信的回調,帶回code,code只能使用一次,5分鐘有效期
-> 後端微信回調的接口再使用code+appid+secret獲取access_token+openid+refresh_token
-> 使用access_token+openid拉取用戶基本信息,但注意拉取得信息編碼是ISO-8859-1編碼
-> 對用戶信息的轉碼操作 new String(response.getBytes("ISO-8859-1"), "UTF-8")
利用第三方SDK(github上 => weixin-java-tools)
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>2.7.0</version>
</dependency>
-> 前端發起用戶授權請求,入參爲回調地址(前端接收授權後openid的地址)
1.3 前後端聯調
-> 手機網頁抓包工具charles及破解教程:https://www.cnblogs.com/jiayuchn-test/p/8875105.html
-> 10003 redirect_uri域名與後臺配置不一致:公衆號設置=>功能設置=>網頁授權域名 必須要與 授權鏈接 https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx69fxxxxxxxxed8&redirect_uri=http%3a%2f%2fwww.xxx.com%2fvShop%2fdefault&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect 中redirect_uri一致!
二、微信支付
1.官網文檔
https://pay.weixin.qq.com/wiki/doc/api/index.html
2.公衆號裏發起支付
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4
3.第三方SDK
https://github.com/Pay-Group/best-pay-sdk
4.支付時序
4.1 發起統一下單
notifyUrl(異步通知必填)設置爲自己單獨的接口地址給微信支付平臺調用,傳來預付單信息,此時微信端已經記錄下“訂單號+訂單金額”信息(所以只改訂單金額是不行的)
4.2 利用預付單信息+freemarker完成動態參數注入js簽名,喚起前端支付
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
pay/create.ftl
<script>
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":"${payResponse.appId}", //公衆號名稱,由商戶傳入
"timeStamp":"${payResponse.timeStamp}", //時間戳,自1970年以來的秒數
"nonceStr":"${payResponse.nonceStr}", //隨機串
"package":"${payResponse.packAge}",
"signType":"MD5", //微信簽名方式:
"paySign":"${payResponse.paySign}" //微信簽名
},
function(res){
// if(res.err_msg == "get_brand_wcpay_request:ok" ) {
// } // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回 ok,但並不保證它絕對可靠。
location.href = "${returnUrl}";
}
);
}
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();
}
</script>
4.3 最後通過微信內置對象WeixinJSBridge喚起支付密碼輸入彈窗
5.處理微信異步通知(API列表=>支付結果通知)
/**
* 微信異步通知
* @param notifyData
*/
@PostMapping("/notify")
public ModelAndView notify(@RequestBody String notifyData) {
payService.notify(notifyData);
//返回給微信處理結果
return new ModelAndView("pay/success");
}
pay/success.ftl 告訴微信訂單處理成功,就不會再收到微信通知支付成功了
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>
三、微信退款
官方文檔:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
1.基於SDK的方法代碼
需要封裝一個退款請求類:RefundRequest(訂單號,訂單金額,支付類型)
/**
* 退款
* @param orderDTO
*/
@Override
public RefundResponse refund(OrderDTO orderDTO) {
RefundRequest refundRequest = new RefundRequest();
refundRequest.setOrderId(orderDTO.getOrderId());
refundRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue());
refundRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_MP);
log.info("【微信退款】request={}", JsonUtil.toJson(refundRequest));
RefundResponse refundResponse = bestPayService.refund(refundRequest);
log.info("【微信退款】response={}", JsonUtil.toJson(refundResponse));
return refundResponse;
}
2.退款微信也會調用異步通知(與支付異步通知同一接口)需要處理
四、其他
1.基於Gson的Json格式化工具
/**
* @Description Json格式化處理工具
* @Date 2020/2/16 12:08
*/
public class JsonUtil {
public static String toJson(Object object) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setPrettyPrinting();
Gson gson = gsonBuilder.create();
return gson.toJson(object);
}
}