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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

微信扫码支付实现

發布時間:2023/12/10 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 微信扫码支付实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言:在一次項目開發中我的業務模塊涉及微信掃碼支付和支付寶掃碼支付。在查閱現有文檔后發現,大部分文章還停留在V2支付,部分文章介紹了V3支付但是并不能走通,于是我便閱讀了官方文檔,形成了這篇總結性文章,希望對讀者有所幫助。
官方開發文檔
官方SDK開發工具包
API字典

文章目錄

    • 微信平臺信息配置
      • 獲取商戶號
      • 獲取證書序列號
      • 獲取API私鑰
      • 獲取APIv3密鑰
      • 獲取并綁定APPID
      • 開通支付產品
    • 代碼中的配置
      • 引入依賴
      • 配置微信工具類
      • 支付請求
      • 回調接口

微信平臺信息配置

相信此刻你一定已經注冊并登陸過 微信開放平臺 了,在此不多贅述。需在平臺中獲取的開發所需信息如下:
MERCHANT_ID:商戶號
MERCHANT_SERIAL_NUMBER:商戶API證書的證書序列號
MERCHANT_PRIVATEKEY:商戶API私鑰
AIV3KEY:API v3密鑰
APP_ID:小程序的APPID
注意:想要獲取以上信息,必須是商戶主賬號才可以(即便是管理員,部分操作也無法完成)。
下面我們來逐個獲取以上參數

獲取商戶號

  • 登錄微信開放平臺
  • 如果是主賬號,如圖紅框位置即為商戶號。如果不是商戶主帳號,顯示的則為個人帳號(如圖為子管理員賬號)
  • 如果登陸賬號不是主賬號,則需要依次點擊產品中心→AppID賬號管理→+關聯AppID,此時即可看到商戶號
  • 獲取證書序列號

    該步驟操作需要商戶主賬號才可完成。

  • 依次點擊賬戶中心→API安全,此時就進入了API安全頁,此頁面可設置一個證書兩個密鑰,API證書是根據網站提供的工具生成的(具體下載操作可參考網站中給出的指引)
  • 對微信工具生成的文件進行解壓縮得到如下信息,后續操作可根據’證書使用說明.txt進行(提示一下:Windows用戶直接雙擊apiclient_cert.p12文件即可上傳證書)。
  • 在根據網站指引完成了API證書上傳后,商戶主賬號就可直接點擊管理證書查看證書序列號。
  • 獲取API私鑰

    在獲取證書序列號的第二步操作中的apiclient_key.pem文件即為所需的商戶API私鑰。
    注意:此處有一個小坑,在粘貼復制密鑰時,除了保留-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----的換行外,中間內容在粘貼時一定要去除復制時產生的換行符(推薦復制內容后去網上的去換行工具中去除下換行符)

    獲取APIv3密鑰

  • 依舊是在API安全頁,直接點擊設置來設置APIv3密鑰即可。
  • APIv3密鑰要求是32個字符,支持數字/大小寫字母,可以在隨機生成字符串的線上工具中進行生成
  • 將上一步生成的密鑰復制粘貼,完成手機號驗證碼安全認證即可完成APIv3密鑰的設置
  • 獲取并綁定APPID

    公眾號和小程序的AppID獲取方式雷同,具體參考如圖所示指引

  • 登錄微信公眾平臺,依次點擊設置→基本設置,頁面最下方賬號信息處即可看到AppID(小程序ID)

  • 在微信公眾平臺,依次點擊設置→基本設置,找到主體信息

  • 回到微信開放平臺,依次點擊產品中心→AppID賬號管理→+關聯AppID,將上一步獲取到的AppID和主體信息粘貼在此并提交

  • 回到微信公眾平臺授權即可

  • 開通支付產品

  • 登錄微信開放平臺,來到產品中心頁面。
  • 開啟支付產品中的Native支付(掃碼支付)功能。
  • 開啟運營工具中的企業付款到零錢(付款資金直接進入微信零錢,提現方式根據用戶需求來開通不同產品即可)。
  • 代碼中的配置

    對于v3支付來說,此時可謂萬事俱備只欠東風,下面來配置代碼中的工具類和第三方請求。

    引入依賴

    此處引入的是v3支付

    <dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>0.3.0</version> </dependency>

    配置微信工具類

    此工具類僅供參考,配置信息也可根據個人喜好放在yml文件中(為方便閱讀此處放在類中作為常量)。
    此處的工具類有以下作用:

  • 配置商戶信息
  • 微信接口請求所需工具方法
  • 微信驗簽
  • public class WeChartUtil {public static final String MERCHANT_ID = "商戶id";public static final String MERCHANT_SERIAL_NUMBER = "證書序列號";public static final String MERCHANT_PRIVATEKEY = "-----BEGIN PRIVATE KEY-----\n" + "你的密鑰內容(記得去換行)" +"\n" + "-----END PRIVATE KEY-----";public static final String AIV3KEY = "APIv3密鑰";public static final String NOTIFY_URL = "回調地址";public static final String APP_ID = "小程序的AppID";/*** @Author Spence_Dou* @Description 生成訂單號* @Date 11:35 2021/12/23* @return void*/public static String orderNo(){return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);}/*** @Author Spence_Dou* @Description 生成訂單過期時間* @Date 11:41 2021/12/23* @return java.time.LocalDateTime*/public static String timeExpire(){//過期時間:5分鐘后long time = 5*60*1000;SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");Date now = new Date();//30分鐘后的時間Date afterDate = new Date(now.getTime() + time);return simpleDateFormat.format(afterDate);}/*** @Author Spence_Dou* @Description 分轉元 保留小數點后兩位* @Date 11:38 2021/12/23* @Param num 轉換金額* @return java.lang.String*/public static BigDecimal transition(Integer num) {BigDecimal bigDecimal1 = new BigDecimal(num + "");BigDecimal bigDecimal2 = new BigDecimal("100.00");return bigDecimal1.divide(bigDecimal2).setScale(2);}/*** @Author Spence_Dou* @Description 微信支付回調簽名驗證* @Date 16:30 2021/12/23* @Param serial 請求頭序列號* @Param message 請求報文* @Param signature 簽名* @return boolean*/public static boolean signVerify(String serial, String message, String signature) {try {PrivateKey key = PemUtil.loadPrivateKey(new ByteArrayInputStream(MERCHANT_PRIVATEKEY.getBytes(StandardCharsets.UTF_8)));ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(new WechatPay2Credentials(MERCHANT_ID, new PrivateKeySigner(MERCHANT_SERIAL_NUMBER, key)),AIV3KEY.getBytes(StandardCharsets.UTF_8));return verifier.verify(serial, message.getBytes(StandardCharsets.UTF_8), signature);} catch (Exception e) {e.printStackTrace();}return false;}/*** @Author Spence_Dou* @Description 解密密文* @Date 17:04 2021/12/23* @Param body 請求數據* @return java.lang.String*/public static String decryptOrder(String body){try {AesUtil util = new AesUtil(AIV3KEY.getBytes(StandardCharsets.UTF_8));ObjectMapper objectMapper = new ObjectMapper();JsonNode node = objectMapper.readTree(body);JsonNode resource = node.get("resource");String ciphertext = resource.get("ciphertext").textValue();String associatedData = resource.get("associated_data").textValue();String nonce = resource.get("nonce").textValue();return util.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);} catch (IOException | GeneralSecurityException e) {e.printStackTrace();}return null;}/*** @Author Spence_Dou* @Description 關閉訂單* @Date 17:34 2021/12/23* @Param outTradeNo 訂單號* @return void*/public static void closeOrder(String outTradeNo) {PrivateKey key = PemUtil.loadPrivateKey(new ByteArrayInputStream(MERCHANT_PRIVATEKEY.getBytes(StandardCharsets.UTF_8)));// 使用定時更新的簽名驗證器,不需要傳入證書ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(new WechatPay2Credentials(MERCHANT_ID, new PrivateKeySigner(MERCHANT_SERIAL_NUMBER, key)),AIV3KEY.getBytes(StandardCharsets.UTF_8));WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create().withMerchant(MERCHANT_ID, MERCHANT_SERIAL_NUMBER, key).withValidator(new WechatPay2Validator(verifier));CloseableHttpClient httpClient = builder.build();HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/"+outTradeNo+"/close");httpPost.addHeader("Accept", "application/json");httpPost.addHeader("Content-type","application/json; charset=utf-8");try {ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectMapper objectMapper = new ObjectMapper();ObjectNode rootNode = objectMapper.createObjectNode();rootNode.put("mchid",MERCHANT_ID);objectMapper.writeValue(bos, rootNode);httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));CloseableHttpResponse response = httpClient.execute(httpPost);String bodyAsString = EntityUtils.toString(response.getEntity());System.out.println(bodyAsString);} catch (IOException e) {e.printStackTrace();}} }

    支付請求

    • 該請求方式參照文章開頭提供的SDK開發工具包中的請求方式
    • 不同的產品應參考 API字典 請求不同的地址,此處以Native支付為例
    PrivateKey key = PemUtil.loadPrivateKey(new ByteArrayInputStream(WeChartUtil.MERCHANT_PRIVATEKEY.getBytes(StandardCharsets.UTF_8)));// 使用定時更新的簽名驗證器,不需要傳入證書ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(new WechatPay2Credentials(WeChartUtil.MERCHANT_ID, new PrivateKeySigner(WeChartUtil.MERCHANT_SERIAL_NUMBER, key)),WeChartUtil.AIV3KEY.getBytes(StandardCharsets.UTF_8));WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create().withMerchant(WeChartUtil.MERCHANT_ID, WeChartUtil.MERCHANT_SERIAL_NUMBER, key).withValidator(new WechatPay2Validator(verifier));// 通過WechatPayHttpClientBuilder構造的HttpClient,會自動的處理簽名和驗簽,并進行證書自動更新CloseableHttpClient httpClient = builder.build();HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");httpPost.addHeader("Accept", "application/json");httpPost.addHeader("Content-type","application/json; charset=utf-8");ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectMapper objectMapper = new ObjectMapper();// 生成訂單號String outTradeNo = WeChartUtil.orderNo();// 請求參數ObjectNode rootNode = objectMapper.createObjectNode();rootNode.put("mchid",WeChartUtil.MERCHANT_ID).put("appid", WeChartUtil.APP_ID).put("notify_url", WeChartUtil.NOTIFY_URL).put("out_trade_no", outTradeNo).put("time_expire", WeChartUtil.timeExpire()).put("description", description); // 訂單描述(前端獲取)rootNode.putObject("amount").put("total", 1); // 此處支付金額單位為分try {objectMapper.writeValue(bos, rootNode);httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));CloseableHttpResponse response = httpClient.execute(httpPost);String bodyAsString = EntityUtils.toString(response.getEntity());// 這里就是請求支付后返回的數據了JSONObject details = JSONObject.parseObject(bodyAsString);// 支付二維碼String qrCode= details.getString("code_url");/*** 此處可進行訂單數據持久化等業務操作* ...*/} catch (IOException e) {e.printStackTrace();}

    回調接口

    • 這里就是v3支付和v2支付一個比較明顯的區別點,v2支付的回調地址是在官方網站中配置的,而v3支付中,回調地址是作為請求參數傳遞到微信的。
    • 此接口地址對應支付請求時的請求參數notify_url,具體功能介紹在此不做闡述
    public Map wxCallback(HttpServletRequest request) {Map result = new HashMap();result.put("code", "FAIL");try {StringBuilder signStr = new StringBuilder();signStr.append(request.getHeader("Wechatpay-Timestamp")).append("\n");signStr.append(request.getHeader("Wechatpay-Nonce")).append("\n");BufferedReader br = request.getReader();String str = null;StringBuilder builder = new StringBuilder();while ((str = br.readLine()) != null){builder.append(str);}signStr.append(builder.toString()).append("\n");// 驗證簽名if (!WeChartUtil.signVerify(request.getHeader("Wechatpay-Serial"), signStr.toString(), request.getHeader("Wechatpay-Signature"))){result.put("message", "sign error");return result;}// 解密密文String decryptOrder = WeChartUtil.decryptOrder(builder.toString());// 驗證訂單JSONObject details = JSONObject.parseObject(decryptOrder);// 獲取訂單狀態String ciphertext = details.getString("trade_state");if ("SUCCESS".equals(ciphertext)){/*** 此處可進行訂單狀態數據持久化等業務操作* ...*/result.put("code", "SUCCESS");result.put("message", "成功");// 關閉訂單WeChartUtil.closeOrder(details.getString("out_trade_no"));}} catch (IOException e) {e.printStackTrace();//強制手動事務回滾TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}return result;}

    總結

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

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