From ea05ff96d6963dc80a1115ae9d8b2bdf356d422e Mon Sep 17 00:00:00 2001 From: xiafang Date: Tue, 8 Dec 2020 14:55:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E8=B4=A6=E5=8D=95=E4=B8=8B=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v3/DownloadHttpMessageConverter.java | 66 +++++++++++++++++++ .../wechat/v3/WechatMarketingFavorApi.java | 40 +++++++---- .../payment/wechat/v3/WechatPayClient.java | 51 +++++++++++--- 3 files changed, 136 insertions(+), 21 deletions(-) create mode 100644 payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/DownloadHttpMessageConverter.java diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/DownloadHttpMessageConverter.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/DownloadHttpMessageConverter.java new file mode 100644 index 0000000..a5b52b6 --- /dev/null +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/DownloadHttpMessageConverter.java @@ -0,0 +1,66 @@ +package cn.felord.payment.wechat.v3; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.*; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.MimeType; +import org.springframework.util.StreamUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +/** + * @author Dax + * @since 12:46 + */ +public class DownloadHttpMessageConverter extends AbstractHttpMessageConverter { + + public DownloadHttpMessageConverter() { + } + + public DownloadHttpMessageConverter(MediaType supportedMediaType) { + super(supportedMediaType); + } + + @Override + protected boolean supports(Class clazz) { + return clazz.isAssignableFrom(ObjectNode.class); + } + + @Override + protected ObjectNode readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { + Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType()); + String s = StreamUtils.copyToString(inputMessage.getBody(), charset); + return new ObjectNode(JsonNodeFactory.withExactBigDecimals(true)).put("result", s); + } + + @Override + protected void writeInternal(ObjectNode jsonNodes, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { + + } + + private Charset getContentTypeCharset(@Nullable MediaType contentType) { + if (contentType != null && contentType.getCharset() != null) { + return contentType.getCharset(); + } + else if (contentType != null && contentType.isCompatibleWith(MediaType.APPLICATION_JSON)) { + // Matching to AbstractJackson2HttpMessageConverter#DEFAULT_CHARSET + return StandardCharsets.UTF_8; + } + else { + Charset charset = getDefaultCharset(); + Assert.state(charset != null, "No default charset"); + return charset; + } + } +} 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 0ff9ac6..df610f9 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 @@ -39,7 +39,7 @@ public class WechatMarketingFavorApi extends AbstractApi { public WechatMarketingFavorApi(WechatPayClient wechatPayClient, String tenantId) { - super(wechatPayClient,tenantId); + super(wechatPayClient, tenantId); } @@ -66,7 +66,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .build() .toUri(); params.setBelongMerchant(mchId); - return post(uri, params,tenantId()); + return post(uri, params, tenantId()); } /** @@ -111,7 +111,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .expand(params.getOpenid()) .toUri(); params.setOpenid(null); - return post(uri, params,tenantId()); + return post(uri, params, tenantId()); } /** @@ -154,7 +154,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .build() .expand(stockId) .toUri(); - return post(uri, body,tenantId()); + return post(uri, body, tenantId()); } /** @@ -211,7 +211,7 @@ public class WechatMarketingFavorApi extends AbstractApi { URI uri = uriComponents .toUri(); - return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); + return RequestEntity.get(uri).header("Pay-TenantId", tenantId()).build(); } /** @@ -242,7 +242,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .build() .expand(stockId) .toUri(); - return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); + return RequestEntity.get(uri).header("Pay-TenantId", tenantId()).build(); } @@ -279,7 +279,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .build() .expand(pathParams) .toUri(); - return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); + return RequestEntity.get(uri).header("Pay-TenantId", tenantId()).build(); } @@ -364,7 +364,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .build() .expand(params.getOpenId()) .toUri(); - return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); + return RequestEntity.get(uri).header("Pay-TenantId", tenantId()).build(); } @@ -380,7 +380,8 @@ public class WechatMarketingFavorApi extends AbstractApi { .function(this::downloadFlowFunction) .consumer(wechatResponseEntity::convert) .request(); - + String csv = billDownload(wechatResponseEntity.getBody().get("url").asText()); + wechatResponseEntity.getBody().put("csv", csv); return wechatResponseEntity; } @@ -396,6 +397,8 @@ public class WechatMarketingFavorApi extends AbstractApi { .function(this::downloadFlowFunction) .consumer(wechatResponseEntity::convert) .request(); + String csv = billDownload(wechatResponseEntity.getBody().get("url").asText()); + wechatResponseEntity.getBody().put("csv", csv); return wechatResponseEntity; } @@ -404,7 +407,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .build() .expand(stockId) .toUri(); - return RequestEntity.get(uri).header("Pay-TenantId",tenantId()).build(); + return RequestEntity.get(uri).header("Pay-TenantId", tenantId()).build(); } /** @@ -444,7 +447,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()) + .header("Pay-TenantId", tenantId()) .body(body); } @@ -474,9 +477,22 @@ public class WechatMarketingFavorApi extends AbstractApi { URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)) .build() .toUri(); - return post(uri, body,tenantId()); + return post(uri, body, tenantId()); } + public String billDownload(String link) { + return this.client().withType(WechatPayV3Type.FILE_DOWNLOAD, link) + .function(this::billDownloadFunction) + .download(); + } + + + private RequestEntity billDownloadFunction(WechatPayV3Type type, String link) { + URI uri = UriComponentsBuilder.fromHttpUrl(link) + .build() + .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 f040331..8b1c4cb 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 @@ -11,6 +11,7 @@ import org.springframework.http.*; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter; import org.springframework.util.Assert; +import org.springframework.util.MimeType; import org.springframework.util.MultiValueMap; import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.RestOperations; @@ -54,7 +55,7 @@ public class WechatPayClient { * @return the executor */ public Executor withType(WechatPayV3Type wechatPayV3Type, M m) { - return new Executor<>(wechatPayV3Type, m, this.signatureProvider,this.restOperations); + return new Executor<>(wechatPayV3Type, m, this.signatureProvider, this.restOperations); } @@ -88,10 +89,11 @@ public class WechatPayClient { * @param wechatPayV3Type the v 3 pay type * @param model the model * @param signatureProvider the signature provider + * @param restOperations the rest operations */ - Executor(WechatPayV3Type wechatPayV3Type, - M model, - SignatureProvider signatureProvider, RestOperations restOperations) { + Executor(WechatPayV3Type wechatPayV3Type, + M model, + SignatureProvider signatureProvider, RestOperations restOperations) { this.wechatPayV3Type = wechatPayV3Type; this.model = model; this.signatureProvider = signatureProvider; @@ -124,7 +126,6 @@ public class WechatPayClient { /** * Request. */ - @SneakyThrows public void request() { RequestEntity requestEntity = this.requestEntityBiFunction.apply(this.wechatPayV3Type, this.model); WechatRequestEntity wechatRequestEntity = WechatRequestEntity.of(requestEntity, this.responseBodyConsumer); @@ -132,6 +133,18 @@ public class WechatPayClient { } + /** + * Download string. + * + * @return the string + */ + public String download() { + RequestEntity requestEntity = this.requestEntityBiFunction.apply(this.wechatPayV3Type, this.model); + WechatRequestEntity wechatRequestEntity = WechatRequestEntity.of(requestEntity, this.responseBodyConsumer); + return this.doDownload(this.header(wechatRequestEntity)); + } + + /** * 构造私钥签名. * @@ -143,7 +156,7 @@ public class WechatPayClient { UriComponents uri = UriComponentsBuilder.fromUri(requestEntity.getUrl()).build(); String canonicalUrl = uri.getPath(); String encodedQuery = uri.getQuery(); - Assert.notNull(canonicalUrl,"canonicalUrl is required"); + Assert.notNull(canonicalUrl, "canonicalUrl is required"); if (encodedQuery != null) { canonicalUrl += "?" + encodedQuery; } @@ -156,11 +169,11 @@ public class WechatPayClient { T entityBody = requestEntity.getBody(); String body = requestEntity.hasBody() ? Objects.requireNonNull(entityBody).toString() : ""; if (WechatPayV3Type.MARKETING_IMAGE_UPLOAD.pattern().contains(canonicalUrl)) { - body = Objects.requireNonNull(headers.get("Meta-Info")).get(0); + body = Objects.requireNonNull(headers.get("Meta-Info")).get(0); } - String tenantId = Objects.requireNonNull(headers.get("Pay-TenantId")).get(0); - String authorization = signatureProvider.requestSign(tenantId,httpMethod.name(), canonicalUrl, body); + String tenantId = Objects.requireNonNull(headers.get("Pay-TenantId")).get(0); + String authorization = signatureProvider.requestSign(tenantId, httpMethod.name(), canonicalUrl, body); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.addAll(headers); @@ -215,8 +228,27 @@ public class WechatPayClient { } } + private String doDownload(WechatRequestEntity requestEntity) { + + ResponseEntity responseEntity = restOperations.exchange(requestEntity, String.class); + + String body = responseEntity.getBody(); + if (!responseEntity.getStatusCode().is2xxSuccessful()) { + throw new PayException("wechat pay server error,result : " + body); + } + if (Objects.isNull(body)) { + throw new PayException("cant obtain wechat response body"); + } + return body; + } + } + /** + * Signature provider signature provider. + * + * @return the signature provider + */ public SignatureProvider signatureProvider() { return signatureProvider; } @@ -229,6 +261,7 @@ public class WechatPayClient { messageConverters.removeIf(httpMessageConverter -> httpMessageConverter instanceof AllEncompassingFormHttpMessageConverter); messageConverters.add(new ExtensionFormHttpMessageConverter()); +// messageConverters.add(new DownloadHttpMessageConverter(MediaType.asMediaType(MimeType.valueOf("text/plain;charset=utf-8")))); restTemplate.setMessageConverters(messageConverters); this.restOperations = restTemplate; }