欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot+MyBatis集成微信支付實(shí)現(xiàn)示例

 更新時(shí)間:2025年06月06日 09:30:23   作者:yuren_xia  
本文主要介紹了SpringBoot+MyBatis集成微信支付實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

下面我將詳細(xì)介紹使用 Spring Boot + MyBatis 實(shí)現(xiàn)微信支付(JSAPI支付)的完整流程和代碼示例。

微信支付核心流程(JSAPI支付)

  • 商戶系統(tǒng)生成訂單
  • 獲取用戶OpenID(微信公眾號支付)
  • 調(diào)用微信統(tǒng)一下單API
  • 生成JSAPI調(diào)起支付參數(shù)
  • 前端調(diào)起微信支付
  • 微信異步通知支付結(jié)果
  • 商戶處理支付結(jié)果更新訂單狀態(tài)
  • 返回處理結(jié)果給微信

代碼實(shí)現(xiàn)示例

1. 添加依賴

<!-- pom.xml -->
<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- MyBatis & MySQL -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    
    <!-- 微信支付SDK -->
    <dependency>
        <groupId>com.github.wechatpay-apiv3</groupId>
        <artifactId>wechatpay-apache-httpclient</artifactId>
        <version>0.4.7</version>
    </dependency>
    
    <!-- XML處理 -->
    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
    </dependency>
    
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

2. 微信支付配置類

@Configuration
public class WxPayConfig {

    @Value("${wxpay.app_id}")
    private String appId;
    
    @Value("${wxpay.mch_id}")
    private String mchId;
    
    @Value("${wxpay.mch_key}")
    private String mchKey;
    
    @Value("${wxpay.notify_url}")
    private String notifyUrl;
    
    @Value("${wxpay.cert_path}")
    private String certPath; // 證書路徑(apiclient_cert.p12)
    
    @Value("${wxpay.api_v3_key}")
    private String apiV3Key;

    // 微信支付HttpClient
    @Bean
    public CloseableHttpClient wxPayHttpClient() throws Exception {
        // 加載商戶私鑰
        PrivateKey merchantPrivateKey = getPrivateKey();
        
        // 使用自動更新平臺證書的驗(yàn)證器
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),
                apiV3Key.getBytes(StandardCharsets.UTF_8));
        
        // 初始化httpClient
        return WechatPayHttpClientBuilder.create()
                .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier))
                .build();
    }

    // 獲取商戶私鑰
    private PrivateKey getPrivateKey() throws Exception {
        InputStream inputStream = new ClassPathResource(certPath).getInputStream();
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(inputStream, mchId.toCharArray());
        return (PrivateKey) keyStore.getKey(mchId, mchId.toCharArray());
    }

    // 微信支付服務(wù)
    @Bean
    public WxPayService wxPayService(CloseableHttpClient wxPayHttpClient) {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(appId);
        payConfig.setMchId(mchId);
        payConfig.setKey(mchKey);
        payConfig.setNotifyUrl(notifyUrl);
        payConfig.setApiV3Key(apiV3Key);
        return new WxPayServiceImpl(payConfig, wxPayHttpClient);
    }
}

3. 實(shí)體類和Mapper

// 訂單實(shí)體
@Data
public class Order {
    private Long id;
    private String orderNo;   // 商戶訂單號
    private BigDecimal amount;// 支付金額
    private Integer status;   // 0-待支付, 1-已支付
    private LocalDateTime createTime;
    private String openid;    // 微信用戶openid
}

// MyBatis Mapper
@Mapper
public interface OrderMapper {
    @Insert("INSERT INTO orders(order_no, amount, status, create_time, openid) " +
            "VALUES(#{orderNo}, #{amount}, 0, NOW(), #{openid})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    void insert(Order order);
    
    @Update("UPDATE orders SET status = #{status} WHERE order_no = #{orderNo}")
    void updateStatus(@Param("orderNo") String orderNo, @Param("status") int status);
    
    @Select("SELECT * FROM orders WHERE order_no = #{orderNo}")
    Order findByOrderNo(String orderNo);
}

4. 支付服務(wù)類

@Service
public class WxPayService {

    @Autowired private WxPayService wxPayService;
    @Autowired private OrderMapper orderMapper;

    // 創(chuàng)建支付訂單
    public Map<String, String> createPayOrder(Order order) throws Exception {
        orderMapper.insert(order); // 保存訂單到數(shù)據(jù)庫

        // 構(gòu)建統(tǒng)一下單請求
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setBody("商品支付");
        request.setOutTradeNo(order.getOrderNo());
        request.setTotalFee(order.getAmount().multiply(new BigDecimal(100)).intValue()); // 微信支付單位為分
        request.setSpbillCreateIp("用戶IP"); // 實(shí)際獲取用戶IP
        request.setNotifyUrl(wxPayConfig.getNotifyUrl());
        request.setTradeType("JSAPI");
        request.setOpenid(order.getOpenid());

        // 調(diào)用統(tǒng)一下單API
        WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(request);
        
        // 生成JSAPI調(diào)起支付參數(shù)
        Map<String, String> payParams = new HashMap<>();
        payParams.put("appId", appId);
        payParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
        payParams.put("nonceStr", WxPayUtil.generateNonceStr());
        payParams.put("package", "prepay_id=" + result.getPrepayId());
        payParams.put("signType", "RSA");
        
        // 生成簽名
        String sign = WxPayUtil.generateSignature(payParams, mchKey);
        payParams.put("paySign", sign);
        
        return payParams;
    }

    // 處理支付結(jié)果通知
    public String handleNotify(HttpServletRequest request) {
        try {
            // 解析通知內(nèi)容
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlResult);

            // 驗(yàn)證簽名和業(yè)務(wù)結(jié)果
            if ("SUCCESS".equals(notifyResult.getResultCode())) {
                // 更新訂單狀態(tài)
                String orderNo = notifyResult.getOutTradeNo();
                orderMapper.updateStatus(orderNo, 1); // 更新為已支付
                
                // 返回成功響應(yīng)
                return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
            }
        } catch (Exception e) {
            // 記錄日志
        }
        return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[處理失敗]]></return_msg></xml>";
    }
}

5. 控制器

@RestController
@RequestMapping("/wxpay")
public class WxPayController {

    @Autowired private WxPayService wxPayService;

    // 創(chuàng)建支付訂單(返回調(diào)起支付所需參數(shù))
    @PostMapping("/create")
    public Map<String, String> createOrder(@RequestParam BigDecimal amount, 
                                          @RequestParam String openid) throws Exception {
        Order order = new Order();
        order.setOrderNo(UUID.randomUUID().toString().replace("-", ""));
        order.setAmount(amount);
        order.setOpenid(openid);
        return wxPayService.createPayOrder(order);
    }

    // 微信支付結(jié)果通知(需要公網(wǎng)可訪問)
    @PostMapping(value = "/notify", produces = "application/xml; charset=UTF-8")
    public String wxpayNotify(HttpServletRequest request) {
        return wxPayService.handleNotify(request);
    }
    
    // 查詢訂單狀態(tài)
    @GetMapping("/status")
    public String getOrderStatus(@RequestParam String orderNo) {
        Order order = orderMapper.findByOrderNo(orderNo);
        if (order == null) {
            return "訂單不存在";
        }
        return order.getStatus() == 1 ? "已支付" : "未支付";
    }
}

6. 前端調(diào)用示例(Vue.js)

<template>
  <div>
    <button @click="createOrder">微信支付</button>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  methods: {
    async createOrder() {
      try {
        // 1. 獲取用戶openid(實(shí)際項(xiàng)目中需要通過OAuth2授權(quán)獲取)
        const openid = '用戶openid';
        
        // 2. 創(chuàng)建訂單
        const response = await axios.post('/wxpay/create', {
          amount: 100, // 支付金額(元)
          openid: openid
        });
        
        // 3. 調(diào)起微信支付
        const payParams = response.data;
        wx.chooseWXPay({
          ...payParams,
          success: (res) => {
            console.log('支付成功', res);
            // 可跳轉(zhuǎn)到支付成功頁面
          },
          fail: (err) => {
            console.error('支付失敗', err);
          }
        });
      } catch (error) {
        console.error('創(chuàng)建訂單失敗', error);
      }
    }
  }
}
</script>

7. 配置文件

# application.properties
# 微信支付配置
wxpay.app_id=wx1234567890abcdef
wxpay.mch_id=1234567890
wxpay.mch_key=your_mch_key
wxpay.api_v3_key=your_api_v3_key
wxpay.notify_url=http://your-domain.com/wxpay/notify
wxpay.cert_path=classpath:cert/apiclient_cert.p12

# MySQL配置
spring.datasource.url=jdbc:mysql://localhost:3306/wxpay_demo
spring.datasource.username=root
spring.datasource.password=123456

關(guān)鍵流程說明

  • 獲取用戶OpenID

    • 微信公眾號支付需要獲取用戶的openid
    • 通過微信OAuth2授權(quán)流程獲?。ㄐ柙谖⑿殴娞柡笈_配置授權(quán)域名)
  • 調(diào)用統(tǒng)一下單API

    • 使用 WxPayUnifiedOrderRequest 構(gòu)建請求
    • 關(guān)鍵參數(shù):訂單號、金額(分)、openid、回調(diào)地址
    • 返回 prepay_id(預(yù)支付交易會話標(biāo)識)
  • 生成JSAPI調(diào)起支付參數(shù)

    • 包含 appId、timeStamp、nonceStr、package、signType
    • 使用商戶密鑰生成簽名(paySign)
  • 前端調(diào)起支付

    • 使用微信JSAPI的 chooseWXPay 方法
    • 傳入支付參數(shù)調(diào)起支付界面
  • 接收異步通知

    • 必須驗(yàn)證簽名(防止偽造請求)
    • 檢查 result_code 是否為 SUCCESS
    • 更新訂單狀態(tài)(注意處理冪等性)
  • 安全注意事項(xiàng)

    • 支付金額需與訂單金額比對(防止金額篡改)
    • 敏感操作記錄日志
    • 異步通知處理需要保證冪等性

微信支付與支付寶支付的區(qū)別

特性微信支付支付寶支付
支付方式JSAPI、Native、App、H5等電腦網(wǎng)站、手機(jī)網(wǎng)站、App等
金額單位
簽名算法HMAC-SHA256/RSARSA/RSA2
通知格式XMLForm表單/JSON
證書要求需要API證書不需要證書
OpenID需要獲取用戶openid不需要用戶標(biāo)識
支付流程需要前端調(diào)起支付自動跳轉(zhuǎn)支付頁面

常見問題解決方案

  • 支付金額單位錯誤

    • 微信支付單位為分,支付寶單位為元
    • 轉(zhuǎn)換公式:微信金額 = 支付寶金額 × 100
  • 簽名驗(yàn)證失敗

    • 檢查商戶密鑰是否正確
    • 確認(rèn)簽名算法一致(微信默認(rèn)HMAC-SHA256)
    • 驗(yàn)證參數(shù)是否完整且順序正確
  • 異步通知處理

    • 必須返回XML格式的響應(yīng)
    • 處理速度要快(微信會在30秒內(nèi)重試)
    • 保證冪等性(防止重復(fù)處理)
  • 跨域問題

    • 前端調(diào)起支付需要在微信內(nèi)置瀏覽器
    • 確保公眾號JS接口安全域名配置正確
  • 證書管理

    • 定期更新API證書
    • 證書文件妥善保管(不要提交到代碼倉庫)

實(shí)際開發(fā)中需要根據(jù)具體業(yè)務(wù)需求進(jìn)行調(diào)整,并注意支付安全相關(guān)事項(xiàng)。

到此這篇關(guān)于SpringBoot+MyBatis集成微信支付實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot MyBatis微信支付內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 教你用JDK編譯Java文件的方法

    教你用JDK編譯Java文件的方法

    這篇文章主要介紹了教你用JDK編譯Java文件的方法,分步驟給大家介紹了設(shè)置環(huán)境變量的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-01-01
  • mybatis-plus數(shù)據(jù)權(quán)限實(shí)現(xiàn)代碼

    mybatis-plus數(shù)據(jù)權(quán)限實(shí)現(xiàn)代碼

    這篇文章主要介紹了mybatis-plus數(shù)據(jù)權(quán)限實(shí)現(xiàn),結(jié)合了mybatis-plus的插件方式,做出了自己的注解方式的數(shù)據(jù)權(quán)限,雖然可能存在一部分的局限性,但很好的解決了我們自己去解析SQL的功能,需要的朋友可以參考下
    2023-06-06
  • IDEA 2020 無法啟動的解決辦法(啟動崩盤)附IDEA 2020 新功能

    IDEA 2020 無法啟動的解決辦法(啟動崩盤)附IDEA 2020 新功能

    這篇文章主要介紹了IDEA 2020 無法啟動的解決辦法(啟動崩盤)附IDEA 2020 新功能,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • WeakHashMap的使用方法詳解

    WeakHashMap的使用方法詳解

    這篇文章主要介紹了WeakHashMap的使用方法詳解的相關(guān)資料,希望通過本文能幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-10-10
  • 比較常用UML類圖幾種關(guān)系的小結(jié)

    比較常用UML類圖幾種關(guān)系的小結(jié)

    本文給大家總結(jié)了UML類圖中幾種比較常用的關(guān)系小總結(jié),需要的朋友可以參考下
    2015-10-10
  • 深入淺出分析Java 類和對象

    深入淺出分析Java 類和對象

    面向?qū)ο竽耸荍ava語言的核心,是程序設(shè)計(jì)的思想。Java語言的面向?qū)ο蠹夹g(shù)包括了面向?qū)ο蠛兔嫦蜻^程的基本概念,面向?qū)ο蟮奶卣?,Java語言的類,對象,修飾符,抽象類等一系列的知識點(diǎn)
    2022-03-03
  • Java自帶消息隊(duì)列Queue的使用教程詳細(xì)講解

    Java自帶消息隊(duì)列Queue的使用教程詳細(xì)講解

    這篇文章主要介紹了Java自帶消息隊(duì)列Queue的使用教程,Java中的queue類是隊(duì)列數(shù)據(jù)結(jié)構(gòu)管理類,在它里邊的元素可以按照添加它們的相同順序被移除,隊(duì)列通常以FIFO的方式排序各個元素,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05
  • Jmeter連接Mysql數(shù)據(jù)庫實(shí)現(xiàn)過程詳解

    Jmeter連接Mysql數(shù)據(jù)庫實(shí)現(xiàn)過程詳解

    這篇文章主要介紹了Jmeter連接Mysql數(shù)據(jù)庫實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Idea如何使用System.getenv()獲取環(huán)境變量的值

    Idea如何使用System.getenv()獲取環(huán)境變量的值

    文章介紹了如何在Java中使用`System.getenv()`方法讀取環(huán)境變量的值,并提供了兩種配置環(huán)境變量的方法:啟動項(xiàng)配置和系統(tǒng)環(huán)境變量配置,對于系統(tǒng)環(huán)境變量,文章特別指出需要重啟電腦或程序才能使其生效
    2024-11-11
  • IntelliJ IDEA 常用設(shè)置(配置)吐血整理(首次安裝必需)

    IntelliJ IDEA 常用設(shè)置(配置)吐血整理(首次安裝必需)

    這篇文章主要介紹了IntelliJ IDEA 常用設(shè)置(配置)吐血整理(首次安裝必需),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06

最新評論