日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

手把手教你实现Java微信JSAPI支付

發布時間:2023/12/31 javascript 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 手把手教你实现Java微信JSAPI支付 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

需求
想在微信瀏覽器里面實現微信支付. 查看微信支付文檔, 發現要用微信JSAPI公眾號支付, 微信H5支付是不能實現的.
自己在實現的時候踩了許多坑, 花費了很多時間. 特此記錄, 希望能幫助到看到該文章的開發者.

開發環境
后端SpringBoot, 前端VUE

準備工作
1.首先我們要在微信公眾號平臺和微信商戶平臺 注冊賬號

2.準備JSAPI支付, 和調用微信統一下單的時候, 所需要的信息.

appid: 這個appid是公眾號的appId.

重要的一步. 這里appid如果想使用, 必需要在微信商戶號那里關聯并授權. 可根據 查看指引 這一步如何操作

appsecret: 開發者密碼. 可在微信公眾號平臺, 自己設置. 切記,設置后保存一下, 因為沒有地方可以回顯.

mer_id: 微信商戶號id

key: 微信商戶號API秘鑰. 配置完之后也需要保存, 因為沒有地方可以回顯

body: 訂單備注
nonce_str: 即用來標識一筆單, 是個隨機數, 可自行實現.
openid: 這個重中之重, 需要前后端一起配合, 后面講解如何獲取.
out_trade_no: 訂單編號
spbill_create_ip: ip地址,可以獲取當前請求的ip地址, 實現方式有很多, 可自行百度實現.
total_fee: 支付金額, 需要注意這個金額的單位是分, 所以在使用的時候, 要自己訂單金額 *100, 可能有時候失敗, 也是因為這個原因.
sign_type: 加簽方式, 也就是生成 sign 的方式, sign后面會提到, 這里默認是MD5, 建議也寫上MD5, 方便調起JSAPI支付的時候, 做統一.
trade_type: 調用的支付方式, 因為這里是JSAPI支付, 所以值為 JSAPI
notify_url: 微信支付的回調, 用于支付成功后處理的業務邏輯. 這個地址必須是外網可以訪問的地址, 如果支付成功沒有進入回調, 可能就是這里的原因.
sign: 簽名, 這個需要程序自己生成, 是根據上面的信息生成, 具體方式可看下面的代碼.

其中openid還沒有獲取到, 最費勁的也就是它了. 下面給出獲取openid的步驟, 需要前后端一起配合. 具體實現流程, 可根據自身情況.

獲取openid

  • 用戶同意授權, 獲取code, 這里獲取code的方式, 是我們給前端實現了.
  • // appid: 需要把我們的appid給前端 // redirect_uri: 回調地址, 前端自己填寫, 用來獲取code的 https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=redirect_uri&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
  • 根據code獲取openid
    有一點需要注意. 這里的code有效時間是5分鐘, 且只能用一次, 如果獲取openid失敗了, 看一下這個code是不是失效了,或者重復使用了, 我們之前前端獲取openid失敗, 就是因為沒有刷新, code重復使用了.
  • @ApiOperation("根據code獲取openId")@GetMapping("openid")public Result getOpenIdByCode(@RequestParam String code){log.info("根據code:{}獲取openId", code);String getopenid_url = "https://api.weixin.qq.com/sns/oauth2/access_token";String param= "appid="+appid+"&secret="+secret+"&code="+code+"&grant_type=authorization_code";String openIdStr = HttpUtils.sendGet(getopenid_url, param);JSONObject json = JSONObject.parseObject(openIdStr);// 轉成Json格式log.info("查詢結果: "+json.toString());String openId = json.getString("openid");// 獲取openIdreturn Result.success(ResultEnum.SELECT_SUCCESS, openId);}

    目前為止, 我們已經獲取到了微信JSAPI支付所需要的全部數據, 如果您能跟著實現到了這里, 就已經成功了百分之八十.


    下面開始代碼實現

  • 后端接口準備. 編寫支付接口中的JSAPI. 這里主要是為了給前端調起JSAPI支付所需要的數據. 也就是后面返回的這幾個值
    appId: 也就是這里一直用的appid
    timeStamp: 注意,這里是時間戳, 我們之前調起失敗, 也是因為這里沒用時間錯
    nonceStr: 隨機字符
    signType: 簽名方式, 和我們調用統一下單生成的簽名方式一樣. 也要設置為MD5
    package: 包名. 注意: 不能寫 package, 因為是關鍵字
    paySign: 簽名
  • // 獲取當前請求的ip地址String requestIp = CommonUtils.getIpAddr(request);// 拼接統一下單地址參數SortedMap<String,String> params = new TreeMap<>();params.put("appid", appid);params.put("body", remark);params.put("mch_id", merId);params.put("nonce_str", CommonUtils.generateUUID());params.put("openid", openId);params.put("out_trade_no", out_trade_no);//訂單號params.put("spbill_create_ip", requestIp);params.put("total_fee","100");params.put("sign_type", "MD5");params.put("trade_type", "JSAPI");params.put("notify_url", weChatConfig.notify_url);String sign = WXPayUtil.createSign(params, weChatConfig.key);// 生成簽名之后, 注意一定要存進去.params.put("sign", sign);String payXml;try {// 微信支付要求這里必須是一個xmlpayXml = WXPayUtil.mapToXml(params);log.info("payXml: "+payXml);// 調用微信的統一下單接口String orderStr = HttpUtils.doPost("https://api.mch.weixin.qq.com/pay/unifiedorder",payXml,4000);log.info("統一下單返回結果: "+orderStr);if(StringUtils.isEmpty(orderStr)){log.error("微信支付失敗.原因: 調用微信統一下單接口失敗");throw new TPlusException(ErrorEnum.WECHAT_PAY_ERROR);}// 預支付idString prepay_id = "";if (orderStr.indexOf("SUCCESS") != -1) {// 這個工具類可以用微信官方案例中的Map<String, String> map = WXPayUtil.xmlToMap(orderStr);prepay_id = map.get("prepay_id");}/** 返回給前端所需要的數據 */SortedMap<String,String> payMap = new TreeMap<>();payMap.put("appId", appid);payMap.put("timeStamp", String.valueOf(new Date().getTime()/1000));payMap.put("nonceStr", CommonUtils.generateUUID());payMap.put("signType", "MD5");payMap.put("package", "prepay_id="+prepay_id);String paySign = WXPayUtil.createSign(payMap, key);payMap.put("paySign", paySign);return payMap;} catch (Exception e) {log.error("微信支付失敗.原因: map參數轉xml失敗({})", e.getMessage());throw new TPlusException(ErrorEnum.WECHAT_PAY_ERROR);}
  • 得到需要的數據之后, 前端來說就很簡單了, 直接可以根據返回的數據調起微信支付.
    也可參考: JSAPI調起支付文檔
  • function onBridgeReady(){WeixinJSBridge.invoke('getBrandWCPayRequest', {"appId":appId, //公眾號ID,由商戶傳入 "timeStamp":timeStamp, //時間戳,自1970年以來的秒數 "nonceStr":nonceStr, //隨機串 "package":package, "signType":signType, //微信簽名方式: "paySign":paySign //微信簽名 },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支付的時候, 通過本地是無法調用成功的, 必須發布到線上, 而且要在微信商戶平臺, 配置線上地址的授權域名.

    特別注意: 該域名必須和前端訪問的域名一致, 不可以配置主域名. 我們一直無法調起支付, 其中有一個坑也是這個原因.

    上面Java調用統一下單時所需要的工具類

  • CommonUtils
  • public class CommonUtils {/*** 生成uuid,即用來標識一筆單,也用做 微信支付的nonce_str* @return*/public static String generateUUID(){String uuid = UUID.randomUUID().toString().replaceAll("-","").substring(0,32);return uuid;}/*** 獲取用戶請求ip* @param request* @return*/public static String getIpAddr(HttpServletRequest request) {String ipAddress = request.getHeader("x-forwarded-for");if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {//根據網卡取本機配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}ipAddress = inet.getHostAddress();}}//對于通過多個代理的情況,第一個IP為客戶端真實IP,多個IP按照','分割if (ipAddress != null && ipAddress.length() > 15) { //"***.***.***.***".length() = 15if (ipAddress.indexOf(",") > 0) {ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));}}return ipAddress;}

    到此為止, 就已經完成了微信JSAPI支付, 以上純手寫, 如有錯誤的地方, 歡迎指教. 謝謝!

    總結

    以上是生活随笔為你收集整理的手把手教你实现Java微信JSAPI支付的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。