package com.dataxai.web.core.config;import com.alibaba.fastjson2.JSON;
import com.dataxai.web.domain.Wxpay;
import com.dataxai.web.mapper.WxpayMapper;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.*;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.ClassPathResource;
import javax.annotation.PostConstruct;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;@Configuration
@Data //使用set方法将wxpay节点中的值填充到当前类的属性中
@Slf4j
public class WxPayConfig {// 商户号private String mchId;// 商户API证书序列号private String mchSerialNo;// 商户私钥文件private String privateKeyPath;// APIv3密钥private String apiV3Key;// APPIDprivate String appid;// 微信服务器地址private String domain;// 接收结果通知地址private String notifyDomain;// 接收结果通知地址private String notifyDomainProd;// APIv2密钥private String partnerKey;@Autowiredprivate WxpayMapper configMapper;@PostConstructpublic void init() {log.info("初始化微信支付配置...");//从数据库获得配置信息Wxpay dbConfig = configMapper.getOne(1l);if (dbConfig != null) {this.mchId = dbConfig.getMchId();this.mchSerialNo = dbConfig.getMchSerialNo();this.privateKeyPath = dbConfig.getPrivateKeyPath(); // 设置私钥路径this.apiV3Key = dbConfig.getApiV3Key();this.appid = dbConfig.getAppId();this.domain = dbConfig.getDomain();this.notifyDomain = dbConfig.getNotifyDomain();this.notifyDomainProd = dbConfig.getNotifyDomainProd();this.partnerKey = dbConfig.getPartnerKey();log.info("微信支付配置已成功初始化: {}", JSON.toJSONString(dbConfig));} else {throw new IllegalStateException("未找到微信支付配置");}}/*** 获取商户的私钥文件* @param filename* @return*/private PrivateKey getPrivateKey(String filename) {System.out.println("filename = "+filename);filename = "/config/"+filename;ClassPathResource resource = new ClassPathResource(filename);InputStream inputStream = null;try {inputStream = resource.getInputStream();return PemUtil.loadPrivateKey(inputStream);} catch (IOException e) {throw new RuntimeException("私钥文件不存在",e);}}/*** 获取签名验证器* @return*/@Beanpublic ScheduledUpdateCertificatesVerifier getVerifier(){log.info("获取签名验证器");//获取商户私钥PrivateKey privateKey = getPrivateKey(privateKeyPath);//私钥签名对象PrivateKeySigner privateKeySigner = new PrivateKeySigner(mchSerialNo, privateKey);//身份认证对象WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);// 使用定时更新的签名验证器,不需要传入证书ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(wechatPay2Credentials,apiV3Key.getBytes(StandardCharsets.UTF_8));return verifier;}/*** 获取http请求对象* @param verifier* @return*/@Bean(name = "wxPayClient")public CloseableHttpClient getWxPayClient(ScheduledUpdateCertificatesVerifier verifier){log.info("获取httpClient");//获取商户私钥PrivateKey privateKey = getPrivateKey(privateKeyPath);WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, privateKey).withValidator(new WechatPay2Validator(verifier));// ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新CloseableHttpClient httpClient = builder.build();return httpClient;}/*** 获取HttpClient,无需进行应答签名验证,跳过验签的流程*/@Bean(name = "wxPayNoSignClient")public CloseableHttpClient getWxPayNoSignClient(){//获取商户私钥PrivateKey privateKey = getPrivateKey(privateKeyPath);//用于构造HttpClientWechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()//设置商户信息.withMerchant(mchId, mchSerialNo, privateKey)//无需进行签名验证、通过withValidator((response) -> true)实现.withValidator((response) -> true);// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新CloseableHttpClient httpClient = builder.build();log.info("== getWxPayNoSignClient END ==");return httpClient;}}
mapper层和controller层省略