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

Posted 俗人码农

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信支付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

微信支付--小程序版

最近应公司要求要做一个微信小程序支付功能,其实刚接到这个功能我心里是比较抵触滴。怎么说呢,如果涉及到资金的问题,应该都不是小问题。好了,废话不多说,先记录我在支付当中遇到的事情吧。
其实现在腾讯对小程序这一块已经很重视了,有完善的API开发文档,还有y用主流语言所编写的DEMO;只要按照demo修改一下一般都可以完成  DEMO下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1。

最开始花一天的时间把微信支付文档从头到尾看了一般,对支付有一个大概的映像,然后在慢慢研究demo中的代码。不难,但是编写中还是范了一些错了。

1、最普遍的错误应该会出现在签名哪儿(sign 第一次签名);提示”签名错误”;如果发现签名错误,先检查自己传递的值是否有问题,特别是商户密匙(在商户中有两个密匙 一个叫APIV3密匙,一个叫API密匙),这儿使用的是API密匙(切记,我就是在这儿调用了APIV3密匙,特别尴尬),签名的加密有MD5和HMAC-SHA256两中,一般默认的是MD5; 如果发现签名错误微信提供了签名验证:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1

2、小程序的统一下单,交易的类型要是JSAPI,openid就是必须值了。

3、下单成功之后在使用小程序的支付APIwx.requestPayment(OBJECT)

支付的难点还是在于签名,一定要首先理解签名的方法。如果签名错误后续工作就没有办法了。

以上是关于微信支付V3 小程序支付API Java版的主要内容,如果未能解决你的问题,请参考以下文章

微信支付2.0和3.0有啥区别?

怎么用java调用微信支付接口

微信小程序支付API

微信支付后端篇

小程序调用微信支付不显示微信支付界面

微信小程序发起支付流程