微信支付
parent
0c1b1ea48e
commit
d2715834ce
|
@ -0,0 +1,34 @@
|
||||||
|
package com.muyu.pay.wechat.clients;
|
||||||
|
|
||||||
|
import com.dtflys.forest.annotation.BaseRequest;
|
||||||
|
import com.dtflys.forest.annotation.JSONBody;
|
||||||
|
import com.dtflys.forest.annotation.Post;
|
||||||
|
import com.muyu.pay.wechat.clients.interceptor.WeChatAuthInterceptor;
|
||||||
|
import com.muyu.pay.wechat.domain.req.WeChatPayAppReq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author DongZl
|
||||||
|
* @description: 微信App支付
|
||||||
|
* @Date 2023/8/29 12:44
|
||||||
|
*/
|
||||||
|
|
||||||
|
@BaseRequest(
|
||||||
|
baseURL = "https://api.mch.weixin.qq.com/v3/pay/transactions",
|
||||||
|
contentType = "application/json",
|
||||||
|
headers = {
|
||||||
|
"Accept: application/json"
|
||||||
|
},
|
||||||
|
interceptor = WeChatAuthInterceptor.class
|
||||||
|
)
|
||||||
|
public interface WeChatAppClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App 支付下单
|
||||||
|
* @param weChatPayReq 请求参数
|
||||||
|
* @return 响应结果
|
||||||
|
*/
|
||||||
|
@Post(
|
||||||
|
url = "/app"
|
||||||
|
)
|
||||||
|
public String order(@JSONBody WeChatPayAppReq weChatPayReq);
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import com.dtflys.forest.annotation.BaseRequest;
|
||||||
import com.dtflys.forest.annotation.JSONBody;
|
import com.dtflys.forest.annotation.JSONBody;
|
||||||
import com.dtflys.forest.annotation.Post;
|
import com.dtflys.forest.annotation.Post;
|
||||||
import com.muyu.pay.wechat.clients.interceptor.WeChatAuthInterceptor;
|
import com.muyu.pay.wechat.clients.interceptor.WeChatAuthInterceptor;
|
||||||
import com.muyu.pay.wechat.domain.req.WeChatPayReqWeChatPay;
|
import com.muyu.pay.wechat.domain.req.WeChatPayNativeReq;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author DongZl
|
* @author DongZl
|
||||||
|
@ -23,11 +23,11 @@ public interface WeChatNativeClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Native 支付下单
|
* Native 支付下单
|
||||||
* @param jsonObject 请求参数
|
* @param weChatPayReq 请求参数
|
||||||
* @return 响应结果
|
* @return 响应结果
|
||||||
*/
|
*/
|
||||||
@Post(
|
@Post(
|
||||||
url = "/native"
|
url = "/native"
|
||||||
)
|
)
|
||||||
public String order(@JSONBody WeChatPayReqWeChatPay weChatPayReq);
|
public String order(@JSONBody WeChatPayNativeReq weChatPayReq);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.dtflys.forest.interceptor.Interceptor;
|
||||||
import com.dtflys.forest.reflection.ForestMethod;
|
import com.dtflys.forest.reflection.ForestMethod;
|
||||||
import com.muyu.pay.wechat.config.WechatPayConfig;
|
import com.muyu.pay.wechat.config.WechatPayConfig;
|
||||||
import com.muyu.pay.wechat.domain.WeChatPayBaseReq;
|
import com.muyu.pay.wechat.domain.WeChatPayBaseReq;
|
||||||
|
import com.muyu.pay.wechat.domain.model.WeChatSignModel;
|
||||||
import com.muyu.pay.wechat.service.WeChatSignService;
|
import com.muyu.pay.wechat.service.WeChatSignService;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -57,17 +58,16 @@ public class WeChatAuthInterceptor<T> implements Interceptor<T> {
|
||||||
log.debug("微信请求前拦截 - 添加Authorization授权请求头");
|
log.debug("微信请求前拦截 - 添加Authorization授权请求头");
|
||||||
ForestBody forestBody = req.getBody();
|
ForestBody forestBody = req.getBody();
|
||||||
String body = forestBody.encodeToString();
|
String body = forestBody.encodeToString();
|
||||||
ForestMethod forestMethod = req.getMethod();
|
|
||||||
String methodName = req.getType().getName();
|
String methodName = req.getType().getName();
|
||||||
String url = req.getUrl();
|
String url = req.getUrl();
|
||||||
String authorization = null;
|
WeChatSignModel weChatSignModel = null;
|
||||||
if (HttpMethod.GET.matches(methodName)){
|
if (HttpMethod.GET.matches(methodName)){
|
||||||
authorization = weChatSignService.tokenByGet(url);
|
weChatSignModel = weChatSignService.tokenByGet(url);
|
||||||
}else if (HttpMethod.POST.matches(methodName)){
|
}else if (HttpMethod.POST.matches(methodName)){
|
||||||
authorization = weChatSignService.tokenByPost(url, body);
|
weChatSignModel = weChatSignService.tokenByPost(url, body);
|
||||||
}
|
}
|
||||||
// 添加Header
|
// 添加Header
|
||||||
req.addHeader("Authorization", authorization);
|
req.addHeader("Authorization", weChatSignModel.getSign());
|
||||||
// 继续执行请求返回true
|
// 继续执行请求返回true
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,18 @@ package com.muyu.pay.wechat.config;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
import static com.muyu.pay.wechat.constant.WechatPayConstant.*;
|
import static com.muyu.pay.wechat.constant.WechatPayConstant.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,6 +24,26 @@ import static com.muyu.pay.wechat.constant.WechatPayConstant.*;
|
||||||
@Configuration
|
@Configuration
|
||||||
public class WechatPayConfigure {
|
public class WechatPayConfigure {
|
||||||
|
|
||||||
|
public PrivateKey getPrivateKey(String filename) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
String content = new String(Files.readAllBytes(Paths.get(filename)), StandardCharsets.UTF_8);
|
||||||
|
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("无效的密钥格式");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化微信支付配置
|
* 初始化微信支付配置
|
||||||
* @return 微信支付配置
|
* @return 微信支付配置
|
||||||
|
@ -19,15 +51,15 @@ public class WechatPayConfigure {
|
||||||
@Bean
|
@Bean
|
||||||
public WechatPayConfig initWechatPayConfig(){
|
public WechatPayConfig initWechatPayConfig(){
|
||||||
return WechatPayConfig.builder()
|
return WechatPayConfig.builder()
|
||||||
.appid("wx1a60b1d281c88896")
|
.appid("*****")
|
||||||
.merchantId("1645775803")
|
.merchantId("*****")
|
||||||
.payKey("wentaoyun1234567wentaoyun1234567")
|
.payKey("*****")
|
||||||
.algorithmType(ALGORITHM_TYPE)
|
.algorithmType(ALGORITHM_TYPE)
|
||||||
.schema(SCHEMA)
|
.schema(SCHEMA)
|
||||||
// 自己填我不知道
|
// 自己填我不知道
|
||||||
.serialNo(null)
|
.serialNo("******")
|
||||||
// 自己填我不知道
|
// 自己填我不知道
|
||||||
.privateKey(null)
|
.privateKey(getPrivateKey("D:\\work\\demo\\wechat-pay\\src\\main\\resources\\wechat\\wxpaykey.pem"))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.muyu.pay.wechat.domain.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author DongZl
|
||||||
|
* @description: 微信支付Sign签名对象
|
||||||
|
* @Date 2023/8/29 12:54
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class WeChatSignModel {
|
||||||
|
|
||||||
|
private String sign;
|
||||||
|
|
||||||
|
|
||||||
|
private long timestamp;
|
||||||
|
|
||||||
|
|
||||||
|
private String nonceStr;
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.muyu.pay.wechat.domain.req;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.muyu.pay.wechat.domain.WeChatPayBaseReq;
|
||||||
|
import com.muyu.pay.wechat.domain.model.WeChatPayAmountModel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author DongZl
|
||||||
|
* @description: 微信支付模型
|
||||||
|
* @Date 2023-8-21 下午 03:17
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class WeChatPayAppReq extends WeChatPayBaseReq {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商户订单号
|
||||||
|
*/
|
||||||
|
@JSONField(name = "out_trade_no")
|
||||||
|
private String outTradeNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知地址
|
||||||
|
*/
|
||||||
|
@JSONField(name = "notify_url")
|
||||||
|
private String notifyUrl;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单金额
|
||||||
|
*/
|
||||||
|
@JSONField(name = "amount")
|
||||||
|
private WeChatPayAmountModel payAmountModel;
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ import lombok.experimental.SuperBuilder;
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class WeChatPayReqWeChatPay extends WeChatPayBaseReq {
|
public class WeChatPayNativeReq extends WeChatPayBaseReq {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商品描述
|
* 商品描述
|
|
@ -1,18 +1,25 @@
|
||||||
package com.muyu.pay.wechat.service;
|
package com.muyu.pay.wechat.service;
|
||||||
|
|
||||||
import com.muyu.pay.wechat.config.WechatPayConfig;
|
import com.muyu.pay.wechat.config.WechatPayConfig;
|
||||||
|
import com.muyu.pay.wechat.domain.model.WeChatSignModel;
|
||||||
import com.muyu.utils.IdUtils;
|
import com.muyu.utils.IdUtils;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.InvalidKeyException;
|
import java.nio.file.Files;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.nio.file.Paths;
|
||||||
import java.security.Signature;
|
import java.security.*;
|
||||||
import java.security.SignatureException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.muyu.pay.wechat.constant.WechatPayConstant.ALGORITHM_TYPE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author DongZl
|
* @author DongZl
|
||||||
|
@ -28,72 +35,57 @@ public class WeChatSignService {
|
||||||
*/
|
*/
|
||||||
private final WechatPayConfig wechatPayConfig;
|
private final WechatPayConfig wechatPayConfig;
|
||||||
|
|
||||||
|
public WeChatSignModel tokenByPost(String url, String bodyJson){
|
||||||
public String tokenByPost(String url, String bodyJson){
|
return getToken("POST", HttpUrl.parse(url), bodyJson);
|
||||||
return wechatPayConfig.getSchema() + " " + getToken("POST", HttpUrl.parse(url), bodyJson);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String tokenByGet(String url){
|
public WeChatSignModel tokenByGet(String url){
|
||||||
return wechatPayConfig.getSchema() + " " + getToken("GET", HttpUrl.parse(url), "");
|
return getToken("POST", HttpUrl.parse(url), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public WeChatSignModel getToken(String method, HttpUrl url, String body) {
|
||||||
* 获取token
|
String nonceStr = IdUtils.simpleUUID();
|
||||||
* @param method 请求方式
|
|
||||||
* @param url url
|
|
||||||
* @param body 请求参数
|
|
||||||
* @return 签名 token
|
|
||||||
*/
|
|
||||||
public String getToken(String method, HttpUrl url, String body) {
|
|
||||||
String nonceStr = IdUtils.simpleUUID().toUpperCase();
|
|
||||||
long timestamp = System.currentTimeMillis() / 1000;
|
long timestamp = System.currentTimeMillis() / 1000;
|
||||||
String message = buildMessage(method, url, timestamp, nonceStr, body);
|
String message = buildMessage(method, url, timestamp, nonceStr, body);
|
||||||
String signature = sign(message.getBytes(StandardCharsets.UTF_8));
|
String signature = null;
|
||||||
return "mchid=\"" + wechatPayConfig.getPayKey() + "\","
|
try {
|
||||||
|
signature = sign(message.getBytes(StandardCharsets.UTF_8));
|
||||||
|
} catch (NoSuchAlgorithmException | IOException | InvalidKeyException | SignatureException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return WeChatSignModel.builder()
|
||||||
|
.sign(
|
||||||
|
wechatPayConfig.getSchema()+" mchid=\""+wechatPayConfig.getMerchantId()+"\","
|
||||||
+ "nonce_str=\""+nonceStr+"\","
|
+ "nonce_str=\""+nonceStr+"\","
|
||||||
+ "timestamp=\""+timestamp+"\","
|
+ "timestamp=\""+timestamp+"\","
|
||||||
+ "serial_no=\""+wechatPayConfig.getSerialNo()+"\","
|
+ "serial_no=\""+wechatPayConfig.getSerialNo()+"\","
|
||||||
+ "signature=\"" + signature + "\"";
|
+ "signature=\""+signature+"\""
|
||||||
|
)
|
||||||
|
.timestamp(timestamp)
|
||||||
|
.nonceStr(nonceStr)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private String sign(byte[] message) throws NoSuchAlgorithmException, IOException, InvalidKeyException, SignatureException {
|
||||||
* 进行算法签名
|
Signature sign = Signature.getInstance(ALGORITHM_TYPE);
|
||||||
* @param message 信息
|
|
||||||
* @return 签名信息
|
|
||||||
*/
|
|
||||||
private String sign(byte[] message) {
|
|
||||||
Signature sign = null;
|
|
||||||
try {
|
|
||||||
sign = Signature.getInstance(wechatPayConfig.getAlgorithmType());
|
|
||||||
sign.initSign(wechatPayConfig.getPrivateKey());
|
sign.initSign(wechatPayConfig.getPrivateKey());
|
||||||
sign.update(message);
|
sign.update(message);
|
||||||
|
|
||||||
return Base64.getEncoder().encodeToString(sign.sign());
|
return Base64.getEncoder().encodeToString(sign.sign());
|
||||||
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
|
|
||||||
log.info("微信支付获取签名失败:{}", e.getMessage(), e);
|
|
||||||
throw new RuntimeException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
|
||||||
* 构建签名明细
|
|
||||||
* @param method 请求方式
|
|
||||||
* @param url 请求rul
|
|
||||||
* @param timestamp 请求时间戳
|
|
||||||
* @param nonceStr 随机字符串
|
|
||||||
* @param body 请求体
|
|
||||||
* @return 请求明细
|
|
||||||
*/
|
|
||||||
private String buildMessage(String method, HttpUrl url, long timestamp,
|
|
||||||
String nonceStr, String body) {
|
|
||||||
String canonicalUrl = url.encodedPath();
|
String canonicalUrl = url.encodedPath();
|
||||||
if (url.encodedQuery() != null) {
|
if (url.encodedQuery() != null) {
|
||||||
canonicalUrl += "?" + url.encodedQuery();
|
canonicalUrl += "?" + url.encodedQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return method + "\n"
|
return method + "\n"
|
||||||
+ canonicalUrl + "\n"
|
+ canonicalUrl + "\n"
|
||||||
+ timestamp + "\n"
|
+ timestamp + "\n"
|
||||||
+ nonceStr + "\n"
|
+ nonceStr + "\n"
|
||||||
+ body + "\n";
|
+ body + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.muyu.wechat.pay;
|
||||||
|
|
||||||
|
import com.muyu.WechatPayApplication;
|
||||||
|
import com.muyu.pay.wechat.clients.WeChatAppClient;
|
||||||
|
import com.muyu.pay.wechat.domain.model.WeChatPayAmountModel;
|
||||||
|
import com.muyu.pay.wechat.domain.req.WeChatPayAppReq;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author DongZl
|
||||||
|
* @description: 微信支付下单测试类
|
||||||
|
* @Date 2023-8-21 下午 02:55
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@SpringBootTest(classes = WechatPayApplication.class)
|
||||||
|
public class AppClientTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信 native支付
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private WeChatAppClient weChatAppClient;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void order(){
|
||||||
|
String orderResult = weChatAppClient.order(
|
||||||
|
WeChatPayAppReq.builder()
|
||||||
|
.description("测试商品")
|
||||||
|
.outTradeNo("12341684615")
|
||||||
|
.notifyUrl("http://doc.qinmian.online")
|
||||||
|
.payAmountModel(
|
||||||
|
WeChatPayAmountModel.totalBuild(1)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
log.info(orderResult);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ package com.muyu.wechat.pay;
|
||||||
import com.muyu.WechatPayApplication;
|
import com.muyu.WechatPayApplication;
|
||||||
import com.muyu.pay.wechat.clients.WeChatNativeClient;
|
import com.muyu.pay.wechat.clients.WeChatNativeClient;
|
||||||
import com.muyu.pay.wechat.domain.model.WeChatPayAmountModel;
|
import com.muyu.pay.wechat.domain.model.WeChatPayAmountModel;
|
||||||
import com.muyu.pay.wechat.domain.req.WeChatPayReqWeChatPay;
|
import com.muyu.pay.wechat.domain.req.WeChatPayNativeReq;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -27,7 +27,7 @@ public class NativeClientTest {
|
||||||
@Test
|
@Test
|
||||||
public void order(){
|
public void order(){
|
||||||
String orderResult = weChatNativeClient.order(
|
String orderResult = weChatNativeClient.order(
|
||||||
WeChatPayReqWeChatPay.builder()
|
WeChatPayNativeReq.builder()
|
||||||
.description("测试商品")
|
.description("测试商品")
|
||||||
.outTradeNo("12341684615")
|
.outTradeNo("12341684615")
|
||||||
.notifyUrl("http://doc.qinmian.online")
|
.notifyUrl("http://doc.qinmian.online")
|
||||||
|
|
Loading…
Reference in New Issue