微信支付V3 小程序支付API Java版

本文目的:快速接通微信支付V3 无需关注细节,实现支付功能,修改配置即可调用


接入准备

申请APPID,申请mchid,绑定APPID及mchid,设置APIV3密钥,下载并配置商户证书

微信支付文档


微信支付流程整理(小程序版)

  1. 前端获取登录凭证(wx.login)
  2. 服务端换取用户openId(code2Session)
  3. 创建微信支付订单(/v3/pay/transactions/jsapi)
  4. 回调服务端

提示:以下是本篇文章正文内容,下面案例可供参考

一、导入微信支付扩展包

微信支付扩展包文档

 <!--微信支付-->
        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-apache-httpclient</artifactId>
            <version>0.4.7</version>
        </dependency>

二、微信支付工具类

1.签名工具类

代码如下(示例):

@Component
public class WxSignUtil {
    
    

    protected static final SecureRandom RANDOM = new SecureRandom();

    /**
     * 微信调起支付参数
     * 返回参数如有不理解 请访问微信官方文档
     * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_4.shtml
     *
     * @param prepayId         微信下单返回的prepay_id
     * @param appId            应用ID
     * @param mch_id           商户号
     * @param privateKey       私钥
     * @return 当前调起支付所需的参数
     * @throws Exception
     */
    public static String WxAppPayTuneUp(String prepayId, String appId, String mch_id, String privateKey) throws Exception {
    
    
        if (StringUtils.isNotBlank(prepayId)) {
    
    
            long timestamp = System.currentTimeMillis() / 1000;
            String nonceStr = generateNonceStr();
            //加载签名
            String packageSign = sign(buildMessage(appId, timestamp, nonceStr, prepayId).getBytes(), privateKey);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("appId", appId);
            jsonObject.put("prepayId", prepayId);
            jsonObject.put("timeStamp", timestamp);
            jsonObject.put("nonceStr", nonceStr);
            jsonObject.put("package", "Sign=WXPay");
            jsonObject.put("signType", "RSA");
            jsonObject.put("sign", packageSign);
            jsonObject.put("partnerId", mch_id);
            return jsonObject.toJSONString();
        }
        return "";
    }

    public static String sign(byte[] message, String privateKey) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {
    
    
        //签名方式
        Signature sign = Signature.getInstance("SHA256withRSA");
        //私钥
        sign.initSign(PemUtil
                .loadPrivateKey(privateKey));
        sign.update(message);

        return Base64.getEncoder().encodeToString(sign.sign());
    }

    //生成随机字符串 微信底层的方法,直接copy出来了
    protected static String generateNonceStr() {
    
    
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
    
    
            nonceChars[index] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(RANDOM.nextInt("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".length()));
        }
        return new String(nonceChars);
    }

    /**
     * 按照前端签名文档规范进行排序,\n是换行
     *
     * @param appId     appId
     * @param timestamp 时间
     * @param nonceStr  随机字符串
     * @param prepay_id prepay_id
     * @return
     */
    public static String buildMessage(String appId, long timestamp, String nonceStr, String prepay_id) {
    
    
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + "prepay_id="+prepay_id + "\n";
    }

}


2.微信支付工具类

代码如下(示例):

@Slf4j
@Component
public class WxMiniPayUtils {
    
    

    public static CloseableHttpClient httpClient;

    public static Verifier verifier;


    /**
     * 初始化 HttpClient
     * @throws IOException
     */
    public static void initWXPayClient() throws IOException {
    
    
        try {
    
    
            // 加载商户私钥(privateKey:私钥字符串)
            PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey({
    
    {
    
    微信支付私钥字符串}});

            // 也可使用证书 查询商户证书序列号
//            X509Certificate wechatPayCert = PemUtil.loadCertificate(new ByteArrayInputStream(StaticVariable.WX_PAY_CERT.getBytes(StandardCharsets.UTF_8)));
//            String serialNo = wechatPayCert.getSerialNumber().toString(16).toUpperCase();

            String serialNo ={
    
    {
    
    微信支付商户证书序列号}};
            //merchantId:商户号,serialNo:商户证书序列号
            // 获取证书管理器实例
            CertificatesManager certificatesManager = CertificatesManager.getInstance();
            // 向证书管理器增加需要自动更新平台证书的商户信息
            certificatesManager.putMerchant({
    
    {
    
    微信支付-商户号}}, new WechatPay2Credentials({
    
    {
    
    微信支付-商户号}},
                    new PrivateKeySigner(serialNo, merchantPrivateKey)), {
    
    {
    
    微信支付-v3 密钥}}.getBytes(StandardCharsets.UTF_8));
            // 从证书管理器中获取verifier
            //版本>=0.4.0可使用 CertificatesManager.getVerifier(mchId) 得到的验签器替代默认的验签器。
            // 它会定时下载和更新商户对应的微信支付平台证书 (默认下载间隔为UPDATE_INTERVAL_MINUTE)。
            verifier = certificatesManager.getVerifier({
    
    {
    
    微信支付-商户号}});

            //创建一个httpClient
            httpClient = WechatPayHttpClientBuilder.create()
                    .withMerchant({
    
    {
    
    微信支付-商户号}}, serialNo, merchantPrivateKey)
                    .withValidator(new WechatPay2Validator(verifier)).build();
        } catch (IOException e) {
    
    
            e.printStackTrace();
            log.error("加载秘钥文件失败");
        } catch (GeneralSecurityException e) {
    
    
            e.printStackTrace();
            log.error("获取平台证书失败");
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 关闭 HttpClient
     * @throws IOException
     */
    public static void closeWXClient() throws IOException {
    
    
        if (httpClient != null) {
    
    
            try {
    
    
                httpClient.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }

    /**
     * 创建微信支付订单
     * @param openId 用户唯一标识
     * @param orderId 订单id
     * @param amount 支付价格(单位分)
     * @param description 订单说明
     * @return
     * @throws Exception
     */
    public static String creatOrderJSAPI(String openId,String orderId,Integer amount,String description) throws Exception {
    
    
        try {
    
    
            initWXPayClient();
            HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");

            String reqdata = "{"
                    + "\"amount\": {"
                    + "\"total\": "+amount+","
                    + "\"currency\": \"CNY\""
                    + "},"
                    + "\"mchid\": \""+{
    
    {
    
    微信支付-商户号}}+"\","
                    + "\"description\": \""+description+"\","
                    + "\"notify_url\": \""+{
    
    {
    
    微信支付-回调地址}}+"\","
                    + "\"payer\": {"
                    + "\"openid\": \""+openId+"\"" + "},"
                    + "\"out_trade_no\": \""+orderId+"\","
                    + "\"goods_tag\": \"WXG\","
                    + "\"appid\": \""+{
    
    {
    
    微信APPID}}+"\"" + "}";

            httpPost.setEntity(new StringEntity(reqdata, "utf-8"));
            CloseableHttpResponse response = httpClient.execute(httpPost);
            String bodyAsString = EntityUtils.toString(response.getEntity());
            return bodyAsString;
        }catch (Exception e){
    
    
            e.printStackTrace();
            log.error("创建微信支付订单失败");
        }finally {
    
    
            closeWXClient();
        }
        return "";
    }
}

三、创建订单

代码如下(示例):

		String response= WxMiniPayUtils.creatOrderJSAPI({
    
    {
    
    用户openId}}, {
    
    {
    
    订单id}},{
    
    {
    
    订单金额}},{
    
    {
    
    订单描述}});
		JSONObject jsonObject= JSONObject.fromObject(response);
		if (jsonObject.containsKey("prepay_id")){
    
    
			/**补充相关业务*/
		}

创建微信支付订单,微信会返回 prepay_id (预下单id)用于前端调起支付


四、调起支付

调起支付文档

前端通过prepay_id调起支付


五、支付回调

Controller代码如下(示例):

	@ApiOperation(value = "微信支付回调", notes = "微信支付回调")
	@PostMapping(value = "wxAppPayNotify.do")
	public String wxAppPayNotify( @RequestHeader("Wechatpay-Serial") String wechatpaySerial,
									  @RequestHeader("Wechatpay-Signature") String wechatpaySignature,
									  @RequestHeader("Wechatpay-Timestamp") String wechatpayTimestamp,
									  @RequestHeader("Wechatpay-Nonce") String wechatpayNonce,
									  @RequestBody String callback) throws Exception {
    
    
	    return Service.wxAppPayNotify(wechatpaySerial,wechatpaySignature,wechatpayTimestamp,wechatpayNonce,callback);
	}

验签和解密并返回通知

Servicer代码如下(示例):

	@Override
	public String wxAppPayNotify(String wechatpaySerial, String wechatpaySignature, String wechatpayTimestamp, String wechatpayNonce, String callback) throws Exception {
    
    
		//按照文档要求拼接验签串
		String verifySignature = wechatpayTimestamp + "\n"
				+ wechatpayNonce + "\n" + callback + "\n";

		//使用官方验签工具进行验签
		boolean verify1 = WxMiniPayUtils.verifier.verify(wechatpaySerial, verifySignature.getBytes(), wechatpaySignature);
		//判断验签的结果
		if (!verify1) {
    
    
			//验签失败,应答接口
			com.alibaba.fastjson.JSONObject jsonResponse = new com.alibaba.fastjson.JSONObject();
			jsonResponse.put("code", "FAIL");
			jsonResponse.put("message", "失败");
			return jsonResponse.toString();
		}
		
		JSONObject parseObject = JSONObject.parseObject(callback);
		if ("TRANSACTION.SUCCESS".equals(parseObject.getString("event_type"))
				&& "encrypt-resource".equals(parseObject.getString("resource_type"))) {
    
    
			//通知的类型,支付成功通知的类型为TRANSACTION.SUCCESS
			//通知的资源数据类型,支付成功通知为encrypt-resource
			JSONObject resourceJson = JSONObject.parseObject(parseObject.getString("resource"));
			String associated_data = resourceJson.getString("associated_data");
			String nonce = resourceJson.getString("nonce");
			String ciphertext = resourceJson.getString("ciphertext");

			//解密,如果这里报错,就一定是APIv3密钥错误
			AesUtil aesUtil = new AesUtil({
    
    {
    
    微信支付-v3 密钥}}.getBytes());
			String resourceData = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
			System.out.println("解密后=" + resourceData);
			//dosomething 处理业务
			JSONObject resource =JSONObject.fromObject(resourceData);
			if (resource.containsKey("out_trade_no")){
    
    
				/**支付成功,补充业务**/
			}

		}
		JSONObject jsonResponse = new JSONObject();
		jsonResponse.put("code", "SUCCESS");
		jsonResponse.put("message", "成功");
		return jsonResponse.toString();

	}

总结

微信支付文档

网上的微信支付V3 教程无需看太多 ,专注官方文档

参考文档:https://www.cnblogs.com/cchilei/p/16077207.html

https://blog.csdn.net/m0_59588838/article/details/127204694

猜你喜欢

转载自blog.csdn.net/weixin_41476211/article/details/128496850