WxJava développe la connexion WeChat et le paiement WeChat


Préface

WxJava est une boîte à outils de développement Java WeChat qui prend en charge le développement back-end des modules fonctionnels WeChat, notamment le paiement WeChat, la plateforme ouverte, le compte public, le compte WeChat/entreprise d'entreprise, le mini-programme et d'autres modules fonctionnels WeChat.

nom site web
Site officiel du gîte https://gitee.com/binary/weixin-java-tools
Documentation en ligne WxJava http://wxjava.fly2you.cn/zh-CN/start/pay/explain.html
Wiki de documentation de développement https://github.com/wechat-group/WxJava/wiki
Javadoc weixin-java-miniapp , weixin-java-pay , weixin-java-mp, weixin-java-common , weixin-java-cp , weixin-java-open
Document de paiement WeChat https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/mini-prepay.html
Document de connexion WeChat https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html

Travail de préparation
Le paiement WeChat doit ouvrir les commerçants de paiement WeChat. Veuillez consulter le site officiel : https://pay.weixin.qq.com/docs/merchant/products/jsapi-payment/preparation.html

1. Introduire des dépendances

La version que j'utilise ici est la 4.5.0

<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-pay</artifactId>
    <version>${weixin-java.version}</version>
</dependency>
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-miniapp</artifactId>
    <version>${weixin-java.version}</version>
</dependency>

2. Modifier le fichier de configuration

Les informations de configuration ici ont été modifiées et ne peuvent pas être utilisées directement.
Le paiement WeChat utilise la version apiV3.
Le chemin du certificat peut être un chemin absolu ou un chemin de classe. Je l'ai placé sous /resource/cert du projet.

wx:
  miniapp:
    configs:
      - appid: wx2xxxxxxxx
        secret: f7bd3ed88cxxxxxxx222e1a7e4f722ad9
        msgDataFormat: JSON
  pay:
    appId: wx2d0f68xxx7f #微信公众号或者小程序等的appid
    mchId: 1650000080 #微信支付商户号
    apiV3Key: TWBQNkNwwjxxxxx2hN5oQ
    certSerialNo: 2078791B21788DC90E44xxxxxx7291FFD
    privateKeyPath: classpath:cert/apiclient_key.pem #apiclient_key.pem证书文件的绝对路径或者以classpath:开头的类路径
    privateCertPath: classpath:cert/apiclient_cert.pem #apiclient_cert.pem证书文件的绝对路径或者以classpath:开头的类路径
    notifyUrl: https://35fxxxxxpbf.guyubao.com/anonymous/wx/notify/order

3. Mini-programme de connexion WeChat

1. Calendrier du processus de connexion

Insérer la description de l'image ici

2. Comprendre openid, unionid et le code

1.openid

openid est une chaîne utilisée pour identifier de manière unique un utilisateur. Dans l'applet WeChat, l'openid de chaque utilisateur est unique. Grâce à openid, le mini programme peut obtenir les informations de base de l'utilisateur, telles que l'avatar, le surnom, etc.

Remarque : le même utilisateur a différents openids dans différents mini-programmes. Par conséquent, lors du développement de petits programmes, openid ne peut pas être utilisé pour déterminer le caractère unique des utilisateurs.

2. les syndicats

Unionid est une chaîne utilisée pour identifier de manière unique l'utilisateur lorsque celui-ci lie plusieurs applications sous le même compte de plateforme ouverte WeChat. Si un utilisateur utilise le même identifiant WeChat pour l'autorisation de connexion dans plusieurs mini-programmes, l'unionid dans ces mini-programmes sera le même.

Remarque : L'ID union de l'utilisateur ne sera généré que lorsque l'utilisateur lie plusieurs applications au même compte de plateforme ouverte WeChat. Par conséquent, si l'utilisateur n'est pas lié à plusieurs applications, l'applet ne pourra pas obtenir l'identifiant syndical de l'utilisateur.

3. coder

Le code est l'identifiant de connexion de l'utilisateur, qui est délivré au mini-programme par le serveur WeChat. Une fois que l'utilisateur a autorisé la connexion, l'applet peut obtenir le code de l'utilisateur en appelant l'interface de connexion WeChat. Ensuite, demandez l'openid, la session_key et d'autres informations de l'utilisateur au serveur WeChat via le code.

Remarque : Chaque code ne peut être utilisé qu'une seule fois et est valable 5 minutes. Par conséquent, lorsque vous utilisez le code pour vous connecter, il doit être converti en openid et session_key de l'utilisateur et en d'autres informations à temps pour éviter l'expiration du code.

3. Mise en œuvre du code

1. Ajoutez le fichier WxMaProperties dans le répertoire de configuration

package com.ruoyi.xyhj.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;

/**
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */
@Data
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxMaProperties {
    
    

    private List<Config> configs;

    @Data
    public static class Config {
    
    
        /**
         * 设置微信小程序的appid
         */
        private String appid;

        /**
         * 设置微信小程序的Secret
         */
        private String secret;

        /**
         * 设置微信小程序消息服务器配置的token
         */
        private String token;

        /**
         * 设置微信小程序消息服务器配置的EncodingAESKey
         */
        private String aesKey;

        /**
         * 消息格式,XML或者JSON
         */
        private String msgDataFormat;
    }

}

2. Injectez wxMaService

package com.ruoyi.xyhj.config;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.File;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(WxMaProperties.class)
public class WxMaConfiguration {
    
    
    private final WxMaProperties properties;

    @Autowired
    public WxMaConfiguration(WxMaProperties properties) {
    
    
        this.properties = properties;
    }

    @Bean("wxMaService")
    public WxMaService wxMaService() {
    
    
        List<WxMaProperties.Config> configs = this.properties.getConfigs();
        if (configs == null) {
    
    
            throw new WxRuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
        }
        WxMaService maService = new WxMaServiceImpl();
        maService.setMultiConfigs(
            configs.stream()
                .map(a -> {
    
    
                    WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
//                WxMaDefaultConfigImpl config = new WxMaRedisConfigImpl(new JedisPool());
                    // 使用上面的配置时,需要同时引入jedis-lock的依赖,否则会报类无法找到的异常
                    config.setAppid(a.getAppid());
                    config.setSecret(a.getSecret());
                    config.setToken(a.getToken());
                    config.setAesKey(a.getAesKey());
                    config.setMsgDataFormat(a.getMsgDataFormat());
                    return config;
                }).collect(Collectors.toMap(WxMaDefaultConfigImpl::getAppid, a -> a, (o, n) -> o)));
        return maService;
    }

    @Bean
    public WxMaMessageRouter wxMaMessageRouter(WxMaService wxMaService) {
    
    
        final WxMaMessageRouter router = new WxMaMessageRouter(wxMaService);
        router
            .rule().handler(logHandler).next()
            .rule().async(false).content("订阅消息").handler(subscribeMsgHandler).end()
            .rule().async(false).content("文本").handler(textHandler).end()
            .rule().async(false).content("图片").handler(picHandler).end()
            .rule().async(false).content("二维码").handler(qrcodeHandler).end();
        return router;
    }

    private final WxMaMessageHandler subscribeMsgHandler = (wxMessage, context, service, sessionManager) -> {
    
    
        service.getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
            .templateId("此处更换为自己的模板id")
            .data(Lists.newArrayList(
                new WxMaSubscribeMessage.MsgData("keyword1", "339208499")))
            .toUser(wxMessage.getFromUser())
            .build());
        return null;
    };

    private final WxMaMessageHandler logHandler = (wxMessage, context, service, sessionManager) -> {
    
    
        log.info("收到消息:" + wxMessage.toString());
        service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
            .toUser(wxMessage.getFromUser()).build());
        return null;
    };

    private final WxMaMessageHandler textHandler = (wxMessage, context, service, sessionManager) -> {
    
    
        service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
            .toUser(wxMessage.getFromUser()).build());
        return null;
    };

    private final WxMaMessageHandler picHandler = (wxMessage, context, service, sessionManager) -> {
    
    
        try {
    
    
            WxMediaUploadResult uploadResult = service.getMediaService()
                .uploadMedia("image", "png",
                    ClassLoader.getSystemResourceAsStream("tmp.png"));
            service.getMsgService().sendKefuMsg(
                WxMaKefuMessage
                    .newImageBuilder()
                    .mediaId(uploadResult.getMediaId())
                    .toUser(wxMessage.getFromUser())
                    .build());
        } catch (WxErrorException e) {
    
    
            e.printStackTrace();
        }

        return null;
    };

    private final WxMaMessageHandler qrcodeHandler = (wxMessage, context, service, sessionManager) -> {
    
    
        try {
    
    
            final File file = service.getQrcodeService().createQrcode("123", 430);
            WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file);
            service.getMsgService().sendKefuMsg(
                WxMaKefuMessage
                    .newImageBuilder()
                    .mediaId(uploadResult.getMediaId())
                    .toUser(wxMessage.getFromUser())
                    .build());
        } catch (WxErrorException e) {
    
    
            e.printStackTrace();
        }

        return null;
    };

}

3. Appelez

	@Resource
    private WxMaService wxMaService;

    public String wxLoginOrRegister(String code) {
    
    
        if (StringUtils.isBlank(code)) {
    
    
            return "empty jscode";
        }
        try {
    
    
            //根据code获取openid
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
        } catch (WxErrorException e) {
    
    
          throw new WxLoginException(e.getMessage());
        }finally {
    
    
            WxMaConfigHolder.remove();//清理ThreadLocal
        }
    }

Pour plus d'informations, veuillez vous référer à l'exemple officiel : https://github.com/binarywang/weixin-java-miniapp-demo ou javadoc

4. Mini-programme de paiement WeChat

1.Organigramme commercial

Insérer la description de l'image ici

2. Signature, clé privée, certificat et instructions de cryptage et de déchiffrement des informations sensibles

1. Format de signature
Nous espérons que les développeurs techniques du commerçant construiront la chaîne de signature selon les règles convenues dans le document actuel. WeChat Pay utilisera la même méthode pour construire la chaîne de signature. Si le commerçant construit la chaîne de signature de manière incorrecte, la vérification de la signature échouera. Le format spécifique de la chaîne de signature sera expliqué ci-dessous.

Il y a cinq lignes dans la chaîne de signature, chaque ligne possède un paramètre. Se termine par \n (caractère de nouvelle ligne, valeur de codage ASCII 0x0A), y compris la dernière ligne. Si le paramètre lui-même se termine par \n, un \n doit également être ajouté.

HTTP请求方法\n
URL\n
请求时间戳\n
请求随机串\n
请求报文主体\n

Adresse du document :
https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-generation.html

2. Clé privée
Lorsqu'un commerçant demande un certificat API marchand, l'outil de certificat générera la clé privée du commerçant et l'enregistrera dans le fichier apiclient_key.pem dans le dossier de certificat local. La clé privée peut également être exportée depuis le certificat p12 du commerçant via des outils. Veuillez conserver correctement le fichier de clé privée du commerçant.
Adresse du document :
https://pay.weixin.qq.com/docs/merchant/development/interface-rules/privatekey-and-certificate.html

3. Certificat
Le certificat API du commerçant fait référence au certificat appliqué par le commerçant et contient le numéro de commerçant du commerçant, le nom de l'entreprise et les informations de clé publique.

WeChat Payment APIv3 utilise un certificat émis par une autorité de certification (CA). Les commerçants peuvent générer eux-mêmes des chaînes de demande de certificat ou télécharger l'outil de certificat de paiement WeChat pour générer des chaînes de demande de certificat. Après avoir soumis la chaîne de demande de certificat à la plateforme marchande, vous pouvez obtenir le fichier de certificat API marchand. Veuillez faire attention à sauvegarder le fichier de clé privée en toute sécurité.

Chaque certificat de plateforme de paiement WeChat est valable 5 ans. Avant l'expiration du certificat, WeChat Pay utilisera progressivement le nouveau certificat de plateforme pour générer des signatures. Afin d'éviter l'échec de la vérification des signatures en raison du manque de certificats correspondants, le système marchand doit prendre en charge plusieurs certificats de plateforme de paiement WeChat, télécharger régulièrement de nouveaux certificats via l'interface et les déployer sur le serveur. Veuillez vous référer à nos directives de renouvellement de certificat pour éviter de dépendre du renouvellement manuel des certificats et garantir le fonctionnement continu de votre entreprise.

Adresse du document :
https://pay.weixin.qq.com/docs/merchant/development/interface-rules/privatekey-and-certificate.html

4. Cryptage et décryptage
Afin de garantir la confidentialité des champs d'informations sensibles (tels que l'adresse de l'utilisateur, le numéro de carte bancaire, le numéro de téléphone portable, etc.) pendant le processus de communication, l'API WeChat Payment v3 oblige les commerçants à crypter les informations sensibles soumises. des champs. En conséquence, WeChat Pay cryptera les champs d'informations sensibles en aval, et les commerçants devront les déchiffrer avant de pouvoir obtenir le texte original. Ce qui suit décrit en détail les méthodes de cryptage et de déchiffrement, ainsi que la manière d'effectuer les calculs correspondants.

Adresse du document :
https://pay.weixin.qq.com/docs/merchant/development/interface-rules/sensitive-data-encryption.html

3. Mise en œuvre du code

1. Ajoutez le fichier WxPayProperties dans le répertoire de configuration

package com.ruoyi.xyhj.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * wxpay pay properties.
 *
 * @author Binary Wang
 */
@Data
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayProperties {
    
    
  /**
   * 设置微信公众号或者小程序等的appid
   */
  private String appId;

  /**
   * 微信支付商户号
   */
  private String mchId;

  /**
   * 微信支付商户V3密钥
   */
  private String apiV3Key;

  /**
   * 证书号
   */
  private String certSerialNo;

  /**
   * apiclient_key.pem证书文件的绝对路径或者以classpath:开头的类路径
   */
  private String privateKeyPath;

  /**
   * apiclient_cert.pem证书文件的绝对路径或者以classpath:开头的类路径
   */
  private String privateCertPath;

  /**
   * 回调地址
   */
  private String notifyUrl;

}

2. Injectez WxPayService

package com.ruoyi.xyhj.config;

import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author Binary Wang
 */
@Configuration
@ConditionalOnClass(WxPayService.class)
@EnableConfigurationProperties(WxPayProperties.class)
@AllArgsConstructor
public class WxPayConfiguration {
    
    
  private WxPayProperties properties;

  @Bean("wxPayService")
  @ConditionalOnMissingBean
  public WxPayService wxService() {
    
    
    WxPayConfig payConfig = new WxPayConfig();
    payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
    payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
    payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiV3Key()));
    payConfig.setCertSerialNo(StringUtils.trimToNull(this.properties.getCertSerialNo()));
    payConfig.setPrivateKeyPath(StringUtils.trimToNull(this.properties.getPrivateKeyPath()));
    payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getPrivateCertPath()));
    payConfig.setNotifyUrl(StringUtils.trimToNull(this.properties.getNotifyUrl()));
    payConfig.setTradeType("JSAPI");
    payConfig.setSignType("MD5");
    WxPayService wxPayService = new WxPayServiceImpl();
    wxPayService.setConfig(payConfig);
    return wxPayService;
  }

}

3. Créez un ordre de prépaiement

Notez que nous utilisons la version v3, donc lors de la création d'un objet ou de l'appel de wxpayService, vous devez appeler la version v3, sinon les paramètres risquent de ne pas correspondre.

/**
* 创建预支付订单
*/
    @Override
    @Transactional
    public WxUnifiedOrderVo createOrder(PatriarchCreateOrderBo bo) throws WxPayException, IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException {
    
    
  
        //构建预支付订单对象
        WxPayUnifiedOrderV3Request orderV3Request = buildWxPayUnifiedOrderRequest(order, parentUser.getOpenid(), product.getName());
        WxPayUnifiedOrderV3Result wxPayUnifiedOrderV3Result = wxPayService.unifiedOrderV3(TradeTypeEnum.JSAPI, orderV3Request);
        //构建返回参数
        WxUnifiedOrderVo tokenJSAPI = WechatSignUtil.getTokenJSAPI(wxPayProperties.getAppId(), wxPayUnifiedOrderV3Result.getPrepayId(), wxPayProperties.getPrivateKeyPath());
        return tokenJSAPI;
    }
/**
     * 构建统一下单对象
     * @param order 订单对象
     * @param openId user openId
     * @param productName 产品名
     * @return
     */
    public WxPayUnifiedOrderV3Request buildWxPayUnifiedOrderRequest(TelOrder order, String openId,String productName){
    
    
        WxPayUnifiedOrderV3Request orderRequest = new WxPayUnifiedOrderV3Request();
        //设置订单号
        orderRequest.setOutTradeNo(order.getId().toString());
        //设置交易结束时间为24小时
        orderRequest.setTimeExpire(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()));
        //设置订单金额
        orderRequest.setAmount(new WxPayUnifiedOrderV3Request.Amount()
                        .setTotal(BaseWxPayRequest.yuanToFen(order.getAmount().toString())));
        //设置支付者信息
        orderRequest.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(openId));
        //设置商品描述
        orderRequest.setDescription(productName);
        return orderRequest;
    }

4. Classe d'outils de signature

package com.ruoyi.xyhj.utils;

import com.ruoyi.xyhj.domain.vo.WxUnifiedOrderVo;

import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.UUID;

public class WechatSignUtil {
    
    

    /**
     * 参考网站 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml
     * 计算签名值
     *
     * @param appId
     * @param prepay_id
     * @return
     * @throws IOException
     * @throws SignatureException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public static WxUnifiedOrderVo getTokenJSAPI(String appId, String prepay_id, String privateKey) throws IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException {
    
    
        // 获取随机字符串
        String nonceStr = getNonceStr();
        // 获取微信小程序支付package
        String packagestr = "prepay_id=" + prepay_id;
        long timestamp = System.currentTimeMillis() / 1000;
        //签名,使用字段appId、timeStamp、nonceStr、package计算得出的签名值
        String message = buildMessageTwo(appId, timestamp, nonceStr, packagestr);
        //获取对应的签名
        String signature = sign(message.getBytes("utf-8"),privateKey);
        // 组装返回
        WxUnifiedOrderVo vo = new WxUnifiedOrderVo();
        vo.setAppId(appId);
        vo.setTimeStamp(String.valueOf(timestamp));
        vo.setNonceStr(nonceStr);
        vo.setPackageStr(packagestr);
        vo.setSignType("RSA");
        vo.setPaySign(signature);
        return vo;
    }

    /**
     * 生成随机数
     * @return
     */
    public static String getNonceStr(){
    
    
        return UUID.randomUUID().toString()
                .replaceAll("-", "")
                .substring(0, 32);
    }
    /**
     * 拼接参数
     *
     * @return
     */

    public static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) {
    
    
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + packag + "\n";
    }
    /**
     * 生成签名
     *
     * @return
     */
    public static String sign(byte[] message,String privateKey) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {
    
    
        Signature sign = Signature.getInstance("SHA256withRSA"); //SHA256withRSA
        sign.initSign(getPrivateKey(privateKey));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }
    /**
     * 获取私钥
     * @param filename 私钥文件路径  (required)
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey(String filename) throws IOException {
    
    
        System.out.println("filename:" + filename);
        filename = filename.replace("classpath:", "");
        WechatSignUtil wechatSignUtil = new WechatSignUtil();
        InputStream resourceAsStream = wechatSignUtil.getClass().getClassLoader().getResourceAsStream(filename);
        byte[] bytes = new byte[0];
        bytes = new byte[resourceAsStream.available()];
        resourceAsStream.read(bytes);
        String content = new String(bytes);
//        String content = new String(Files.readAllBytes(Paths.get(resource.getPath())), "utf-8");
        try {
    
    
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
    
    
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
    
    
            throw new RuntimeException("无效的密钥格式");
        }
    }
}

5. Interface de rappel

 @ApiOperation(value = "支付回调通知处理")
    @PostMapping("/wx/notify/order")
    public void parseOrderNotifyResult(@RequestBody String resultData) throws WxPayException {
    
    
        WxPayOrderNotifyV3Result notifyV3Result = wxPayService.parseOrderNotifyV3Result(resultData,null);
        log.info("回调:{}",notifyV3Result.getResult());
        orderService.wxNotify(notifyV3Result.getResult());
    }

Je suppose que tu aimes

Origine blog.csdn.net/qq_43548590/article/details/132837104
conseillé
Classement