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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

微信扫码支付实现

發(fā)布時(shí)間:2023/12/10 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 微信扫码支付实现 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

文章目錄

    • 微信平臺(tái)信息配置
      • 獲取商戶(hù)號(hào)
      • 獲取證書(shū)序列號(hào)
      • 獲取API私鑰
      • 獲取APIv3密鑰
      • 獲取并綁定APPID
      • 開(kāi)通支付產(chǎn)品
    • 代碼中的配置
      • 引入依賴(lài)
      • 配置微信工具類(lèi)
      • 支付請(qǐng)求
      • 回調(diào)接口

微信平臺(tái)信息配置

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

獲取商戶(hù)號(hào)

  • 登錄微信開(kāi)放平臺(tái)
  • 如果是主賬號(hào),如圖紅框位置即為商戶(hù)號(hào)。如果不是商戶(hù)主帳號(hào),顯示的則為個(gè)人帳號(hào)(如圖為子管理員賬號(hào))
  • 如果登陸賬號(hào)不是主賬號(hào),則需要依次點(diǎn)擊產(chǎn)品中心→AppID賬號(hào)管理→+關(guān)聯(lián)AppID,此時(shí)即可看到商戶(hù)號(hào)
  • 獲取證書(shū)序列號(hào)

    該步驟操作需要商戶(hù)主賬號(hào)才可完成。

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

    在獲取證書(shū)序列號(hào)的第二步操作中的apiclient_key.pem文件即為所需的商戶(hù)API私鑰。
    注意:此處有一個(gè)小坑,在粘貼復(fù)制密鑰時(shí),除了保留-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----的換行外,中間內(nèi)容在粘貼時(shí)一定要去除復(fù)制時(shí)產(chǎn)生的換行符(推薦復(fù)制內(nèi)容后去網(wǎng)上的去換行工具中去除下?lián)Q行符)

    獲取APIv3密鑰

  • 依舊是在API安全頁(yè),直接點(diǎn)擊設(shè)置來(lái)設(shè)置APIv3密鑰即可。
  • APIv3密鑰要求是32個(gè)字符,支持?jǐn)?shù)字/大小寫(xiě)字母,可以在隨機(jī)生成字符串的線上工具中進(jìn)行生成
  • 將上一步生成的密鑰復(fù)制粘貼,完成手機(jī)號(hào)驗(yàn)證碼安全認(rèn)證即可完成APIv3密鑰的設(shè)置
  • 獲取并綁定APPID

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

  • 登錄微信公眾平臺(tái),依次點(diǎn)擊設(shè)置→基本設(shè)置,頁(yè)面最下方賬號(hào)信息處即可看到AppID(小程序ID)

  • 在微信公眾平臺(tái),依次點(diǎn)擊設(shè)置→基本設(shè)置,找到主體信息

  • 回到微信開(kāi)放平臺(tái),依次點(diǎn)擊產(chǎn)品中心→AppID賬號(hào)管理→+關(guān)聯(lián)AppID,將上一步獲取到的AppID和主體信息粘貼在此并提交

  • 回到微信公眾平臺(tái)授權(quán)即可

  • 開(kāi)通支付產(chǎn)品

  • 登錄微信開(kāi)放平臺(tái),來(lái)到產(chǎn)品中心頁(yè)面。
  • 開(kāi)啟支付產(chǎn)品中的Native支付(掃碼支付)功能。
  • 開(kāi)啟運(yùn)營(yíng)工具中的企業(yè)付款到零錢(qián)(付款資金直接進(jìn)入微信零錢(qián),提現(xiàn)方式根據(jù)用戶(hù)需求來(lái)開(kāi)通不同產(chǎn)品即可)。
  • 代碼中的配置

    對(duì)于v3支付來(lái)說(shuō),此時(shí)可謂萬(wàn)事俱備只欠東風(fēng),下面來(lái)配置代碼中的工具類(lèi)和第三方請(qǐng)求。

    引入依賴(lài)

    此處引入的是v3支付

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

    配置微信工具類(lèi)

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

  • 配置商戶(hù)信息
  • 微信接口請(qǐng)求所需工具方法
  • 微信驗(yàn)簽
  • public class WeChartUtil {public static final String MERCHANT_ID = "商戶(hù)id";public static final String MERCHANT_SERIAL_NUMBER = "證書(shū)序列號(hào)";public static final String MERCHANT_PRIVATEKEY = "-----BEGIN PRIVATE KEY-----\n" + "你的密鑰內(nèi)容(記得去換行)" +"\n" + "-----END PRIVATE KEY-----";public static final String AIV3KEY = "APIv3密鑰";public static final String NOTIFY_URL = "回調(diào)地址";public static final String APP_ID = "小程序的AppID";/*** @Author Spence_Dou* @Description 生成訂單號(hào)* @Date 11:35 2021/12/23* @return void*/public static String orderNo(){return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);}/*** @Author Spence_Dou* @Description 生成訂單過(guò)期時(shí)間* @Date 11:41 2021/12/23* @return java.time.LocalDateTime*/public static String timeExpire(){//過(guò)期時(shí)間:5分鐘后long time = 5*60*1000;SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");Date now = new Date();//30分鐘后的時(shí)間Date afterDate = new Date(now.getTime() + time);return simpleDateFormat.format(afterDate);}/*** @Author Spence_Dou* @Description 分轉(zhuǎn)元 保留小數(shù)點(diǎn)后兩位* @Date 11:38 2021/12/23* @Param num 轉(zhuǎn)換金額* @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 微信支付回調(diào)簽名驗(yàn)證* @Date 16:30 2021/12/23* @Param serial 請(qǐng)求頭序列號(hào)* @Param message 請(qǐng)求報(bào)文* @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 請(qǐng)求數(shù)據(jù)* @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 關(guān)閉訂單* @Date 17:34 2021/12/23* @Param outTradeNo 訂單號(hào)* @return void*/public static void closeOrder(String outTradeNo) {PrivateKey key = PemUtil.loadPrivateKey(new ByteArrayInputStream(MERCHANT_PRIVATEKEY.getBytes(StandardCharsets.UTF_8)));// 使用定時(shí)更新的簽名驗(yàn)證器,不需要傳入證書(shū)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();}} }

    支付請(qǐng)求

    • 該請(qǐng)求方式參照文章開(kāi)頭提供的SDK開(kāi)發(fā)工具包中的請(qǐng)求方式
    • 不同的產(chǎn)品應(yīng)參考 API字典 請(qǐng)求不同的地址,此處以Native支付為例
    PrivateKey key = PemUtil.loadPrivateKey(new ByteArrayInputStream(WeChartUtil.MERCHANT_PRIVATEKEY.getBytes(StandardCharsets.UTF_8)));// 使用定時(shí)更新的簽名驗(yàn)證器,不需要傳入證書(shū)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));// 通過(guò)WechatPayHttpClientBuilder構(gòu)造的HttpClient,會(huì)自動(dòng)的處理簽名和驗(yàn)簽,并進(jìn)行證書(shū)自動(dòng)更新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();// 生成訂單號(hào)String outTradeNo = WeChartUtil.orderNo();// 請(qǐng)求參數(shù)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());// 這里就是請(qǐng)求支付后返回的數(shù)據(jù)了JSONObject details = JSONObject.parseObject(bodyAsString);// 支付二維碼String qrCode= details.getString("code_url");/*** 此處可進(jìn)行訂單數(shù)據(jù)持久化等業(yè)務(wù)操作* ...*/} catch (IOException e) {e.printStackTrace();}

    回調(diào)接口

    • 這里就是v3支付和v2支付一個(gè)比較明顯的區(qū)別點(diǎn),v2支付的回調(diào)地址是在官方網(wǎng)站中配置的,而v3支付中,回調(diào)地址是作為請(qǐng)求參數(shù)傳遞到微信的
    • 此接口地址對(duì)應(yīng)支付請(qǐng)求時(shí)的請(qǐng)求參數(shù)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");// 驗(yà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());// 驗(yàn)證訂單JSONObject details = JSONObject.parseObject(decryptOrder);// 獲取訂單狀態(tài)String ciphertext = details.getString("trade_state");if ("SUCCESS".equals(ciphertext)){/*** 此處可進(jìn)行訂單狀態(tài)數(shù)據(jù)持久化等業(yè)務(wù)操作* ...*/result.put("code", "SUCCESS");result.put("message", "成功");// 關(guān)閉訂單WeChartUtil.closeOrder(details.getString("out_trade_no"));}} catch (IOException e) {e.printStackTrace();//強(qiáng)制手動(dòng)事務(wù)回滾TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}return result;}

    總結(jié)

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

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。