Java-微信支付详解

一.准备工作

        注册微信商户平台

  •         获取商户号(mchid)、API密钥(API_KEY)。

    • 下载API证书apiclient_cert.pem 和 apiclient_key.pem)。

二.核心接口实现 

        1.生成预支付订单(Native支付)

public class WxPayService {
    private String mchId;
    private String apiKey;
    private String notifyUrl;

    // 初始化参数(通过@Value注入或配置文件读取)

    /**
     * 生成Native支付二维码链接
     */
    public String createNativeOrder(String orderId, int amount) throws Exception {
        String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/native";

        Map<String, Object> params = new HashMap<>();
        params.put("mchid", mchId);
        params.put("appid", "你的AppID");  // 如果是公众号/小程序支付
        params.put("description", "订单描述");
        params.put("out_trade_no", orderId);
        params.put("notify_url", notifyUrl);
        params.put("amount", Map.of("total", amount, "currency", "CNY"));

        // 生成签名并发送请求
        String body = JSON.toJSONString(params);
        String authorization = generateSignature("POST", url, body);
        
        // 使用OkHttp或RestTemplate发送请求
        String response = sendPostRequest(url, body, authorization);
        return JSON.parseObject(response).getString("code_url");
    }

    /**
     * 生成V3接口的Authorization头
     */
    private String generateSignature(String method, String url, String body) {
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = UUID.randomUUID().toString().replace("-", "");
        String message = method + "\n" + url + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
        String signature = signWithSHA256RSA(message, apiKey);  // 使用私钥签名
        return "WECHATPAY2-SHA256-RSA2048 " 
                + "mchid=\"" + mchId + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"你的证书序列号\","
                + "signature=\"" + signature + "\"";
    }
}

2.处理微信支付回调 

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

    @PostMapping("/notify")
    public String handleNotify(@RequestBody String requestBody,
                               @RequestHeader("Wechatpay-Signature") String signature,
                               @RequestHeader("Wechatpay-Timestamp") String timestamp,
                               @RequestHeader("Wechatpay-Nonce") String nonce) {
        // 1. 验证签名(防止伪造请求)
        String message = timestamp + "\n" + nonce + "\n" + requestBody + "\n";
        boolean isValid = verifySignature(message, signature, publicKey); // 使用微信平台公钥验证
        if (!isValid) {
            return "<xml><return_code>FAIL</return_code></xml>";
        }

        // 2. 解析回调数据
        Map<String, String> result = parseXml(requestBody);
        String orderId = result.get("out_trade_no");
        String transactionId = result.get("transaction_id");
        
        // 3. 幂等性处理:检查订单是否已处理
        if (orderService.isOrderPaid(orderId)) {
            return "<xml><return_code>SUCCESS</return_code></xml>";
        }

        // 4. 更新订单状态
        orderService.updateOrderToPaid(orderId, transactionId);
        
        // 5. 返回成功响应(必须!否则微信会重试)
        return "<xml><return_code>SUCCESS</return_code></xml>";
    }
}

3.查询订单状态 

public class WxPayService {
    public Map<String, String> queryOrder(String orderId) throws Exception {
        String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" 
                    + orderId + "?mchid=" + mchId;
        
        String authorization = generateSignature("GET", url, "");
        String response = sendGetRequest(url, authorization);
        return JSON.parseObject(response, Map.class);
    }
}

三.注意事项

        签名验证 

  •         所有回调必须验证签名,防止伪造请求。

        密等性设计 

  •         通过数据库唯一索引或Redis锁防止重复处理订单。

        证书管理 

                推荐使用WechatPay Apache HttpClient简化证书处理: 

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

         日志记录

  •         记录所有微信请求和回调,方便排查问题。

四.完整调用事例(Spring Boot) 

@RestController
public class PaymentController {
    @Autowired
    private WxPayService wxPayService;

    @GetMapping("/createOrder")
    public String createOrder(@RequestParam String orderId, @RequestParam int amount) {
        try {
            String codeUrl = wxPayService.createNativeOrder(orderId, amount);
            return "<img src=\"https://example.com/qr?data=" + codeUrl + "\">";
        } catch (Exception e) {
            return "支付创建失败: " + e.getMessage();
        }
    }
}

五.常见问题 

  • 证书加载失败:检查证书路径和格式(必须为PEM格式)。

  • 签名错误:使用微信官方验签工具调试。

  • 回调未触发:检查notify_url是否外网可访问,且返回SUCCESS

                 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值