微信支付相关参数
- 商户号
- 公众号appid
- 商户证书序列号
- APIv3秘钥
具体申请方式,参考微信支付开发者文档
项目工程搭建
在resources目录下新建cert目录存放证书中的私钥文件
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--项目中添加 spring-boot-starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<!-- 微信支付API v3的Apache HttpClient扩展,实现了请求签名的生成和应答签名的验证-->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.3.0</version>
</dependency>
</dependencies>
@Slf4j
@Configuration
@RequiredArgsConstructor
public class CertificateConfig {
private final WechatPayConfig wechatPayConfig;
public PrivateKey getPrivateKey() throws IOException {
InputStream inputStream = new ClassPathResource(wechatPayConfig.getPrivateKeyPath()
.replace("classpath:", ""))
.getInputStream();
String content = new BufferedReader(new InputStreamReader(inputStream))
.lines().collect(Collectors.joining(System.lineSeparator()));
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("无效的密钥格式");
}
}
}
测试私钥证书读取
@Autowired
private CertificateConfig certificateConfig;
@Test
public void testLoadPrivateKey() throws IOException {
log.info(certificateConfig.getPrivateKey().getAlgorithm());
}
自动更新微信平台证书
/**
* 定时获取微信签名验证器,自动获取微信平台证书(证书里面包括微信平台公钥)
* @return
* @throws IOException
*/
@Bean
public ScheduledUpdateCertificatesVerifier getCertificatesVerifier() throws IOException {
//使用定时更新的签名验证器,不需要传入证书
ScheduledUpdateCertificatesVerifier getPrivateKey = new ScheduledUpdateCertificatesVerifier(
new WechatPay2Credentials(wechatPayConfig.getMchId(),new PrivateKeySigner(wechatPayConfig.getMchSerialNo(),getPrivateKey())),
wechatPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
return getPrivateKey;
}
封装httpclient
/**
* 获取http请求对象,会自动的处理签名和验签,并进行证书自动更新
* @param verifier
* @return
*/
@Bean("wechatPayClient")
public CloseableHttpClient getWechatPayClient(ScheduledUpdateCertificatesVerifier verifier) throws IOException {
return WechatPayHttpClientBuilder.create()
.withMerchant(wechatPayConfig.getMchId(), wechatPayConfig.getMchSerialNo(), getPrivateKey())
.withValidator(new WechatPay2Validator(verifier))
.build();
}
Navtive下单API接口调用
构造请求参数中的必填选项
@Test
public void testNativeOrder(){
ObjectMapper objectMapper = new ObjectMapper();
//构建下单请求参数
ObjectNode nativeOrder = objectMapper.createObjectNode();
nativeOrder.put("mchid",wechatPayConfig.getMchId());
//订单号,根据业务规则生成即可
nativeOrder.put("out_trade_no","123456789abcdefghijk");
nativeOrder.put("appid",wechatPayConfig.getWxPayAppid());
nativeOrder.put("description","测试微信支付");
nativeOrder.put("notify_url",wechatPayConfig.getCallbackUrl());
//微信支付 支付信息结点
ObjectNode payNode = objectMapper.createObjectNode();
//订单支付的总金额 单位为分
payNode.put("total",100);
payNode.put("currency","CNY");
nativeOrder.set("amount",payNode);
String requestBody = nativeOrder.toString();
log.info("微信支付请求报文为{}",requestBody);
StringEntity entity = new StringEntity(requestBody, StandardCharsets.UTF_8);
entity.setContentType("application/json");
//调用native API
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
httpPost.setHeader("Accept","application/json");
httpPost.setEntity(entity);
//使用封装的httpClient自动进行参数签名
try(CloseableHttpResponse response = wechatHttpClient.execute(httpPost)) {
//响应码
int statusCode = response.getStatusLine().getStatusCode();
log.info("native下单接口响应码为:{}",statusCode);
if (HttpStatus.SC_OK == statusCode){
String responseBody = EntityUtils.toString(response.getEntity());
log.info("native下单接口返回内容为:{}",responseBody);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
查询订单API接口调用
@Test
public void testNativeQuery(){
//上一步中的商户订单号
String outTradeNo = "123456789abcdefghijk";
String queryUrl = String.format("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s?mchid=%s", outTradeNo,wechatPayConfig.getMchId());
HttpGet httpGet = new HttpGet(queryUrl);
httpGet.setHeader("Accept","application/json");
try (CloseableHttpResponse response = wechatHttpClient.execute(httpGet)){
int statusCode = response.getStatusLine().getStatusCode();
log.info("native query下单接口响应码为:{}",statusCode);
if (HttpStatus.SC_OK == statusCode){
String responseBody = EntityUtils.toString(response.getEntity());
log.info("native query下单接口返回内容为:{}",responseBody);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}