SpringBoot Jsapi APIv3微信支付

官网文档:微信支付-开发者文档

官方SDK: https://github.com/wechatpay-apiv3/wechatpay-java

JSAPI下单 准备参数不写,只写关键方法 JSAPI是通过微信获取prepay_id来完成支付

第一步: 引入SDK依赖 

        <!-- https://mvnrepository.com/artifact/com.github.wechatpay-apiv3/wechatpay-java -->
        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-java</artifactId>
            <version>0.2.5</version>
        </dependency>

 

第二步:编写获取预订单id方法

//自行封装请求参数
PrepayRequest prepayRequest = new PrepayRequest();
//getJsapiService()方法是我自己封装的
//prepay sdk中有的方法 PrepayResponse 属性有prepay_id
PrepayResponse prepay = getJsapiService(one).prepay(prepayRequest);


 

private JsapiService getJsapiService(WxConfig one) {
        //one参数里面封装的所需要的参数
        Config config = getJsapiConfig(one);


        HttpClient httpClient =
                new DefaultHttpClientBuilder()
                        .config(config)
                        .connectTimeoutMs(5000)
                        .build();
        return new JsapiService.Builder().httpClient(httpClient).build();
}
private static final Map<String, Config> HASH_MAP = new ConcurrentHashMap<>();  
private Config getJsapiConfig(WxConfig one) {
        Config config;
        String mchId = one.getMchId();
        config = HASH_MAP.get(mchId);
        //由于程序运行后 SDK中将已经创建的RSAAutoCertificateConfig保存下来,如果再次创建就会抛出异常
        //我就引入了双重检锁 还用的Redisson 
        //如果写的不对评论区告诉我
        /*
            merchantId: 商户号Id
            privateKeyFromPath: 保存私钥的路径,这个就是申请的郑虎会带有私钥文件apiclient_key.pem
            merchantSerialNumber:这个值在申请证书之后,商户后台证书可以看到
            apiV3Key:apiv3填写的值
        */
        if (config == null) {
            RLock lock = redisson.getLock("lock:" + mchId);
            lock.lock(1000, TimeUnit.MILLISECONDS);
            try {
                config = HASH_MAP.get(mchId);
                if (config == null) {
                    config =
                            new RSAAutoCertificateConfig.Builder()
                                    .merchantId(one.getMchId())
                                    .privateKeyFromPath(one.getPrivateKey())
                                    .merchantSerialNumber(one.getMerchantSerialNumber())
                                    .apiV3Key(one.getApiV3Key())
                                    .build();
                    HASH_MAP.put(mchId, config);
                }
            } catch (Exception e) {
                log.error("getJsapiService异常: {}", ExceptionUtils.getStackTrace(e));
                throw new ServiceException("微信服务异常");
            } finally {
                lock.unlock();
            }
        }
        return config;
    }

JSAPI调起支付API

调起支付页面使用JS完成,参数我是由后端接口封装返回

签名生成-接口规则 | 微信支付商户平台文档中心 这是官方提供的示例 我根据这个改的

private String getPaySign(String appId, String timeStamp, String nonceStr, String prePay, WxConfig config) throws Exception {
        String paySignBefore = appId +
                "\n" +
                timeStamp +
                "\n" +
                nonceStr +
                "\n" +
                prePay +
                "\n";

        return SignUtil.sign(paySignBefore, config.getPrivateKey());
}
public class SignUtil {
    //获取paySign工具类         参数          apiclient_key.pem文件路径
    public static String sign(String param, String fileName) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(getPrivateKey(fileName));
        sign.update(param.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(sign.sign());
    }
    /**
     * 获取私钥。
     *
     * @param fileName 私钥文件路径  (required)
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey(String fileName) throws IOException {

        String content = new String(Files.readAllBytes(Paths.get(fileName)), "utf-8");
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }
}

支付结果通知 用来接收支付结果

这是github上面的说明

 

/*
map 就是post请求发送过来的参数 我自己创建实体类接收 解析的时候抛出异常 我看官方内容 我就改成了Map就可以了
*/
 
private Transaction getTransaction(HttpServletRequest request, WxConfig wxConfig, Map<String, Object> map) {

        String characterEncoding = request.getCharacterEncoding();
        System.out.println("characterEncoding=" + characterEncoding);
        //从请求头获取验签字段
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String signature = request.getHeader("Wechatpay-Signature");
        String serial = request.getHeader("Wechatpay-Serial");
        //        // 构造 RequestParam
        com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
                .serialNumber(serial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(JSON.toJSONString(map))
                .build();
        NotificationConfig config = (NotificationConfig) getJsapiConfig(wxConfig);


        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);
        // 以支付通知回调为例,验签、解密并转换成 Transaction
        return parser.parse(requestParam, Transaction.class);
    }

 注: 如果有写的不清晰的地方,评论区联系,以上我只是写的调用微信的关键步骤

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值