paiement applet java WeChat - rappel (Jsapi-APIv3)

1. Préparation avant accès, préparez-vous selon ce document

       Préparation :  Préparation avant l'accès - Mini programme de paiement | Centre de documentation de la plate-forme marchande de paiement WeChat

Vous pouvez l'obtenir lorsque vous êtes prêt ( paramètres requis au deuxième point ) :
        paramètre 1 ID marchand : xxxxxx (tous les chiffres)

        Paramètre 2 Merchant APIV3 key apiV3key : xxxxxxx (32 chaînes alphanumériques majuscules et minuscules, préparées par le développeur lui-même)

        Paramètre 3 Numéro de série du certificat du commerçant marchandSerialNumber : xxxxx

            Méthode de visualisation : Où trouver le numéro de série du certificat de paiement WeChat (où trouver le numéro de série du certificat marchand v3)-Li Fei SEO

        Paramètre 4 Chemin de la clé privée de l'API Merchant privateKeyPath : chemin du fichier apiclient_key.pem

--------------------- Ordre de paiement natif (code QR), les quatre premiers suffisent, 5 est pour le paiement Jsapi ------ ---- ------
        Paramètre 5 Chemin du certificat secret national de la plateforme de paiement WeChat (fichier X509) wechatPayCertificatePath : wechatpay_xxxx.pem()

                Je cherchais ce fichier depuis longtemps et j'ai finalement essayé l'outil ci-dessous pour le télécharger à l'aide de GitHub - wechatpay-apiv3/CertificateDownloader : outil de téléchargement de la ligne de commande du certificat de la plate-forme APIv3 de paiement Java WeChat
 

2. Accès au code de paiement

Documentation du site officiel de paiement : https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7

Wechat a fait un paquet maven pour apiv3, et ça y ressemblait finalement.En conséquence, j'ai trouvé que bien que l'exemple de paiement natif soit complet, je ne sais pas comment donner les 1-5 paramètres dans le premier point. Les paramètres jsapi sont les mêmes, je suis Le patchwork de choses s'est réuni. documentation du paquet maven

-

Postez un exemple d'appel de jsapi, il suffit d'invoquer le paiement côté applet, ceci est basé sur l'exemple officiel :

import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.CloseOrderRequest;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByIdRequest;
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class JsapiDemoService {
    public static String merchantId = "1xxxx";
//    public static String privateKeyPath = "";
    public static String merchantSerialNumber = "xxxx";
    public static String wechatPayCertificatePath = "";

    public static com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension service;

    public static PrepayWithRequestPaymentResponse createWxJsapOrder(String certificatePath, String keyPath, JsapiReq cliReq) {
        String method = Thread.currentThread().getStackTrace()[1].getMethodName();

        // 使用自动更新平台证书的RSA配置
        // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
        Config config =
                new RSAConfig.Builder()
                        .merchantId(merchantId)
                        // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
                        .privateKeyFromPath(keyPath)
                        .merchantSerialNumber(merchantSerialNumber)
                        .wechatPayCertificatesFromPath(certificatePath)
                        .build();
        // 构建service
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        // request.setXxx(val)设置所需参数,具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();

        Payer payer = new Payer();
        payer.setOpenid(cliReq.getOpenid());
        request.setPayer(payer);

        Amount amount = new Amount();
        amount.setTotal(10);//订单总金额,单位为分
        request.setAmount(amount);

        request.setAppid("wxddddxxxxxx");
        request.setMchid("1xxxx");
        request.setDescription("ms");
        request.setNotifyUrl("https://xxx.net/callBackr");
        //request.setOutTradeNo("out_trade_no_1");
        request.setOutTradeNo(cliReq.getOutTradeNo());
        // 调用下单方法,得到应答
        try {
            // ... 调用接口
            PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
            // 使用微信扫描 code_url 对应的二维码,即可体验Native支付
            System.out.println(JSONObject.toJSON(response));
            return response;
        } catch (HttpException e) { // 发送HTTP请求失败
            // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
            log.error(method, e);
        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
            // 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
            log.error(method, e);
        } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
            // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
            log.error(method, e);
        } catch (Exception e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
            // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
            log.error(method, e);
        }
        return new PrepayWithRequestPaymentResponse();
    }

    /** 关闭订单 */
    public static void closeOrder() {

        CloseOrderRequest request = new CloseOrderRequest();
        // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
        // 调用接口
        service.closeOrder(request);
    }
    /** JSAPI支付下单,并返回JSAPI调起支付数据 */
    public static PrepayWithRequestPaymentResponse prepayWithRequestPayment() {
        PrepayRequest request = new PrepayRequest();
        // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
        // 调用接口
        return service.prepayWithRequestPayment(request);
    }
    /** 微信支付订单号查询订单 */
    public static Transaction queryOrderById() {

        QueryOrderByIdRequest request = new QueryOrderByIdRequest();
        // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
        // 调用接口
        return service.queryOrderById(request);
    }
    /** 商户订单号查询订单 */
    public static Transaction queryOrderByOutTradeNo() {

        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
        // 调用接口
        return service.queryOrderByOutTradeNo(request);
    }
}

Remplissez la définition de JsapiReq

public class JsapiReq implements Serializable {
    private static final long serialVersionUID = 1L;
    private String openid;
    private String outTradeNo;
}

 Rappelez-vous également comment lire le chemin du fichier de ressources dans java/spring/srpingboot

        String userDir = System.getProperty("user.dir");
        String certificatePath = userDir + "/src/main/resources/cert/wechatpay_xxx.pem";
        String keyPath = userDir + "/src/main/resources/cert/apiclient_xxxxkey.pem";

3. Rappel de paiement

Paiement Callback-Documentation du site Web officiel : WeChat Payment-Developer Documentation

le code

    @PostMapping(value = "/callBack")
    public Map<String, String> callBack(@RequestBody JSONObject jsonObject) {
        String method = Thread.currentThread().getStackTrace()[1].getMethodName();

        try {
            String key = WxNativePayProxy.getWxV3Key();
            String json = jsonObject.toString();
            String associated_data = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.associated_data");
            String ciphertext = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.ciphertext");
            String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.nonce");

            String decryptData = new AesUtil(key.getBytes(StandardCharsets.UTF_8)).decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
            //验签成功
            JSONObject decryptDataObj = JSONObject.parseObject(decryptData, JSONObject.class);            
            //decryptDataObj 为解码后的obj,其内容如下。之后便是验签成功后的业务处理
            //{
            //	"sp_appid": "wx8888888888888888",
            //	"sp_mchid": "1230000109",
            //	"sub_appid": "wxd678efh567hg6999",
            //	"sub_mchid": "1900000109",
            //	"out_trade_no": "1217752501201407033233368018",
            //	"trade_state_desc": "支付成功",
            //	"trade_type": "MICROPAY",
            //	"attach": "自定义数据",
            //	"transaction_id": "1217752501201407033233368018",
            //	"trade_state": "SUCCESS",
            //	"bank_type": "CMC",
            //	"success_time": "2018-06-08T10:34:56+08:00",
            //    ...
            //	"payer": {
            //		"openid": "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"
            //	},
            //	"scene_info": {
            //		"device_id": "013467007045764"
            //	}
            //}
        }catch (Exception e){
            log.info("{} ,parms{}, 异常:", method, jsonObject.toJSONString(), e);
        }

        Map<String, String> res = new HashMap<>();
        res.put("code", "SUCCESS");
        res.put("message", "成功");
        return res;
    }

Parmi eux, la classe d'outil de décodage WeChat est utile : AesUtil

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AesUtil{

    static final int KEY_LENGTH_BYTE = 32;
    static final int TAG_LENGTH_BIT = 128;
    private final byte[] aesKey;

    public AesUtil(byte[] key) {
        if (key.length != KEY_LENGTH_BYTE) {
            throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
        }
        this.aesKey = key;
    }

    public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
            throws GeneralSecurityException, IOException {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

            SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
            GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);

            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);

            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }
}

Je suppose que tu aimes

Origine blog.csdn.net/tiantiannianni/article/details/130476543
conseillé
Classement