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

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

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

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

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

  • 商戶系統(tǒng)生成訂單
  • 獲取用戶OpenID(微信公眾號(hào)支付)
  • 調(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();
        
        // 使用自動(dòng)更新平臺(tái)證書的驗(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;   // 商戶訂單號(hào)
    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)一下單請(qǐ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

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

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

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

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

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

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

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

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

常見問題解決方案

  • 支付金額單位錯(cuò)誤

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

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

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

    • 前端調(diào)起支付需要在微信內(nèi)置瀏覽器
    • 確保公眾號(hào)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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)自定義Excel數(shù)據(jù)排序的方法詳解

    Java實(shí)現(xiàn)自定義Excel數(shù)據(jù)排序的方法詳解

    通常,我們可以在Excel中對(duì)指定列數(shù)據(jù)執(zhí)行升序或者降序排序,在需要自定義排序情況下,我們也可以自行根據(jù)排序需要編輯數(shù)據(jù)排列順序。本文將通過Java應(yīng)用程序來實(shí)現(xiàn)如何自定義排序,需要的可以參考一下
    2022-09-09
  • java實(shí)現(xiàn)讀取、刪除文件夾下的文件

    java實(shí)現(xiàn)讀取、刪除文件夾下的文件

    本文給大家分享的是java實(shí)現(xiàn)讀取、刪除文件夾下的文件,其中File.delete()用于刪除“某個(gè)文件或者空目錄”!所以要?jiǎng)h除某個(gè)目錄及其中的所有文件和子目錄,要進(jìn)行遞歸刪除,有需要的小伙伴可以參考下。
    2015-05-05
  • 基于MapperXML掃描的問題

    基于MapperXML掃描的問題

    這篇文章主要介紹了MapperXML掃描的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • SpringBoot事務(wù)注解超詳細(xì)講解

    SpringBoot事務(wù)注解超詳細(xì)講解

    這篇文章主要給大家介紹了關(guān)于SpringBoot事務(wù)注解的相關(guān)資料,在Spring Boot中,事務(wù)管理是一個(gè)非常重要的概念,我們可以使用事務(wù)注解來控制事務(wù)的行為,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • Spring集成Mybatis過程詳細(xì)講解

    Spring集成Mybatis過程詳細(xì)講解

    mybatis-plus是一個(gè)Mybatis的增強(qiáng)工具,在Mybatis的基礎(chǔ)上只做增強(qiáng)不做改變,為簡化開發(fā)、提高效率而生,下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合Mybatis-plus案例及用法實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • java的split方法使用示例

    java的split方法使用示例

    這篇文章主要介紹了java的split方法使用示例,需要的朋友可以參考下
    2014-04-04
  • Spring Boot2與Spring Boot3的區(qū)別小結(jié)

    Spring Boot2與Spring Boot3的區(qū)別小結(jié)

    SpringBoot2和SpringBoot3之間有一些重要的區(qū)別,本文就來探討SpringBoot2和SpringBoot3之間的區(qū)別,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • Linux部署springboot項(xiàng)目彩色日志打印方式

    Linux部署springboot項(xiàng)目彩色日志打印方式

    這篇文章主要介紹了Linux部署springboot項(xiàng)目彩色日志打印方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Springboot項(xiàng)目基于Devtools實(shí)現(xiàn)熱部署步驟詳解

    Springboot項(xiàng)目基于Devtools實(shí)現(xiàn)熱部署步驟詳解

    這篇文章主要介紹了Springboot項(xiàng)目基于Devtools實(shí)現(xiàn)熱部署,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Mybatis Plus使用@TableId的示例詳解

    Mybatis Plus使用@TableId的示例詳解

    在 MyBatis Plus 中,@TableId 注解是用于標(biāo)記實(shí)體類中的主鍵字段,它可以更方便地處理主鍵相關(guān)的操作,如自動(dòng)填充主鍵值或識(shí)別主鍵字段,這篇文章主要介紹了Mybatis Plus使用@TableId,需要的朋友可以參考下
    2024-08-08

最新評(píng)論

江川县| 新泰市| 镇雄县| 益阳市| 河西区| 儋州市| 余庆县| 横山县| 喀喇沁旗| 临湘市| 钟祥市| 淅川县| 建阳市| 尤溪县| 北海市| 花垣县| 孝感市| 兴安盟| 大厂| 勐海县| 华安县| 彰化市| 洞头县| 蚌埠市| 廊坊市| 黑河市| 常德市| 宁河县| 楚雄市| 唐海县| 枞阳县| 卫辉市| 高陵县| 满城县| 桦南县| 丰顺县| 聂荣县| 搜索| 宁乡县| 昭平县| 丰顺县|