diff --git a/README.md b/README.md index 75f99b1..9b7a7b6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# 移动支付 Spring Boot 组件 -提供聚合支付能力。 +# 移动支付 Spring Boot 组件 多租户版 +为了满足业务中出现app支付、公众号支付、小程序支付等多appid并存的场景,对原有的进行了增强开发出了多租户版本。 ## 支持类型 @@ -31,6 +31,8 @@ wechat: pay: v3: +# 租户id + : # 应用appId 必填 app-id: xxxxxxxx # api 密钥 必填 @@ -62,9 +64,7 @@ public class PayConfig { 微信支付V3开放接口引入: ```java @Autowired - WechatPayApi wechatPayV3Api; - @Autowired - WechatMarketingFavorApi wechatMarketingFavorApi; + WechatApiProvider wechatApiProvider; ``` ###### V3 例如V3 查询商户下的优惠券 @@ -73,11 +73,13 @@ public class PayConfig { // 查询商户下的优惠券 @Test public void v3MchStocks() { - StocksQueryParams params = new StocksQueryParams(); - params.setOffset(0); - params.setLimit(10); - WechatResponseEntity objectNodeWechatResponseEntity = wechatMarketingFavorApi.queryStocksByMch(params); - System.out.println("objectNodeWechatResponseEntity = " + objectNodeWechatResponseEntity); + // 配置文件中对应的tenantID: + String tenantId =; + StocksQueryParams params = new StocksQueryParams(); + params.setOffset(0); + params.setLimit(10); + WechatResponseEntity objectNodeWechatResponseEntity = wechatApiProvider.favorApi(tenantId).queryStocksByMch(params); + System.out.println("objectNodeWechatResponseEntity = " + objectNodeWechatResponseEntity); } ``` diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java index 047b8d1..dedb735 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java @@ -14,6 +14,11 @@ public enum WechatPayV3Type { */ CERT(HttpMethod.GET, "%s/v3/certificates"), + /** + * 文件下载 + */ + FILE_DOWNLOAD(HttpMethod.GET,"%s/v3/billdownload/file"), + /** * 微信公众号支付或者小程序支付. */ @@ -33,6 +38,14 @@ public enum WechatPayV3Type { * H5支付. */ MWEB(HttpMethod.POST, "%s/v3/pay/transactions/h5"), + /** + * 微信支付订单号查询. + */ + TRANSACTION_TRANSACTION_ID(HttpMethod.GET, "%s/v3/pay/transactions/id/{transaction_id}"), + /** + * 商户订单号查询. + */ + TRANSACTION_OUT_TRADE_NO(HttpMethod.GET, "%s/v3/pay/transactions/out-trade-no/{out_trade_no}"), /** @@ -53,7 +66,7 @@ public enum WechatPayV3Type { */ MARKETING_FAVOR_USERS_COUPONS(HttpMethod.POST,"%s/v3/marketing/favor/users/{openid}/coupons"), /** - * 重启代金券API + * 重启代金券API. */ MARKETING_FAVOR_STOCKS_RESTART(HttpMethod.POST,"%s/v3/marketing/favor/stocks/{stock_id}/restart"), /** diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/AbstractApi.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/AbstractApi.java index f4bf203..2668c81 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/AbstractApi.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/AbstractApi.java @@ -50,9 +50,9 @@ public abstract class AbstractApi { return wechatPayClient.signatureProvider().wechatMetaContainer(); } - protected RequestEntity post(URI uri, Object params) { + protected RequestEntity post(URI uri, Object params,String tenantId) { try { - return RequestEntity.post(uri) + return RequestEntity.post(uri).header("Pay-TenantId",tenantId) .body(mapper.writeValueAsString(params)); } catch (JsonProcessingException e) { throw new PayException("wechat app pay json failed"); diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMarketingFavorApi.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMarketingFavorApi.java index fbf4b07..0ff9ac6 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMarketingFavorApi.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMarketingFavorApi.java @@ -63,11 +63,10 @@ public class WechatMarketingFavorApi extends AbstractApi { String mchId = v3.getMchId(); URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)) - .queryParam("pay_tenantId", this.tenantId()) .build() .toUri(); params.setBelongMerchant(mchId); - return post(uri, params); + return post(uri, params,tenantId()); } /** @@ -108,12 +107,11 @@ public class WechatMarketingFavorApi extends AbstractApi { params.setAppid(v3.getMp().getAppId()); params.setStockCreatorMchid(v3.getMchId()); URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)) - .queryParam("pay_tenantId", this.tenantId()) .build() .expand(params.getOpenid()) .toUri(); params.setOpenid(null); - return post(uri, params); + return post(uri, params,tenantId()); } /** @@ -153,11 +151,10 @@ public class WechatMarketingFavorApi extends AbstractApi { body.put("stock_creator_mchid", mchId); URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)) - .queryParam("pay_tenantId", this.tenantId()) .build() .expand(stockId) .toUri(); - return post(uri, body); + return post(uri, body,tenantId()); } /** @@ -180,7 +177,6 @@ public class WechatMarketingFavorApi extends AbstractApi { private RequestEntity queryStocksFunction(WechatPayV3Type type, StocksQueryParams params) { MultiValueMap queryParams = new LinkedMultiValueMap<>(); - queryParams.add("pay_tenantId", this.tenantId()); queryParams.add("offset", String.valueOf(params.getOffset())); queryParams.add("limit", String.valueOf(params.getLimit())); WechatPayProperties.V3 v3 = this.container().getWechatMeta(tenantId()).getV3(); @@ -215,7 +211,7 @@ public class WechatMarketingFavorApi extends AbstractApi { URI uri = uriComponents .toUri(); - return RequestEntity.get(uri).build(); + return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); } /** @@ -240,14 +236,13 @@ public class WechatMarketingFavorApi extends AbstractApi { MultiValueMap queryParams = new LinkedMultiValueMap<>(); queryParams.add("stock_creator_mchid", v3.getMchId()); - queryParams.add("pay_tenantId", this.tenantId()); URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)) .queryParams(queryParams) .build() .expand(stockId) .toUri(); - return RequestEntity.get(uri).build(); + return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); } @@ -274,7 +269,7 @@ public class WechatMarketingFavorApi extends AbstractApi { MultiValueMap queryParams = new LinkedMultiValueMap<>(); queryParams.add("appid", v3.getMp().getAppId()); - queryParams.add("pay_tenantId", this.tenantId()); + MultiValueMap pathParams = new LinkedMultiValueMap<>(); pathParams.add("openid", params.getOpenId()); @@ -284,7 +279,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .build() .expand(pathParams) .toUri(); - return RequestEntity.get(uri).build(); + return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); } @@ -339,10 +334,8 @@ public class WechatMarketingFavorApi extends AbstractApi { final String ignore = "available_mchid"; WechatPayProperties.V3 v3 = this.container().getWechatMeta(tenantId()).getV3(); - MultiValueMap queryParams = new LinkedMultiValueMap<>(); queryParams.add("appid", v3.getMp().getAppId()); - queryParams.add("pay_tenantId", this.tenantId()); String stockId = params.getStockId(); if (StringUtils.hasText(stockId)) { queryParams.add("stock_id", stockId); @@ -371,7 +364,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .build() .expand(params.getOpenId()) .toUri(); - return RequestEntity.get(uri).build(); + return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); } @@ -408,11 +401,10 @@ public class WechatMarketingFavorApi extends AbstractApi { private RequestEntity downloadFlowFunction(WechatPayV3Type type, String stockId) { URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)) - .queryParam("pay_tenantId", this.tenantId()) .build() .expand(stockId) .toUri(); - return RequestEntity.get(uri).build(); + return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); } /** @@ -452,6 +444,7 @@ public class WechatMarketingFavorApi extends AbstractApi { return RequestEntity.post(uri) .header("Content-Type", MediaType.MULTIPART_FORM_DATA_VALUE) .header("Meta-Info", metaStr) + .header("Pay-TenantId",tenantId()) .body(body); } @@ -479,10 +472,9 @@ public class WechatMarketingFavorApi extends AbstractApi { body.put("notify_url", notifyUrl); body.put("switch", true); URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)) - .queryParam("pay_tenantId", this.tenantId()) .build() .toUri(); - return post(uri, body); + return post(uri, body,tenantId()); } } diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayApi.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayApi.java index 4765539..3ea9054 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayApi.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayApi.java @@ -1,12 +1,14 @@ package cn.felord.payment.wechat.v3; -import cn.felord.payment.PayException; import cn.felord.payment.wechat.enumeration.WeChatServer; import cn.felord.payment.wechat.WechatPayProperties; import cn.felord.payment.wechat.enumeration.WechatPayV3Type; import cn.felord.payment.wechat.v3.model.PayParams; +import cn.felord.payment.wechat.v3.model.TransactionQueryParams; import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.http.RequestEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.util.UriComponentsBuilder; import java.net.URI; @@ -19,6 +21,12 @@ import java.net.URI; */ public class WechatPayApi extends AbstractApi { + /** + * Instantiates a new Wechat pay api. + * + * @param wechatPayClient the wechat pay client + * @param tenantId the tenant id + */ public WechatPayApi(WechatPayClient wechatPayClient, String tenantId) { super(wechatPayClient, tenantId); } @@ -29,10 +37,10 @@ public class WechatPayApi extends AbstractApi { * @param payParams the pay params * @return the wechat response entity */ - public WechatResponseEntity app(PayParams payParams) { + public WechatResponseEntity appPay(PayParams payParams) { WechatResponseEntity wechatResponseEntity = new WechatResponseEntity<>(); this.client().withType(WechatPayV3Type.APP, payParams) - .function(this::appPayFunction) + .function(this::payFunction) .consumer(wechatResponseEntity::convert) .request(); return wechatResponseEntity; @@ -44,23 +52,97 @@ public class WechatPayApi extends AbstractApi { * @param payParams the pay params * @return wechat response entity */ - public WechatResponseEntity js(PayParams payParams) { + public WechatResponseEntity jsPay(PayParams payParams) { WechatResponseEntity wechatResponseEntity = new WechatResponseEntity<>(); this.client().withType(WechatPayV3Type.JSAPI, payParams) - .function(this::appPayFunction) + .function(this::payFunction) .consumer(wechatResponseEntity::convert) .request(); return wechatResponseEntity; } - private RequestEntity appPayFunction(WechatPayV3Type type, PayParams payParams) { + /** + * Native下单API + * + * @param payParams the pay params + * @return wechat response entity + */ + public WechatResponseEntity nativePay(PayParams payParams) { + WechatResponseEntity wechatResponseEntity = new WechatResponseEntity<>(); + this.client().withType(WechatPayV3Type.NATIVE, payParams) + .function(this::payFunction) + .consumer(wechatResponseEntity::convert) + .request(); + return wechatResponseEntity; + } + + /** + * H5下单API + * + * @param payParams the pay params + * @return wechat response entity + */ + public WechatResponseEntity h5Pay(PayParams payParams) { + WechatResponseEntity wechatResponseEntity = new WechatResponseEntity<>(); + this.client().withType(WechatPayV3Type.MWEB, payParams) + .function(this::payFunction) + .consumer(wechatResponseEntity::convert) + .request(); + return wechatResponseEntity; + } + + private RequestEntity payFunction(WechatPayV3Type type, PayParams payParams) { WechatPayProperties.V3 v3 = this.container().getWechatMeta(tenantId()).getV3(); payParams.setAppid(v3.getAppId()); payParams.setMchid(v3.getMchId()); URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)) - .queryParam("pay_tenantId", this.tenantId()) .build() .toUri(); - return post(uri, payParams); + return post(uri, payParams,tenantId()); } + + /** + * 微信支付订单号查询API + * + * @param params the params + * @return the wechat response entity + */ + public WechatResponseEntity queryTransactionById(TransactionQueryParams params) { + WechatResponseEntity wechatResponseEntity = new WechatResponseEntity<>(); + this.client().withType(WechatPayV3Type.TRANSACTION_TRANSACTION_ID, params) + .function(this::queryTransactionFunction) + .consumer(wechatResponseEntity::convert) + .request(); + return wechatResponseEntity; + } + + /** + * 商户订单号查询API + * + * @param params the params + * @return the wechat response entity + */ + public WechatResponseEntity queryTransactionByOutTradeNo(TransactionQueryParams params) { + WechatResponseEntity wechatResponseEntity = new WechatResponseEntity<>(); + this.client().withType(WechatPayV3Type.TRANSACTION_OUT_TRADE_NO, params) + .function(this::queryTransactionFunction) + .consumer(wechatResponseEntity::convert) + .request(); + return wechatResponseEntity; + } + + private RequestEntity queryTransactionFunction(WechatPayV3Type type, TransactionQueryParams params) { + WechatPayProperties.V3 v3 = this.container().getWechatMeta(tenantId()).getV3(); + + MultiValueMap queryParams = new LinkedMultiValueMap<>(); + queryParams.add("mchid", params.getMchId()); + + URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)) + .queryParams(queryParams) + .build() + .expand(params.getTransactionIdOrOutTradeNo()) + .toUri(); + return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); + } + } diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java index 0f41c16..f040331 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java @@ -158,9 +158,8 @@ public class WechatPayClient { if (WechatPayV3Type.MARKETING_IMAGE_UPLOAD.pattern().contains(canonicalUrl)) { body = Objects.requireNonNull(headers.get("Meta-Info")).get(0); } - MultiValueMap queryParams = uri.getQueryParams(); - String tenantId = queryParams.getFirst("pay_tenantId"); - Assert.notNull(tenantId, "tenantId is required"); + + String tenantId = Objects.requireNonNull(headers.get("Pay-TenantId")).get(0); String authorization = signatureProvider.requestSign(tenantId,httpMethod.name(), canonicalUrl, body); HttpHeaders httpHeaders = new HttpHeaders(); @@ -172,7 +171,8 @@ public class WechatPayClient { } httpHeaders.add("Authorization", authorization); httpHeaders.add("User-Agent", "X-Pay-Service"); - + httpHeaders.remove("Meta-Info"); + httpHeaders.remove("Pay-TenantId"); return requestEntity.headers(httpHeaders); } diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/PayParams.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/PayParams.java index 76fc7bc..d92025a 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/PayParams.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/PayParams.java @@ -43,8 +43,17 @@ public class PayParams { * 支付金额 */ private Amount amount; - + /** + * 支付者 JSAPI/小程序下单 必传 + */ + private Payer payer; + /** + * 优惠功能 + */ private Detail detail; + /** + * 场景信息 + */ private SceneInfo sceneInfo; diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/TransactionQueryParams.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/TransactionQueryParams.java new file mode 100644 index 0000000..15c1eaa --- /dev/null +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/TransactionQueryParams.java @@ -0,0 +1,13 @@ +package cn.felord.payment.wechat.v3.model; + +import lombok.Data; + +/** + * @author Dax + * @since 17:42 + */ +@Data +public class TransactionQueryParams { +private String mchId; +private String transactionIdOrOutTradeNo; +}