最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java接入微信支付詳細實現(xiàn)步驟

 更新時間:2025年09月30日 08:54:17   作者:阿海打醬油  
在Java中接入微信支付,通常需要通過微信提供的微信支付開放平臺來進行集成,這篇文章主要介紹了Java接入微信支付的詳細實現(xiàn)步驟,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

一:主要流程

(1)前期準備工作

①注冊認證微信公眾號/小程序

②申請微信商戶號

③配置API安全

(2)環(huán)境搭建和主要流程理解

①引入依賴

②確定支付方式,分析其流程

(3)核心代碼開發(fā)

①配置參數(shù)

②向微信發(fā)送請求

二:注意事項

(1)個人類型賬號無法開通微信支付

(2)切勿泄露APIV3秘鑰

三:步驟實現(xiàn)

官方文檔(以Native為例):產(chǎn)品介紹_Native支付|微信支付商戶文檔中心

先查看具體流程

(1)先注冊對應(yīng)的公眾號/小程序

官網(wǎng)鏈接:https://mp.weixin.qq.com/

(2)認證對應(yīng)的公眾號/小程序

①方法一:

②方法二:

(3)注冊商戶號,開通對應(yīng)的Native支付權(quán)限

官網(wǎng)鏈接:https://pay.weixin.qq.com/

開通步驟指引鏈接:申請Native支付權(quán)限指引_Native支付|微信支付商戶文檔中心

(4)綁定商戶號與APPID

對應(yīng)指引鏈接:管理商戶號綁定的APPID賬號_Native支付|微信支付商戶文檔中心

(5)獲取對應(yīng)參數(shù)開發(fā)

對應(yīng)指引鏈接:開發(fā)必要參數(shù)說明_通用規(guī)則|微信支付商戶文檔中心

(6)核心代碼開發(fā)

①推薦使用官方SDK:https://github.com/wechatpay-apiv3/wechatpay-java

②引入依賴

<dependency>
    <groupId>com.github.wechatpay-apiv3</groupId>
    <artifactId>wechatpay-java</artifactId>
    <version>0.4.13</version> <!-- 注意檢查最新版本 -->
</dependency>

③代碼實現(xiàn)

配置類:

@Configuration
public class WeChatPayConfig {

    @Value("${wechat.pay.mchid}")
    private String mchId;

    @Value("${wechat.pay.mchSerialNo}") // 你的商戶API證書序列號
    private String mchSerialNo;

    @Value("${wechat.pay.privateKeyPath}") // 你的.p12證書中的私鑰文件路徑 (.pem格式更佳)
    private String privateKeyPath;

    @Value("${wechat.pay.apiV3Key}")
    private String apiV3Key;

    @Value("${wechat.pay.certPath}") // 下載的微信平臺證書路徑
    private String certPath;

    /**
     * 創(chuàng)建私鑰簽名對象
     */
    @Bean
    public PrivateKey getPrivateKey() throws Exception {
        return PemUtil.loadPrivateKey(
            new FileInputStream(privateKeyPath));
    }

    /**
     * 創(chuàng)建自動更新的Verifier (驗證微信響應(yīng)簽名)
     */
    @Bean
    public Verifier getVerifier() throws Exception {
        // 方式1: 使用本地已下載的平臺證書 (簡單,需手動更新)
        // X509Certificate certificate = PemUtil.loadCertificate(new FileInputStream(certPath));
        // return new StaticVerifier(mchId, mchSerialNo, certificate);

        // 方式2: 使用自動更新機制 (推薦)
        ScheduledUpdateCertificatesVerifier verifier = 
            new ScheduledUpdateCertificatesVerifier(
                new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, getPrivateKey())),
                apiV3Key.getBytes(StandardCharsets.UTF_8));
        return verifier;
    }

    /**
     * 創(chuàng)建HttpClient (用于調(diào)用微信API)
     */
    @Bean
    public CloseableHttpClient getWxPayClient() throws Exception {
        return WechatPayHttpClientBuilder.create()
            .withMerchant(mchId, mchSerialNo, getPrivateKey())
            .withValidator(new WechatPay2Validator(getVerifier()))
            .build();
    }
}

服務(wù)層(統(tǒng)一下單)示例與代碼(需調(diào)整)

@Override
public String createNativeOrder(String outTradeNo, int totalFee, String body) {
    // ... 構(gòu)建請求參數(shù) (類似JSAPI,但去掉payer,增加scene_info等)
    json.put("appid", appid); // Native也需要appid
    json.put("mchid", mchId);
    json.put("description", body);
    json.put("out_trade_no", outTradeNo);
    json.put("notify_url", "https://yourdomain.com/api/wxpay/notify");

    JSONObject amount = new JSONObject();
    amount.put("total", totalFee);
    amount.put("currency", "CNY");
    json.put("amount", amount);

    // 場景信息 (可選)
    JSONObject sceneInfo = new JSONObject();
    sceneInfo.put("payer_client_ip", "用戶IP"); // 必須傳真實IP
    json.put("scene_info", sceneInfo);

    // 發(fā)送請求到 Native 接口
    try {
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
        // ... 同上設(shè)置請求頭和實體
        // 解析響應(yīng),獲取 code_url
        JSONObject result = JSON.parseObject(responseString);
        return result.getString("code_url"); // 返回二維碼鏈接
    } catch (Exception e) {
        throw new RuntimeException("創(chuàng)建Native訂單失敗", e);
    }
}

④回調(diào)處理

注意:此路徑必須是公網(wǎng)能訪問的路徑

@RestController
@RequestMapping("/api/wxpay")
public class WeChatPayController {

    @Autowired
    private WeChatPayService weChatPayService;

    @PostMapping("/create-jsapi-order")
    public ResponseEntity<Map<String, String>> createJsapiOrder(@RequestBody PayRequest request) {
        // 獲取用戶openid (通常由前端通過登錄態(tài)傳遞或后端通過code換取)
        String openid = getUserOpenidFromSessionOrToken(request.getToken());
        Map<String, String> result = weChatPayService.createJsapiOrder(
            openid, request.getOutTradeNo(), request.getTotalFee(), request.getBody());
        return ResponseEntity.ok(result);
    }

    @PostMapping("/notify")
    public ResponseEntity<String> handleNotify(@RequestBody String notifyData, 
                                              HttpServletRequest request) {
        try {
            // 1. 驗證通知的簽名和有效性 (SDK提供了工具類)
            // 這里需要解析請求頭中的 Wechatpay-Signature, Wechatpay-Nonce, Wechatpay-Timestamp
            String signature = request.getHeader("Wechatpay-Signature");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String body = notifyData; // 請求體

            // 使用之前配置的Verifier來驗證
            // boolean isValid = verifier.verify(timestamp, nonce, body, signature);
            // if (!isValid) {
            //     return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("簽名驗證失敗");
            // }

            // 2. 解密通知數(shù)據(jù) (APIv3通知體是加密的)
            AesUtil aesUtil = new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8));
            String plainText = aesUtil.decryptToString(
                nonce.getBytes(StandardCharsets.UTF_8),
                associatedData.getBytes(StandardCharsets.UTF_8), // 關(guān)聯(lián)數(shù)據(jù)
                ciphertext.getBytes(StandardCharsets.UTF_8)); // 密文

            // 3. 解析解密后的JSON數(shù)據(jù)
            JSONObject notifyDataObj = JSON.parseObject(plainText);
            String eventType = notifyDataObj.getString("event_type");
            JSONObject resource = notifyDataObj.getJSONObject("resource");
            String ciphertext = resource.getString("ciphertext"); // 加密的數(shù)據(jù)包
            String associatedData = resource.getString("associated_data");
            String nonce = resource.getString("nonce");

            // 再次解密ciphertext得到最終的訂單信息
            String orderInfo = aesUtil.decryptToString(nonce.getBytes(), 
                associatedData.getBytes(), ciphertext.getBytes());
            JSONObject orderData = JSON.parseObject(orderInfo);

            String outTradeNo = orderData.getString("out_trade_no");
            String transactionId = orderData.getString("transaction_id");
            String tradeState = orderData.getString("trade_state"); // SUCCESS為支付成功

            // 4. 業(yè)務(wù)處理
            if ("SUCCESS".equals(tradeState)) {
                // TODO: 更新你的數(shù)據(jù)庫訂單狀態(tài)為"已支付"
                // TODO: 執(zhí)行發(fā)貨、積分發(fā)放等后續(xù)業(yè)務(wù)邏輯
                // TODO: 記錄日志
            } else if ("CLOSED".equals(tradeState) || "REVOKED".equals(tradeState)) {
                // 支付失敗或關(guān)閉
            }

            // 5. 返回成功響應(yīng) (必須是200且內(nèi)容為"success")
            return ResponseEntity.ok().body("{\"code\":\"SUCCESS\",\"message\":\"成功\"}");
        } catch (Exception e) {
            // 記錄詳細的錯誤日志
            log.error("處理微信支付通知失敗", e);
            // 返回失敗,微信會在一段時間后重試
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("");
        }
    }
}

工具類

public class WeChatPayUtil {
    // 生成JSAPI調(diào)用所需參數(shù)的簽名 (注意:這是RSA-SHA256,不是APIv3的HMAC-SHA256)
    public static String sign(Map<String, String> params, String apiKey) {
        // 1. 參數(shù)按key ASCII排序
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);

        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            String value = params.get(key);
            if (value != null && !value.trim().isEmpty() && !"sign".equals(key)) {
                sb.append(key).append("=").append(value).append("&");
            }
        }
        sb.append("key=").append(apiKey);

        // 2. 計算MD5 (舊版) 或 HMAC-SHA256 (新版推薦,但JSAPI仍多用MD5?實際看文檔)
        // 注意:微信JSAPI目前主流仍是MD5,但請查閱最新官方文檔確認!
        String stringA = sb.toString();
        String sign = DigestUtils.md5Hex(stringA).toUpperCase();

        return sign;
    }
}

四:總結(jié)

對接微信支付主要繁瑣的是前期商戶號、證書、配置,需仔細閱讀文檔,后續(xù)對接SDK非常簡單,注意處理冪等性

到此這篇關(guān)于Java接入微信支付的文章就介紹到這了,更多相關(guān)Java接入微信支付內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot攔截器如何獲取http請求參數(shù)

    SpringBoot攔截器如何獲取http請求參數(shù)

    這篇文章主要給大家介紹了SpringBoot攔截器如何獲取http請求參數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • Spring中的AOP面向切面編程詳解

    Spring中的AOP面向切面編程詳解

    這篇文章主要介紹了Spring中的AOP面向切面編程詳解,AOP?即面向切面編程,和?OOP面向?qū)ο缶幊填愃?也是一種編程思想,AOP采取橫向抽取機制(動態(tài)代理),取代了傳統(tǒng)縱向繼承機制的重復性代碼,其應(yīng)用主要體現(xiàn)在事務(wù)處理、日志管理、權(quán)限控制等方面,需要的朋友可以參考下
    2024-01-01
  • Java中的雪花算法Snowflake解析與實踐技巧

    Java中的雪花算法Snowflake解析與實踐技巧

    本文解析了雪花算法的原理、Java實現(xiàn)及生產(chǎn)實踐,涵蓋ID結(jié)構(gòu)、位運算技巧、時鐘回撥處理、WorkerId分配等關(guān)鍵點,并探討了百度UidGenerator、美團Leaf等擴展方案,強調(diào)配置優(yōu)化、監(jiān)控告警和容災(zāi)機制在實際應(yīng)用中的重要性,感興趣的朋友一起看看吧
    2025-06-06
  • SpringCloud實現(xiàn)Eureka服務(wù)注冊與發(fā)現(xiàn)

    SpringCloud實現(xiàn)Eureka服務(wù)注冊與發(fā)現(xiàn)

    這篇文章主要介紹了SpringCloud如何實現(xiàn)Eureka服務(wù)注冊與發(fā)現(xiàn),幫助大家更好的理解和學習使用SpringCloud,感興趣的朋友可以了解下
    2021-05-05
  • dubbo服務(wù)注冊到nacos的過程剖析

    dubbo服務(wù)注冊到nacos的過程剖析

    這篇文章主要為大家介紹了dubbo服務(wù)注冊到nacos的過程剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職極限
    2022-02-02
  • java線程組構(gòu)造方法源碼解析

    java線程組構(gòu)造方法源碼解析

    這篇文章主要為大家介紹了java線程組構(gòu)造方法源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Java程序中Doc文檔注釋示例教程

    Java程序中Doc文檔注釋示例教程

    這篇文章主要為大家介紹了Java程序中Doc文檔注釋的示例教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2021-10-10
  • SpringBoot詳解整合MyBatis過程中可能遇到的問題

    SpringBoot詳解整合MyBatis過程中可能遇到的問題

    因為Spring Boot框架開發(fā)的便利性,所以實現(xiàn)Spring Boot與數(shù)據(jù)訪問層框架(例如MyBatis)的整合非常簡單,主要是引入對應(yīng)的依賴啟動器,并進行數(shù)據(jù)庫相關(guān)參數(shù)設(shè)置即可
    2022-07-07
  • SpringBoot自定義starter啟動器的實現(xiàn)思路

    SpringBoot自定義starter啟動器的實現(xiàn)思路

    這篇文章主要介紹了SpringBoot如何自定義starter啟動器,通過starter的自定義過程,能夠加深大家對SpringBoot自動配置原理的理解,需要的朋友可以參考下
    2022-10-10
  • Java Swing仿QQ登錄界面效果

    Java Swing仿QQ登錄界面效果

    這篇文章主要為大家詳細介紹了Java Swing仿QQ登錄界面效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05

最新評論

资阳市| 阳原县| 盐池县| 任丘市| 涿州市| 湖口县| 大田县| 元朗区| 青川县| 万荣县| 鹤岗市| 南阳市| 岳普湖县| 桐梓县| 黔南| 甘德县| 酉阳| 怀宁县| 通许县| 垦利县| 广州市| 綦江县| 莱西市| 永吉县| 林周县| 雷州市| 清流县| 楚雄市| 颍上县| 临武县| 宁强县| 锡林郭勒盟| 渭源县| 泰和县| 滨海县| 句容市| 广河县| 盱眙县| 桂平市| 甘谷县| 肇源县|