Java开发笔记-小程序微信支付接入

步骤:

1.注册微信商户,开通小程序支付业务,获得必要接入参数。(Certificate、PrivateKey、merchantId、SerialNumbe、apiV3Key)

2.微信商户号关联小程序(需目标小程序审核)

3.java使用接入参数发起下单,获取下单参数。

4.小程序使用下单参数,调用微信支付,拉起微信支付。

5.客户支付完成后,java后台接收微信支付回调,完成最后的业务。

6.在商户平台下载微信支付账单与系统订单进行对账。

一、微信商户注册
注册地址

微信商户注册地址

通过上传企业信息,法人信息等,成为商户

开通小程序支付业务

产品中心--我的产品--JSAPI支付

merchantId获取

账户中心-商户信息-微信支付商户号

其他参数获取

Certificate、PrivateKey、SerialNumbe、apiV3Key参数获取:账户中心-API安全。具体步骤,在申请的时候官方会提醒的。

二、关联小程序

产品中心--AppID账号管理--关联APPID

三、发起下单

java使用接入参数发起下单,直接上代码

package com.ancun.netsign;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.ScheduledUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;


public class Test {

    private static final String appId="";
    private static final String merchantId="";
    private static final String merchantSerialNumber="";
    private static final String apiV3Key="";
    private static final String merchantPrivateKey="";

    public static void main(String[] args) throws Exception {
        payNomal();
        searchOrder();
    }


    public static void payNomal() throws Exception {

        PrivateKey privateKey = PemUtil.loadPrivateKey(
                new ByteArrayInputStream(merchantPrivateKey.getBytes("utf-8")));
        PrivateKeySigner signer=new PrivateKeySigner(merchantSerialNumber, privateKey);
        byte[] bs=apiV3Key.getBytes(StandardCharsets.UTF_8);
        WechatPay2Credentials cred=new WechatPay2Credentials(merchantId, signer);
        ScheduledUpdateCertificatesVerifier   verifier = new ScheduledUpdateCertificatesVerifier(cred, bs);
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create();
        builder.withMerchant(merchantId, merchantSerialNumber, privateKey);
        builder.withValidator(new WechatPay2Validator(verifier));
        CloseableHttpClient httpClient = builder.build();
        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");
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode rootNode = objectMapper.createObjectNode();
        rootNode.put("mchid",merchantId)
                .put("appid", appId)
                .put("description", "测试公司")
                .put("notify_url", "http://回调地址")
                .put("attach","自定义参数")
                .put("out_trade_no", "订单id");
        rootNode.putObject("amount")
                .put("total", 3);
        rootNode.putObject("payer")
                .put("openid", "微信openid");

        objectMapper.writeValue(bos, rootNode);
        httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
        CloseableHttpResponse response = httpClient.execute(httpPost);
        String bodyAsString = EntityUtils.toString(response.getEntity());
        JSONObject jo=JSONObject.parseObject(bodyAsString);
        System.out.println("prepay_id = " + jo.getString("prepay_id"));

    }



    public static void searchOrder() throws Exception {

        PrivateKey privateKey = PemUtil.loadPrivateKey(
                new ByteArrayInputStream(merchantPrivateKey.getBytes("utf-8")));
        PrivateKeySigner signer=new PrivateKeySigner(merchantSerialNumber, privateKey);
        byte[] bs=apiV3Key.getBytes(StandardCharsets.UTF_8);
        WechatPay2Credentials cred=new WechatPay2Credentials(merchantId, signer);
        ScheduledUpdateCertificatesVerifier   verifier = new ScheduledUpdateCertificatesVerifier(cred, bs);
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create();
        builder.withMerchant(merchantId, merchantSerialNumber, privateKey);
        builder.withValidator(new WechatPay2Validator(verifier));
        CloseableHttpClient httpClient = builder.build();
        HttpGet httpget = new HttpGet("https://api.mch.weixin.qq.com/v3/pay/transactions/id/交易号?mchid=");
        httpget.addHeader("Accept", "application/json");
        httpget.addHeader("Content-type","application/json; charset=utf-8");
        CloseableHttpResponse response = httpClient.execute(httpget);
        String bodyAsString = EntityUtils.toString(response.getEntity());
        System.out.println(bodyAsString);
        JSONObject jo=JSONObject.parseObject(bodyAsString);
        System.out.println(jo);

    }

}
下单接口返回:
{"prepay_id":"wx2310065247629669c55d9ec38dxxxxxx"}
//组装小程序需要的参数:packageInfo、NonceStr、AppId、PaySign、TimeStamp

        String NonceStr= RandomUtil.enUuId();
        Long timeStamp = System.currentTimeMillis() / 1000;
        String packageInfo = "prepay_id=" + prepayId;
        CreateSign02 sign = new CreateSign02();
        String paySign = sign.getToken(appId, packageInfo, NonceStr, timeStamp, merchantPrivateKey);
        String signType="RSA"

package jnpf.utils;



import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Base64;

public class CreateSign02 {

  public  String getToken(String appid,String prepay_id,String nonceStr,long timestamp,String privateKey) throws IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException {
        //从下往上依次生成
        String message = buildMessage(appid, timestamp, nonceStr, prepay_id);
        //签名
        String signature = sign(message.getBytes("utf-8"),privateKey);
        return  signature;
    }

    String sign(byte[] message,String privateKey) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {
        //签名方式
        Signature sign = Signature.getInstance("SHA256withRSA");
        //私钥,通过MyPrivateKey来获取,这是个静态类可以接调用方法 ,需要的是_key.pem文件的绝对路径配上文件名
        sign.initSign(MyPrivatekey.getPrivateKey(privateKey));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    /**
     *  按照前端签名文档规范进行排序,\n是换行
     * @param appid
     * @param timestamp
     * @param nonceStr
     * @param prepay_id
     * @return
     */
    String buildMessage(String appid, long timestamp,String nonceStr,String prepay_id) {

        return appid + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + prepay_id + "\n";
    }

}
四、小程序拉起支付
//小程序拉起支付方法
uni.requestPayment({
		provider: 'wxpay',
		timeStamp: timeStamp,
		nonceStr: nonceStr,
		package: package,
		signType: signType,
		paySign: paySign,
		success: res => {
		//成功后的操作
            
		},fail: err => {
				
		},complete: () => {
		}
	})

效果

五、接收回调

业务代码就不贴了,直接上验签和解密代码

 private String checkSignAndDecrypt(HttpServletRequest request) throws Exception {
        StringBuffer xmlStr = new StringBuffer();
        BufferedReader reader = request.getReader();
        String line;
        while ((line = reader.readLine()) != null) {
            xmlStr.append(line);
        }
        //支付回调通知:
        // {
        // "id":"ff9ce7d0-6d60-520a-bb79-ba98aadaef58",
        // "create_time":"2022-01-26T10:07:46+08:00",
        // "resource_type":"encrypt-resource",
        // "event_type":"TRANSACTION.SUCCESS",
        // "summary":"支付成功",
        // "resource":{
        // "original_type":"transaction",
        // "algorithm":"AEAD_AES_256_GCM",
        // "ciphertext":"bHsdM/qkwb+dU0aani3s0TO+HzD4W0AbQ1TyOBL4VFKDN2IEJx9FPFWWpAwywi/5llfPkf4DoyMMc6KDSkVf3U1bk1y6rKcC+XTFg6jPpsMj/H9kqmrLTYXohtJ6PtmUijnJyEKtyjr7Z6scMEY0oRAAOMZlz3IxheXwNc1AO14zUohS3jppF7wS8lgasVTRiGnk8WRzGLyJTH7lo0bUKYtL2Asq9ARESZbDzJAUcfl8ywZTVFGIlItTXte4CT529cRl+oQtbOFXhlW4kRM7k1QVFhQ3I5FOX58+oPf5aOMaUTzh5HMbpxOAHNB6Yr0JR0QmX1qMwRbeaS45aWhd8BBYJPRFk2MuPalAK3oWqHHYTwa9lEHEJHofSRMZDdUVD3gCCEyzDJpeR0bmQlm1oxnkV4CzBQQeoPg/7Dn2VBUjyX2kKpdVMSdiCb7h1HGesl1BuFurcbZ6rayMfX1Nbq9a7C+oofGauKtdAY1tfQOkee2+NfWTKTc3cfwrWB90aYV2uV9G3tCXeD/XRS2VkXsXiU2UljeVnI1Qv7+9eHWtQDpboQ8q2G2pc4MalhXV2g==",
        // "associated_data":"transaction",
        // "nonce":"EzVTGRqlF6GM"
        // }
        // }
        log.info("支付回调通知接收的body参数:" + xmlStr);
        try {
            log.info("开始验签===========================");
            // 验签
            String Signature = request.getHeader("Wechatpay-Signature");
            String Serial = request.getHeader("Wechatpay-Serial");
            String Timestamp = request.getHeader("Wechatpay-Timestamp");
            String Nonce = request.getHeader("Wechatpay-Nonce");

            PrivateKey privateKey = PemUtil.loadPrivateKey(
                    new ByteArrayInputStream(pro.getMerchantPrivateKey().getBytes("utf-8")));
            //加载官方自动更新证书
            AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                    //商户平台查看                            //不是API密钥
                    new WechatPay2Credentials(pro.getMerchantId(), new PrivateKeySigner(pro.getMerchantSerialNumbe(), privateKey)), pro.getApiV3Key().getBytes("utf-8"));

            String s1 = xmlStr.toString();
            //按照文档要求拼接验签串
            String VerifySignature = Timestamp + "\n" + Nonce + "\n" + s1 + "\n";
            log.info("拼接后的验签串=" + VerifySignature);

            //使用官方验签工具进行验签
            boolean verify1 = verifier.verify(Serial, VerifySignature.getBytes(), Signature);
            log.info("验签结果=" + verify1);
            if (!verify1) {
                return "验签失败";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        log.info("开始解密=========================");
        //解密
        JSONObject jo = JSONObject.parseObject(xmlStr.toString());
        JSONObject jodata = jo.getJSONObject("resource");
        String associated_data = jodata.getString("associated_data");
        String nonce = jodata.getString("nonce");
        String ciphertext = jodata.getString("ciphertext");
        AesUtil aesUtil = new AesUtil(pro.getApiV3Key().getBytes());
        String aes = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
        log.info("解密结果=========================" + aes);

        return aes;
    }

回调方法定义:

  /**
     * 微信支付回调
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @PostMapping(value = "/wxPayNotify")
    public String wxPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.info("进入微信支付回调");
        String aes="";
        try {
            WeCharPayProperties pro = new WeCharPayProperties();

             aes = this.checkSignAndDecrypt(pro, request);
            log.info("解密后参数:" + aes);
            if (aes.equals("验签失败")) {
                return "{" +
                        '"' + "code" + '"' + ":" + '"' + "FAIL" + '"' + "," +
                        '"' + "message" + '"' + ":" + '"' + "失败,验签失败" + '"' +
                        "}";
            }
            //=============解析参数开始=======================================

            省略代码

            //============解析参数结束=======================================
            业务代码

        } catch (Exception e) {
            log.error("微信支付回调出错", e);

        }

        log.info("微信支付回调完成====================================================");

        return "{" +
                '"' + "code" + '"' + ":" + '"' + "SUCCESS" + '"' + "," +
                '"' + "message" + '"' + ":" + '"' + "成功" + '"' +
                "}";
    }

至此完成开发,后续的对账就不贴了。根据自己的业务进行对账。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值