【转发】微信支付JSAPI支付方式,支付和退款的详细代码以及解析

最近开发微信支付功能,但是看个人来看微信支付的文档很是头疼,上面提供的demo,复制下来不能用,又咨询客服查询资料才把微信支付搞清楚。

我使用的是JSAPI的 支付方法,这个支付方法是以下流程:

支付流程:

获取预支付订单号和签名(后端)----->前端拿到预支付订单号和签名调器支付---->支付成功后自动回调

退款流程:

调用企业微信申请退款接口----->退款成功后自动回调

在开发之前需要做好基本配置:

(1)引入微信支付依赖:

com.github.wechatpay-apiv3 wechatpay-java 0.2.12 (2)配置商户证书和APIv3密钥,这部操作直接看文档即可,已经非常详细:下载并配置商户证书 - 通用规则 | 微信支付商户文档中心

1.支付流程代码:

下面代码一些商户信息,商户私密,appid,openid根据自己的实际情况来替换代码。

import com.wechat.pay.java.core.util.IOUtil;
import com.wechat.pay.java.core.util.PemUtil;

import java.security.PrivateKey;

public class MtWeChatConstant {

//商户号  (自己商户平台的商户号)
public static final String MERCHANT_ID = "1234568951";
//商户API私钥路径
public static final String MERCHANT_PRIVATE_KEY_PATH = "/app/resources/wxPayConfig/apiclient_key.pem";
//商户证书序列号(自己配置的证书序列号)
public static final String MERCHANT_SERIAL_NUMBER = "ABCDEF**M63BD96AA3F7A307AEA";
//商户APIV3密钥(自己配置的APIV3)
public static final String API_V3_KEY = "cewi123***89hUPOmAWgABCABCMGH3";
//支付完成后的回调的地址(如果不要回调信息,可以不配置)
public static final String PAY_NOTIFY_URL = "https://xxxx.xxxx.com/services/mt/api/pay/notifi";
//退款完成后的回调的地址(如果不要回调信息,可以不配置)
public static final String REFUND_NOTIFY_URL = "https://xxx.xxxxx.com/services/mt/api/refund/notifi";
//一下代码用于生成签名,写法参考微信支付文档,链接:https://github.com/wechatpay-apiv3/wechatpay-java/blob/main/core/src/test/java/com/wechat/pay/java/core/model/TestConfig.java
public static final PrivateKey MERCHANT_PRIVATE_KEY;
public static final String MERCHANT_PRIVATE_KEY_STRING;

static {
    try {
        MERCHANT_PRIVATE_KEY_STRING = IOUtil.loadStringFromPath(MERCHANT_PRIVATE_KEY_PATH);
        MERCHANT_PRIVATE_KEY = PemUtil.loadPrivateKeyFromString(MERCHANT_PRIVATE_KEY_STRING);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

}
这个配置商户证书的微信支付平台提供的证书私钥,是我存放的位置:“/app/resources/wxPayConfig/apiclient_key.pem” 根据自己项目实际的情况来存放

获取预支付订单号以及签名的代码:

import com.alibaba.fastjson.JSON;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.cipher.RSASigner;
import com.wechat.pay.java.core.cipher.Signer;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class PerPayId {
public static void main(String[] args) {
// 使用自动更新平台证书的RSA配置
// 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(MtWeChatConstant.MERCHANT_ID)
.privateKeyFromPath(MtWeChatConstant.MERCHANT_PRIVATE_KEY_PATH)
.merchantSerialNumber(MtWeChatConstant.MERCHANT_SERIAL_NUMBER)
.apiV3Key(MtWeChatConstant.API_V3_KEY)
.build();

    //获取预支付订单号
    // 构建service
    JsapiService service = new JsapiService.Builder().config(config).build();
    // request.setXxx(val)设置所需参数,具体参数可见Request定义,参考文档:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/direct-jsons/jsapi-prepay.html
    PrepayRequest request = new PrepayRequest();
    Amount amount = new Amount();
    //设置金额, 以分为单位 金额根据实际情况自行填写
    amount.setTotal(1);
    amount.setCurrency("CNY");
    request.setAmount(amount);
    //绑定微信支 公众号的appid 根据实际情况自行获取填写
    request.setAppid("appid");
    // 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一,根据自己需求自己定义
    request.setMchid(MtWeChatConstant.MERCHANT_ID);
    request.setDescription("产品描述");
    //支付成功后回调的URL
    request.setNotifyUrl(MtWeChatConstant.PAY_NOTIFY_URL);
    //ZHE
    request.setOutTradeNo(UUID.randomUUID().toString().replace("-",""));
    //自定义信息, 在支付订单回调可以取到(自行替换,如不需要可注释掉)
    Map meetIfno = new HashMap();
    meetIfno.put("key", "value");
    request.setAttach(JSON.toJSONString(meetIfno));
    Payer payer = new Payer();
    //支付人员的的openid
    payer.setOpenid("openid");
    request.setPayer(payer);
    //调用支付接口
    PrepayResponse response = service.prepay(request);
    //响应体中有预支付订单号
    response.getPrepayId();
    System.out.println(response.getPrepayId());
    //以上为获取预支付订单号步骤


    /**
     * 下面为使用加密获取密钥,也需要返回给前段
     */
    long timeStamp = System.currentTimeMillis() / 1000;
    String nonceStr = UUID.randomUUID().toString().replace("-", "");
    //构造签名参数(appid更换为实际支付人员的appid)
    String message = "appid" + "\n" + timeStamp + "\n" + nonceStr + "\n" + "prepay_id=" + response.getPrepayId() + "\n";

    //生成签名
    Signer rsaSigner = new RSASigner(MtWeChatConstant.MERCHANT_SERIAL_NUMBER, MtWeChatConstant.MERCHANT_PRIVATE_KEY);
    String sign = rsaSigner.sign(message).getSign();
    //前段通过该签名可以调用支付
    System.out.println(sign);

    /**
     * 注意:
     * 1.预支付订单号(prepay_id),以及生成签名的timeStamp,nonceStr的参数都需要返回前端
     * 2.在构造签名参数的时候,\n一定要加 否则也是签名无效
     * 3.
     */
}

2.如果支付完成需要回调的话,以下是回调的代码:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.e7ing.smart.constant.MtWeChatConstant;
import com.e7ing.smart.utils.E7ResponseEntity;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.model.TransactionPayer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(“/api”)
@Transactional(rollbackFor = Exception.class)
public class WeChatPayInfoController {

private final Logger log = LoggerFactory.getLogger(WeChatPayInfoController.class);

/**
 * 处理订单回调事件
 *
 * @param info
 * @return
 */
@PostMapping("/pay/notifi")
public String savePayOrder(
        @RequestHeader(value = "Wechatpay-Signature") String sign,
        @RequestHeader(value = "Wechatpay-Serial") String serial,
        @RequestHeader(value = "Wechatpay-Nonce") String nonce,
        @RequestHeader(value = "Wechatpay-Timestamp") String timestamp,
        @RequestHeader(value = "Wechatpay-Signature-Type") String signType,
        @RequestBody String info
) {
    /**
     * 注意:
     * 1.请求头必须按照代码中的定义格式(如果接收不到可以试试@RequestHeader(value = "Wechatpay-Signature",required = false) String sign)在里面加一个required = false
     * 2.接收body请求体必须是String类型,不能使用json,如果使用json会导致解析不正确
     * 3.返回值类型可以参考文档,我这边定义的String,看文档需求是成功返回"SUCCESS",失败为"FAIL"
     * 3.其他问题可以参考文档代码:https://github.com/wechatpay-apiv3/wechatpay-java/tree/main
     * 4.解析出来的参数问题可以参考这个文档:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/payment-notice.html
     */

    log.debug(
            "获取到回调事件,请求头信息 sign:{}, serial:{}, nonce:{}, timestamp:{}, signType:{}, info:{}",
            sign,
            serial,
            nonce,
            timestamp,
            signType,
            info
    );

    // 构造 RequestParam
    com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
            .serialNumber(serial)
            .nonce(nonce)
            .signature(sign)
            .timestamp(timestamp)
            .body(info)
            .build();

    // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
    NotificationConfig config = new RSAAutoCertificateConfig.Builder()
            .merchantId(MtWeChatConstant.MERCHANT_ID)
            .privateKeyFromPath(MtWeChatConstant.MERCHANT_PRIVATE_KEY_PATH)
            .merchantSerialNumber(MtWeChatConstant.MERCHANT_SERIAL_NUMBER)
            .apiV3Key(MtWeChatConstant.API_V3_KEY)
            .build();

    // 初始化 NotificationParser
    NotificationParser parser = new NotificationParser(config);

    // 以支付通知回调为例,验签、解密并转换成 Transaction
    Transaction payInfo = null;
    try {
        //回调所有的支付信息
        payInfo = parser.parse(requestParam, Transaction.class);
    } catch (Exception e) {
        log.error(
                "签名验证失败,获取到回调事件,请求头信息 sign:{}, serial:{}, nonce:{}, timestamp:{}, signType:{}, info:{}",
                sign,
                serial,
                nonce,
                timestamp,
                signType,
                info
        );
        log.error(e.getMessage());
        return "FAIL";
    }
    //获取支付人员的信息
    TransactionPayer payerInfo = payInfo.getPayer();
    //获取自定义信息
    JSONObject meetInfo = JSON.parseObject(payInfo.getAttach());
    //具体信息自行获取即可
    System.out.println(payInfo.toString());
    
    /**
     * 以上代码只是拿到回调的签名,解析出来回调的支付信息,具体业务根据自己的实际情况自行编写
     */
    return "SUCCESS";
}

}
3.申请退款代码:

import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;

public class Refund {
public static void main(String[] args) {
// 使用自动更新平台证书的RSA配置
// 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(MtWeChatConstant.MERCHANT_ID)
.privateKeyFromPath(MtWeChatConstant.MERCHANT_PRIVATE_KEY_PATH)
.merchantSerialNumber(MtWeChatConstant.MERCHANT_SERIAL_NUMBER)
.apiV3Key(MtWeChatConstant.API_V3_KEY)
.build();
//构造申请退款对象
RefundService service = new RefundService.Builder().config(config).build();
//请求参数
CreateRequest request = new CreateRequest();
//设置退款金额 根据自己的实际业务自行填写
AmountReq amountReq = new AmountReq();
amountReq.setRefund(1L);
amountReq.setTotal(1L);
amountReq.setCurrency(“CNY”);
request.setAmount(amountReq);
//支付成功后回调回来的transactionId 按照实际情况填写
request.setTransactionId(“transactionId”);
//支付成功后回调回来的transactionId 按照实际情况填写
request.setOutRefundNo(“transactionId”);
//退款成功的回调地址
request.setNotifyUrl(MtWeChatConstant.REFUND_NOTIFY_URL);
//发起请求,申请退款
com.wechat.pay.java.service.refund.model.Refund refund = service.create(request);
//调用成功的响应数据
System.out.println(refund);
/**
* 注意:
* 1.以上参数都需要按照实际情况填写,大部分参数都是付款成功之后的回调数据
* 2.以上退款是必要参数,如果想要填写其他参数参考文档:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/create.html
* 3.SDK的微信支付的退款代码参考:https://github.com/wechatpay-apiv3/wechatpay-java/blob/main/service/src/main/java/com/wechat/pay/java/service/refund/RefundService.java
*/
}
4.退款成功的回调代码:

import com.e7ing.smart.constant.MtWeChatConstant;
import com.e7ing.smart.utils.E7ResponseEntity;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(“/api”)
@Transactional(rollbackFor = Exception.class)
public class WeChatPayInfoController {

private final Logger log = LoggerFactory.getLogger(WeChatPayInfoController.class);
/**
 * 处理退款订单回调事件
 *
 * @param info
 * @return
 */
@PostMapping("/refund/notifi")
public E7ResponseEntity saveReFundOrder(
        @RequestHeader(value = "Wechatpay-Signature", required = false) String sign,
        @RequestHeader(value = "Wechatpay-Serial", required = false) String serial,
        @RequestHeader(value = "Wechatpay-Nonce", required = false) String nonce,
        @RequestHeader(value = "Wechatpay-Timestamp", required = false) String timestamp,
        @RequestHeader(value = "Wechatpay-Signature-Type", required = false) String signType,
        @RequestBody String info
) {
    /**
     * 注意:
     * 1.请求头必须按照代码中的定义格式
     * 2.接收body请求体必须是String类型,不能使用json,如果使用json会导致解析不正确
     * 3.返回值类型可以参考文档,我这边定义的String,看文档需求是成功返回"SUCCESS",失败为"FAIL"
     * 3.其他问题可以参考文档代码:https://github.com/wechatpay-apiv3/wechatpay-java/tree/main
     * 4.解析出来的参数问题可以参考这个文档:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/payment-notice.html
     */

    log.debug(
            "获取到回调事件,请求头信息 sign:{}, serial:{}, nonce:{}, timestamp:{}, signType:{}, info:{}",
            sign,
            serial,
            nonce,
            timestamp,
            signType,
            info
    );

    // 构造 RequestParam
    com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
            .serialNumber(serial)
            .nonce(nonce)
            .signature(sign)
            .timestamp(timestamp)
            .body(info)
            .build();

    // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
    NotificationConfig config = new RSAAutoCertificateConfig.Builder()
            .merchantId(MtWeChatConstant.MERCHANT_ID)
            .privateKeyFromPath(MtWeChatConstant.MERCHANT_PRIVATE_KEY_PATH)
            .merchantSerialNumber(MtWeChatConstant.MERCHANT_SERIAL_NUMBER)
            .apiV3Key(MtWeChatConstant.API_V3_KEY)
            .build();

    // 初始化 NotificationParser
    NotificationParser parser = new NotificationParser(config);
    //获取退款回调的信息
    RefundNotification refundInfo = parser.parse(requestParam, RefundNotification.class);
    System.out.println(refundInfo);
    /**
     * 以上代码用于获取退款回调的信息,写法与支付回调很像,具体业务根据自己实际情况修改
     * 回调的具体参数参考文档:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/refund-result-notice.html
     */
    return new E7ResponseEntity("SUCCESS");
}

}
JSAPI其他的功能,以及APP支付,H5支付,Native支付等等都可以参考,微信支付SDK全部都封装好了,使用方法大同小异。

微信支付的官方文档:API列表 - JSAPI支付 | 微信支付商户文档中心

微信支付SDK官方文档:GitHub - wechatpay-apiv3/wechatpay-java: 微信支付 APIv3 的官方 Java Library

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/wudidi_1/article/details/134261383

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值