java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot MyBatis微信支付

SpringBoot+MyBatis集成微信支付实现示例

作者:yuren_xia

本文主要介绍了SpringBoot+MyBatis集成微信支付实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

下面我将详细介绍使用 Spring Boot + MyBatis 实现微信支付(JSAPI支付)的完整流程和代码示例。

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

代码实现示例

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();
        
        // 使用自动更新平台证书的验证器
        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());
    }

    // 微信支付服务
    @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. 实体类和Mapper

// 订单实体
@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. 支付服务类

@Service
public class WxPayService {

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

    // 创建支付订单
    public Map<String, String> createPayOrder(Order order) throws Exception {
        orderMapper.insert(order); // 保存订单到数据库

        // 构建统一下单请求
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setBody("商品支付");
        request.setOutTradeNo(order.getOrderNo());
        request.setTotalFee(order.getAmount().multiply(new BigDecimal(100)).intValue()); // 微信支付单位为分
        request.setSpbillCreateIp("用户IP"); // 实际获取用户IP
        request.setNotifyUrl(wxPayConfig.getNotifyUrl());
        request.setTradeType("JSAPI");
        request.setOpenid(order.getOpenid());

        // 调用统一下单API
        WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(request);
        
        // 生成JSAPI调起支付参数
        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;
    }

    // 处理支付结果通知
    public String handleNotify(HttpServletRequest request) {
        try {
            // 解析通知内容
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlResult);

            // 验证签名和业务结果
            if ("SUCCESS".equals(notifyResult.getResultCode())) {
                // 更新订单状态
                String orderNo = notifyResult.getOutTradeNo();
                orderMapper.updateStatus(orderNo, 1); // 更新为已支付
                
                // 返回成功响应
                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;

    // 创建支付订单(返回调起支付所需参数)
    @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);
    }

    // 微信支付结果通知(需要公网可访问)
    @PostMapping(value = "/notify", produces = "application/xml; charset=UTF-8")
    public String wxpayNotify(HttpServletRequest request) {
        return wxPayService.handleNotify(request);
    }
    
    // 查询订单状态
    @GetMapping("/status")
    public String getOrderStatus(@RequestParam String orderNo) {
        Order order = orderMapper.findByOrderNo(orderNo);
        if (order == null) {
            return "订单不存在";
        }
        return order.getStatus() == 1 ? "已支付" : "未支付";
    }
}

6. 前端调用示例(Vue.js)

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

<script>
import axios from 'axios';

export default {
  methods: {
    async createOrder() {
      try {
        // 1. 获取用户openid(实际项目中需要通过OAuth2授权获取)
        const openid = '用户openid';
        
        // 2. 创建订单
        const response = await axios.post('/wxpay/create', {
          amount: 100, // 支付金额(元)
          openid: openid
        });
        
        // 3. 调起微信支付
        const payParams = response.data;
        wx.chooseWXPay({
          ...payParams,
          success: (res) => {
            console.log('支付成功', res);
            // 可跳转到支付成功页面
          },
          fail: (err) => {
            console.error('支付失败', err);
          }
        });
      } catch (error) {
        console.error('创建订单失败', 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

关键流程说明

微信支付与支付宝支付的区别

特性微信支付支付宝支付
支付方式JSAPI、Native、App、H5等电脑网站、手机网站、App等
金额单位
签名算法HMAC-SHA256/RSARSA/RSA2
通知格式XMLForm表单/JSON
证书要求需要API证书不需要证书
OpenID需要获取用户openid不需要用户标识
支付流程需要前端调起支付自动跳转支付页面

常见问题解决方案

实际开发中需要根据具体业务需求进行调整,并注意支付安全相关事项。

到此这篇关于SpringBoot+MyBatis集成微信支付实现示例的文章就介绍到这了,更多相关SpringBoot MyBatis微信支付内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文