ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

springboot集成微信支付APIv3接口 实现小程序和公众号支付

2022-01-18 18:00:35  阅读:215  来源: 互联网

标签:APIv3 String 微信 param 支付 put new public springboot


前言:

网上有很多大佬们集成的综合支付包,做相应配置也很方便,我这个是基于微信官方文档流程做的直连模式,实现公众号和小程序支付(需要代码中正确使用appid),不得不吐槽微信的文档还是一如既往的。。。

 

微信官方支付文档链接:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_0.shtml,各种证书配置就按照文档上说的来就行了,下边直接上代码。

1.引入maven依赖

        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-apache-httpclient</artifactId>
            <version>0.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.5</version>
        </dependency>

2.yaml配置

wx:
    pay:
        mchId: 16126xxxx #微信支付商户号
        mchSerialNo: 60B04XXXXXXXXX #证书序列号
        v3Secret: 5ovxxxxxxxxxxxxxxxx  #密钥
        p12Path:/usr/local/apiclient_cert.p12 #证书绝对路径地址
        keyPass:16126xxxx  #证书密码 默认微信商户号
        privateKey: | #这个符号一定注意(回车键旁边) 是yaml中保持文本换行读取的写法 防止证书读出来加载失败
            -----BEGIN PRIVATE KEY-----
            xxxx
            -----END PRIVATE KEY----- #私钥
        certificate: |
            -----BEGIN CERTIFICATE-----
            xxxx
            -----END CERTIFICATE----- #平台证书

特别提示:

  yaml配置中的certificate这个证书,需要自己生成,https://developers.weixin.qq.com/community/pay/doc/000e4a0d5dc1486acc19c6fd15bc00,这个链接中网友果果璐璐和萧的回答给出了答案

3.读取yaml内容的Properties类

@Data
@Component
@ConfigurationProperties(prefix = "wx.pay")
public class WeChatPayProperties {

    /**
     * 商户id
     */
    private String mchId;

    /**
     * 商户证书序列号
     */
    private String mchSerialNo;

    /**
     * apiV3密钥
     */
    private String v3Secret;

    /**
     * p12证书文件位置
     */
    private String p12Path;

    /**
     * 证书密码
     */
    private String keyPass;

    /**
     * 商户私钥
     */
    private String privateKey;

    /**
     * 微信支付平台证书 jar包生产的
     */
    private String certificate;

}

4.启动配置类 

@Configuration
public class WxPayV3Config {

    @Autowired
    WeChatPayProperties weChatPayProperties;

    @Bean
    public CloseableHttpClient wxV3Init() {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(weChatPayProperties.getPrivateKey());
        X509Certificate wechatPayCertificate = PemUtil.loadCertificate(
                new ByteArrayInputStream(weChatPayProperties.getCertificate().getBytes(StandardCharsets.UTF_8)));

        ArrayList<X509Certificate> listCertificates = new ArrayList<>();
        listCertificates.add(wechatPayCertificate);

        return WechatPayHttpClientBuilder.create()
                .withMerchant(weChatPayProperties.getMchId(), weChatPayProperties.getMchSerialNo(), merchantPrivateKey)
                .withWechatPay(listCertificates)
                .build();
    }
}

5.下单api

@Slf4j
@Component
public class WeChatPayApi {

    @Autowired
    WeChatPayProperties weChatPayProperties;
    @Autowired
    WeChatAppletProperties weChatAppletProperties;
    @Autowired
    CloseableHttpClient httpClient;

    /**
     * 微信小程序下单的请求地址
     */
    private static final String applet_req_url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";/**
     * 创建微信小程序订单
     *
     * @param orderNo   订单号
     * @param amount    单位 分
     * @param openid    小程序的openid
     * @param goodsName 订单名称
     * @param notify    通知地址
     * @throws IOException
     */
    public String createWxAppletOrder(String orderNo, Integer amount, String openid, String goodsName, String notify) throws IOException {// 请求body参数
        JSONObject paramObject = new JSONObject();
        JSONObject amountObject = new JSONObject();
        amountObject.put("total", amount);
        amountObject.put("currency", "CNY");
        paramObject.put("amount", amountObject);
        paramObject.put("mchid", weChatPayProperties.getMchId());
        paramObject.put("description", goodsName);
        paramObject.put("notify_url", notify);

        JSONObject payerObject = new JSONObject();
        payerObject.put("openid", openid);
        paramObject.put("payer", payerObject);
        paramObject.put("out_trade_no", orderNo);
        paramObject.put("appid", "小程序appid");

        HttpPost httpPost = new HttpPost(applet_req_url);
        httpPost.setHeader("Accept", "application/json");
        StringEntity entity = new StringEntity(paramObject.toJSONString(), "utf-8");
        entity.setContentType("application/json");
        log.info("[微信下单请求参数列表]=" + paramObject);
        httpPost.setEntity(entity);

        //完成签名并执行请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
        Map<String, Object> resMap = new HashMap<>();
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            Assert.isTrue(statusCode == 200, "微信下单请求失败");
            JSONObject jsonObject = JSON.parseObject(EntityUtils.toString(response.getEntity()));
            String prepayId = jsonObject.getString("prepay_id");
            Assert.isTrue(StringUtils.isNotBlank(prepayId), "下单获取参数失败");

            String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
            String nonceStr = RandomUtil.randomString(32).toUpperCase();
            String packagep = "prepay_id=" + prepayId;


            SortedMap<Object, Object> params = new TreeMap<>();
            params.put("appId", weChatAppletProperties.getAppId());
            params.put("timeStamp", timeStamp);
            params.put("nonceStr", nonceStr);
            params.put("package", packagep);
            params.put("signType", "RSA");

            resMap.put("appId", "小程序appid");
            resMap.put("timeStamp", timeStamp);
            resMap.put("nonceStr", nonceStr);
            resMap.put("package", packagep);
            resMap.put("signType", "RSA");
            resMap.put("paySign", WechatPayUtils.createSign(params, weChatPayProperties.getP12Path(), weChatPayProperties.getKeyPass()));
            log.info("[微信支付] 支付参数:" + JSON.toJSONString(resMap));
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        } finally {
            response.close();
        }

        return JSON.toJSONString(resMap);
    }

6.微信paySign签名生成 WechatPayUtils类,KeyPairFactory类,WechatRSAUtils类

public class WechatPayUtils {

    /**
     * sign签名
     *
     * @param map
     * @return
     */
    public static String createSign(SortedMap<Object, Object> map, String certPath, String keyPass) throws Exception {
        String signatureStr = Stream.of(
                String.valueOf(map.get("appId"))
                , String.valueOf(map.get("timeStamp"))
                , String.valueOf(map.get("nonceStr"))
                , String.valueOf(map.get("package"))
        ).collect(Collectors.joining("\n", "", "\n"));
        KeyPair keyPair = KeyPairFactory.createPKCS12(certPath, "Tenpay Certificate", keyPass);
        return WechatRSAUtils.payRequestSign(signatureStr, keyPair);  
}
public class KeyPairFactory {

    private static KeyStore store;

    private static final Object lock = new Object();

    /**
     * 获取公私钥.
     *
     * @param keyPath  the key path
     * @param keyAlias the key alias
     * @param keyPass  password
     * @return the key pair
     */
    public static KeyPair createPKCS12(String keyPath, String keyAlias, String keyPass) throws Exception {
//        ClassPathResource resource = new ClassPathResource(keyPath); //喜欢用相对路径的同学使用这一行
        PathResource resource = new PathResource(keyPath);

        char[] pem = keyPass.toCharArray();
        synchronized (lock) {
            if (store == null) {
                synchronized (lock) {
                    store = KeyStore.getInstance("PKCS12");
                    store.load(resource.getInputStream(), pem);
                }
            }
        }
        X509Certificate certificate = (X509Certificate) store.getCertificate(keyAlias);
        certificate.checkValidity();
        // 证书的序列号 也有用
        String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
        // 证书的 公钥
        PublicKey publicKey = certificate.getPublicKey();
        // 证书的私钥
        PrivateKey storeKey = (PrivateKey) store.getKey(keyAlias, pem);
        return new KeyPair(publicKey, storeKey);
    }
}
public class WechatRSAUtils {
  /**
     * 生成支付签名
     *
     * @param signStr
     * @param keyPair
     * @return
     **/
    @SneakyThrows
    public static String payRequestSign(String signStr, KeyPair keyPair) {
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(keyPair.getPrivate());
        sign.update(signStr.getBytes(StandardCharsets.UTF_8));
        return Base64Utils.encodeToString(sign.sign());
    }     
}

 

标签:APIv3,String,微信,param,支付,put,new,public,springboot
来源: https://www.cnblogs.com/runwithraining/p/15819029.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有