差签名

master
DongZeLiang 2023-08-21 16:39:21 +08:00
parent bc2fd16e25
commit 0c1b1ea48e
14 changed files with 1029 additions and 59 deletions

View File

@ -13,7 +13,7 @@
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<forest.version>1.5.32</forest.version>
<fastjson2.version>2.0.38</fastjson2.version>
<fastjson.version>1.2.73</fastjson.version>
</properties>
<parent>
@ -40,9 +40,9 @@
<!-- Json框架 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson2.version}</version>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- API 请求框架 -->

View File

@ -0,0 +1,33 @@
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.WeChatPayReqWeChatPay;
/**
* @author DongZl
* @description: Native
* @Date 2023-8-21 02:42
*/
@BaseRequest(
baseURL = "https://api.mch.weixin.qq.com/v3/pay/transactions",
contentType = "application/json",
headers = {
"Accept: application/json"
},
interceptor = WeChatAuthInterceptor.class
)
public interface WeChatNativeClient {
/**
* Native
* @param jsonObject
* @return
*/
@Post(
url = "/native"
)
public String order(@JSONBody WeChatPayReqWeChatPay weChatPayReq);
}

View File

@ -0,0 +1,74 @@
package com.muyu.pay.wechat.clients.interceptor;
import com.dtflys.forest.http.ForestBody;
import com.dtflys.forest.http.ForestRequest;
import com.dtflys.forest.interceptor.Interceptor;
import com.dtflys.forest.reflection.ForestMethod;
import com.muyu.pay.wechat.config.WechatPayConfig;
import com.muyu.pay.wechat.domain.WeChatPayBaseReq;
import com.muyu.pay.wechat.service.WeChatSignService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
/**
* @author DongZl
* @description:
* @Date 2023-8-21 03:06
*/
@Log4j2
@Component
public class WeChatAuthInterceptor<T> implements Interceptor<T> {
@Autowired
private WechatPayConfig wechatPayConfig;
@Autowired
private WeChatSignService weChatSignService;
public WeChatAuthInterceptor () {
log.info("微信支付请求拦截器 - 初始化成功");
}
/**
* beforeExecute
* @Param request Forest
* @Param args
*/
@Override
public void onInvokeMethod(ForestRequest req, ForestMethod method, Object[] args) {
log.debug("进行用户微信公众号和商户号填写");
for (Object arg : args) {
if (arg instanceof WeChatPayBaseReq){
WeChatPayBaseReq weChatPayBaseReq = (WeChatPayBaseReq) arg;
weChatPayBaseReq.setAppid(wechatPayConfig.getAppid());
weChatPayBaseReq.setMchid(wechatPayConfig.getMerchantId());
}
}
}
/**
* , false
* @Param request Forest
*/
@Override
public boolean beforeExecute(ForestRequest req) {
log.debug("微信请求前拦截 - 添加Authorization授权请求头");
ForestBody forestBody = req.getBody();
String body = forestBody.encodeToString();
ForestMethod forestMethod = req.getMethod();
String methodName = req.getType().getName();
String url = req.getUrl();
String authorization = null;
if (HttpMethod.GET.matches(methodName)){
authorization = weChatSignService.tokenByGet(url);
}else if (HttpMethod.POST.matches(methodName)){
authorization = weChatSignService.tokenByPost(url, body);
}
// 添加Header
req.addHeader("Authorization", authorization);
// 继续执行请求返回true
return true;
}
}

View File

@ -0,0 +1,56 @@
package com.muyu.pay.wechat.config;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.security.PrivateKey;
/**
* @author DongZl
* @description:
* @Date 2023-8-21 01:54
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WechatPayConfig {
/**
* Id
*/
private String appid;
/**
* ID
*/
private String merchantId ;
/**
* Key
*/
private String payKey;
/**
* SHA256withRSA
*/
private String algorithmType;
/**
*
*/
private String schema;
/**
*
*/
private String serialNo;
/**
*
*/
private PrivateKey privateKey;
}

View File

@ -0,0 +1,33 @@
package com.muyu.pay.wechat.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static com.muyu.pay.wechat.constant.WechatPayConstant.*;
/**
* @author DongZl
* @description:
* @Date 2023-8-21 02:34
*/
@Configuration
public class WechatPayConfigure {
/**
*
* @return
*/
@Bean
public WechatPayConfig initWechatPayConfig(){
return WechatPayConfig.builder()
.appid("wx1a60b1d281c88896")
.merchantId("1645775803")
.payKey("wentaoyun1234567wentaoyun1234567")
.algorithmType(ALGORITHM_TYPE)
.schema(SCHEMA)
// 自己填我不知道
.serialNo(null)
// 自己填我不知道
.privateKey(null)
.build();
}
}

View File

@ -0,0 +1,20 @@
package com.muyu.pay.wechat.constant;
/**
* @author DongZl
* @description:
* @Date 2023-8-21 02:36
*/
public class WechatPayConstant {
/**
* SHA256withRSA
*/
public final static String ALGORITHM_TYPE = "SHA256withRSA";
/**
*
*/
public final static String SCHEMA = "WECHATPAY2-SHA256-RSA2048";
}

View File

@ -0,0 +1,27 @@
package com.muyu.pay.wechat.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* @author DongZl
* @description:
* @Date 2023-8-21 03:29
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class WeChatPayBaseReq {
/**
* ID
*/
private String appid;
/**
* ID
*/
private String mchid;
}

View File

@ -0,0 +1,40 @@
package com.muyu.pay.wechat.domain.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author DongZl
* @description:
* @Date 2023-8-21 04:04
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WeChatPayAmountModel {
/**
*
*/
private int total;
/**
* CNY()
*/
private String currency;
/**
*
* @param total
* @return
*/
public static WeChatPayAmountModel totalBuild(int total){
return WeChatPayAmountModel.builder()
.total(total)
.currency("CNY")
.build();
}
}

View File

@ -0,0 +1,45 @@
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.*;
import lombok.experimental.SuperBuilder;
/**
* @author DongZl
* @description:
* @Date 2023-8-21 03:17
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class WeChatPayReqWeChatPay 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;
}

View File

@ -0,0 +1,99 @@
package com.muyu.pay.wechat.service;
import com.muyu.pay.wechat.config.WechatPayConfig;
import com.muyu.utils.IdUtils;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import okhttp3.HttpUrl;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Base64;
/**
* @author DongZl
* @description:
* @Date 2023-8-21 11:23
*/
@Log4j2
@Service
@AllArgsConstructor
public class WeChatSignService {
/**
*
*/
private final WechatPayConfig wechatPayConfig;
public String tokenByPost(String url, String bodyJson){
return wechatPayConfig.getSchema() + " " + getToken("POST", HttpUrl.parse(url), bodyJson);
}
public String tokenByGet(String url){
return wechatPayConfig.getSchema() + " " + getToken("GET", HttpUrl.parse(url), "");
}
/**
* token
* @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;
String message = buildMessage(method, url, timestamp, nonceStr, body);
String signature = sign(message.getBytes(StandardCharsets.UTF_8));
return "mchid=\"" + wechatPayConfig.getPayKey() + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + wechatPayConfig.getSerialNo() + "\","
+ "signature=\"" + signature + "\"";
}
/**
*
* @param message
* @return
*/
private String sign(byte[] message) {
Signature sign = null;
try {
sign = Signature.getInstance(wechatPayConfig.getAlgorithmType());
sign.initSign(wechatPayConfig.getPrivateKey());
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
log.info("微信支付获取签名失败:{}", e.getMessage(), e);
throw new RuntimeException(e.getMessage());
}
}
/**
*
* @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();
if (url.encodedQuery() != null) {
canonicalUrl += "?" + url.encodedQuery();
}
return method + "\n"
+ canonicalUrl + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ body + "\n";
}
}

View File

@ -1,55 +0,0 @@
package com.muyu.pay.wechat.utils;
import okhttp3.HttpUrl;
import java.security.Signature;
import java.util.Base64;
/**
* @author DongZl
* @description:
* @Date 2023-8-21 11:23
*/
public class SignUtils {
// Authorization: <schema> <token>
// GET - getToken("GET", httpurl, "")
// POST - getToken("POST", httpurl, json)
String schema = "WECHATPAY2-SHA256-RSA2048";
HttpUrl httpurl = HttpUrl.parse(url);
String getToken(String method, HttpUrl url, String body) {
String nonceStr = "your nonce string";
long timestamp = System.currentTimeMillis() / 1000;
String message = buildMessage(method, url, timestamp, nonceStr, body);
String signature = sign(message.getBytes("utf-8"));
return "mchid=\"" + yourMerchantId + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + yourCertificateSerialNo + "\","
+ "signature=\"" + signature + "\"";
}
String sign(byte[] message) {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(yourPrivateKey);
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
String canonicalUrl = url.encodedPath();
if (url.encodedQuery() != null) {
canonicalUrl += "?" + url.encodedQuery();
}
return method + "\n"
+ canonicalUrl + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ body + "\n";
}
}

View File

@ -0,0 +1,72 @@
package com.muyu.utils;
import java.util.Random;
/**
* ID
*
* @author leiyonghui
*/
public class IdUtils
{
/**
* UUID
*
* @return UUID
*/
public static String randomUUID()
{
return UUID.randomUUID().toString();
}
/**
* UUID线
*
* @return UUID线
*/
public static String simpleUUID()
{
return UUID.randomUUID().toString(true);
}
/**
* UUID使ThreadLocalRandomUUID
*
* @return UUID
*/
public static String fastUUID()
{
return UUID.fastUUID().toString();
}
/**
* UUID线使ThreadLocalRandomUUID
*
* @return UUID线
*/
public static String fastSimpleUUID()
{
return UUID.fastUUID().toString(true);
}
/**
*
* @param tag
* @return
*/
public static String getNewNumber(String tag)
{
StringBuffer sb = new StringBuffer("");
Random random = new Random();
for (int i=0;i<6;i++)
{
sb.append(random.nextInt(10));
}
String number = tag+System.currentTimeMillis()+sb.toString();
return number;
}
}

View File

@ -0,0 +1,485 @@
package com.muyu.utils;
import com.sun.xml.internal.ws.util.UtilException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
/**
* universally unique identifierUUID
*
* @author leiyonghui
*/
public final class UUID implements java.io.Serializable, Comparable<UUID>
{
private static final long serialVersionUID = -1185015143654744140L;
/**
* SecureRandom
*
*/
private static class Holder
{
static final SecureRandom numberGenerator = getSecureRandom();
}
/** 此UUID的最高64有效位 */
private final long mostSigBits;
/** 此UUID的最低64有效位 */
private final long leastSigBits;
/**
*
*
* @param data
*/
private UUID(byte[] data)
{
long msb = 0;
long lsb = 0;
assert data.length == 16 : "data must be 16 bytes in length";
for (int i = 0; i < 8; i++)
{
msb = (msb << 8) | (data[i] & 0xff);
}
for (int i = 8; i < 16; i++)
{
lsb = (lsb << 8) | (data[i] & 0xff);
}
this.mostSigBits = msb;
this.leastSigBits = lsb;
}
/**
* 使 UUID
*
* @param mostSigBits {@code UUID} 64
* @param leastSigBits {@code UUID} 64
*/
public UUID(long mostSigBits, long leastSigBits)
{
this.mostSigBits = mostSigBits;
this.leastSigBits = leastSigBits;
}
/**
* 4UUID 使线 UUID
*
* @return {@code UUID}
*/
public static UUID fastUUID()
{
return randomUUID(false);
}
/**
* 4UUID 使 UUID
*
* @return {@code UUID}
*/
public static UUID randomUUID()
{
return randomUUID(true);
}
/**
* 4UUID 使 UUID
*
* @param isSecure 使{@link SecureRandom}
* @return {@code UUID}
*/
public static UUID randomUUID(boolean isSecure)
{
final Random ng = isSecure ? Holder.numberGenerator : getRandom();
byte[] randomBytes = new byte[16];
ng.nextBytes(randomBytes);
randomBytes[6] &= 0x0f; /* clear version */
randomBytes[6] |= 0x40; /* set to version 4 */
randomBytes[8] &= 0x3f; /* clear variant */
randomBytes[8] |= 0x80; /* set to IETF variant */
return new UUID(randomBytes);
}
/**
* 3UUID
*
* @param name UUID
*
* @return {@code UUID}
*/
public static UUID nameUUIDFromBytes(byte[] name)
{
MessageDigest md;
try
{
md = MessageDigest.getInstance("MD5");
}
catch (NoSuchAlgorithmException nsae)
{
throw new InternalError("MD5 not supported");
}
byte[] md5Bytes = md.digest(name);
md5Bytes[6] &= 0x0f; /* clear version */
md5Bytes[6] |= 0x30; /* set to version 3 */
md5Bytes[8] &= 0x3f; /* clear variant */
md5Bytes[8] |= 0x80; /* set to IETF variant */
return new UUID(md5Bytes);
}
/**
* {@link #toString()} {@code UUID}
*
* @param name {@code UUID}
* @return {@code UUID}
* @throws IllegalArgumentException name {@link #toString}
*
*/
public static UUID fromString(String name)
{
String[] components = name.split("-");
if (components.length != 5)
{
throw new IllegalArgumentException("Invalid UUID string: " + name);
}
for (int i = 0; i < 5; i++)
{
components[i] = "0x" + components[i];
}
long mostSigBits = Long.decode(components[0]).longValue();
mostSigBits <<= 16;
mostSigBits |= Long.decode(components[1]).longValue();
mostSigBits <<= 16;
mostSigBits |= Long.decode(components[2]).longValue();
long leastSigBits = Long.decode(components[3]).longValue();
leastSigBits <<= 48;
leastSigBits |= Long.decode(components[4]).longValue();
return new UUID(mostSigBits, leastSigBits);
}
/**
* UUID 128 64
*
* @return UUID 128 64
*/
public long getLeastSignificantBits()
{
return leastSigBits;
}
/**
* UUID 128 64
*
* @return UUID 128 64
*/
public long getMostSignificantBits()
{
return mostSigBits;
}
/**
* {@code UUID} . {@code UUID}
* <p>
* :
* <ul>
* <li>1 UUID
* <li>2 DCE UUID
* <li>3 UUID
* <li>4 UUID
* </ul>
*
* @return {@code UUID}
*/
public int version()
{
// Version is bits masked by 0x000000000000F000 in MS long
return (int) ((mostSigBits >> 12) & 0x0f);
}
/**
* {@code UUID} {@code UUID}
* <p>
*
* <ul>
* <li>0 NCS
* <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF&nbsp;RFC&nbsp;4122</a>(Leach-Salz),
* <li>6
* <li>7 使
* </ul>
*
* @return {@code UUID}
*/
public int variant()
{
// This field is composed of a varying number of bits.
// 0 - - Reserved for NCS backward compatibility
// 1 0 - The IETF aka Leach-Salz variant (used by this class)
// 1 1 0 Reserved, Microsoft backward compatibility
// 1 1 1 Reserved for future definition.
return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));
}
/**
* UUID
*
* <p>
* 60 {@code UUID} time_lowtime_mid time_hi <br>
* 100 UTC 1582 10 15
*
* <p>
* UUID version 1<br>
* {@code UUID} UUID UnsupportedOperationException
*
* @throws UnsupportedOperationException {@code UUID} version 1 UUID
*/
public long timestamp() throws UnsupportedOperationException
{
checkTimeBase();
return (mostSigBits & 0x0FFFL) << 48//
| ((mostSigBits >> 16) & 0x0FFFFL) << 32//
| mostSigBits >>> 32;
}
/**
* UUID
*
* <p>
* 14 UUID clock_seq clock_seq UUID
* <p>
* {@code clockSequence} UUID version 1 UUID UUID
* UnsupportedOperationException
*
* @return {@code UUID}
*
* @throws UnsupportedOperationException UUID version 1
*/
public int clockSequence() throws UnsupportedOperationException
{
checkTimeBase();
return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);
}
/**
* UUID
*
* <p>
* 48 UUID node IEEE 802 UUID
* <p>
* UUID version 1<br>
* UUID UUID UnsupportedOperationException
*
* @return {@code UUID}
*
* @throws UnsupportedOperationException UUID version 1
*/
public long node() throws UnsupportedOperationException
{
checkTimeBase();
return leastSigBits & 0x0000FFFFFFFFFFFFL;
}
/**
* {@code UUID}
*
* <p>
* UUID BNF
*
* <pre>
* {@code
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
* time_low = 4*<hexOctet>
* time_mid = 2*<hexOctet>
* time_high_and_version = 2*<hexOctet>
* variant_and_sequence = 2*<hexOctet>
* node = 6*<hexOctet>
* hexOctet = <hexDigit><hexDigit>
* hexDigit = [0-9a-fA-F]
* }
* </pre>
*
* </blockquote>
*
* @return {@code UUID}
* @see #toString(boolean)
*/
@Override
public String toString()
{
return toString(false);
}
/**
* {@code UUID}
*
* <p>
* UUID BNF
*
* <pre>
* {@code
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
* time_low = 4*<hexOctet>
* time_mid = 2*<hexOctet>
* time_high_and_version = 2*<hexOctet>
* variant_and_sequence = 2*<hexOctet>
* node = 6*<hexOctet>
* hexOctet = <hexDigit><hexDigit>
* hexDigit = [0-9a-fA-F]
* }
* </pre>
*
* </blockquote>
*
* @param isSimple '-'UUID
* @return {@code UUID}
*/
public String toString(boolean isSimple)
{
final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
// time_low
builder.append(digits(mostSigBits >> 32, 8));
if (false == isSimple)
{
builder.append('-');
}
// time_mid
builder.append(digits(mostSigBits >> 16, 4));
if (false == isSimple)
{
builder.append('-');
}
// time_high_and_version
builder.append(digits(mostSigBits, 4));
if (false == isSimple)
{
builder.append('-');
}
// variant_and_sequence
builder.append(digits(leastSigBits >> 48, 4));
if (false == isSimple)
{
builder.append('-');
}
// node
builder.append(digits(leastSigBits, 12));
return builder.toString();
}
/**
* UUID
*
* @return UUID
*/
@Override
public int hashCode()
{
long hilo = mostSigBits ^ leastSigBits;
return ((int) (hilo >> 32)) ^ (int) hilo;
}
/**
*
* <p>
* {@code null} UUID UUID varriant {@code true}
*
* @param obj
*
* @return {@code true} {@code false}
*/
@Override
public boolean equals(Object obj)
{
if ((null == obj) || (obj.getClass() != UUID.class))
{
return false;
}
UUID id = (UUID) obj;
return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits);
}
// Comparison Operations
/**
* UUID UUID
*
* <p>
* UUID UUID UUID UUID UUID
*
* @param val UUID UUID
*
* @return UUID val -10 1
*
*/
@Override
public int compareTo(UUID val)
{
// The ordering is intentionally set up so that the UUIDs
// can simply be numerically compared as two numbers
return (this.mostSigBits < val.mostSigBits ? -1 : //
(this.mostSigBits > val.mostSigBits ? 1 : //
(this.leastSigBits < val.leastSigBits ? -1 : //
(this.leastSigBits > val.leastSigBits ? 1 : //
0))));
}
// -------------------------------------------------------------------------------------------------------------------
// Private method start
/**
* hex
*
* @param val
* @param digits
* @return
*/
private static String digits(long val, int digits)
{
long hi = 1L << (digits * 4);
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
}
/**
* time-basedUUID
*/
private void checkTimeBase()
{
if (version() != 1)
{
throw new UnsupportedOperationException("Not a time-based UUID");
}
}
/**
* {@link SecureRandom} (RNG)
*
* @return {@link SecureRandom}
*/
public static SecureRandom getSecureRandom()
{
try
{
return SecureRandom.getInstance("SHA1PRNG");
}
catch (NoSuchAlgorithmException e)
{
throw new UtilException(e);
}
}
/**
* <br>
* ThreadLocalRandomJDK 7线
*
* @return {@link ThreadLocalRandom}
*/
public static ThreadLocalRandom getRandom()
{
return ThreadLocalRandom.current();
}
}

View File

@ -0,0 +1,41 @@
package com.muyu.wechat.pay;
import com.muyu.WechatPayApplication;
import com.muyu.pay.wechat.clients.WeChatNativeClient;
import com.muyu.pay.wechat.domain.model.WeChatPayAmountModel;
import com.muyu.pay.wechat.domain.req.WeChatPayReqWeChatPay;
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 NativeClientTest {
/**
* native
*/
@Autowired
private WeChatNativeClient weChatNativeClient;
@Test
public void order(){
String orderResult = weChatNativeClient.order(
WeChatPayReqWeChatPay.builder()
.description("测试商品")
.outTradeNo("12341684615")
.notifyUrl("http://doc.qinmian.online")
.payAmountModel(
WeChatPayAmountModel.totalBuild(100)
)
.build()
);
log.info(orderResult);
}
}