diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/controller/app/miniapp/MiniappPayAppController.java b/module-wechat/src/main/java/ink/wgink/module/wechat/controller/app/miniapp/MiniappPayAppController.java index 6fc0d4c7..075e5d20 100644 --- a/module-wechat/src/main/java/ink/wgink/module/wechat/controller/app/miniapp/MiniappPayAppController.java +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/controller/app/miniapp/MiniappPayAppController.java @@ -7,6 +7,8 @@ import ink.wgink.module.wechat.service.pay.v3.jsapi.IJsapiService; import ink.wgink.pojo.result.ErrorResult; import ink.wgink.util.OrderUtil; import io.swagger.annotations.*; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestHeader; @@ -41,6 +43,7 @@ public class MiniappPayAppController { PayPlaceOrder payPlaceOrder = new PayPlaceOrder(); payPlaceOrder.setDescription("测试商品"); payPlaceOrder.setOutTradeNo(atomicOrder); + payPlaceOrder.setTimeExpire(DateTime.now().plusMinutes(1).toString(DateTimeFormat.forPattern(ISystemConstant.DATE_YYYY_MM_DD_T_HH_MM_SS_TIMEZONE))); payPlaceOrder.setNotifyUrl("https://www.wgink.ink/study/wechat/pay/notice"); PayPlaceOrder.Amount amount = new PayPlaceOrder.Amount(); @@ -48,7 +51,7 @@ public class MiniappPayAppController { payPlaceOrder.setAmount(amount); PayPlaceOrder.Payer payer = new PayPlaceOrder.Payer(); - payer.setOpenid(""); + payer.setOpenid("oZBi65WehgT4W9ZxztEuRgp0QKvU"); payPlaceOrder.setPayer(payer); return jsapiService.placeOrder(payPlaceOrder); diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/request/pay/v3/AbstractPayRequest.java b/module-wechat/src/main/java/ink/wgink/module/wechat/request/pay/v3/AbstractPayRequest.java index e7d98b33..72e945ce 100644 --- a/module-wechat/src/main/java/ink/wgink/module/wechat/request/pay/v3/AbstractPayRequest.java +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/request/pay/v3/AbstractPayRequest.java @@ -1,9 +1,10 @@ package ink.wgink.module.wechat.request.pay.v3; -import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; import ink.wgink.exceptions.base.SystemException; import ink.wgink.module.wechat.enums.PayAuthorizationTypeEnum; -import ink.wgink.module.wechat.pojo.pay.v3.PayErrorResponse; import ink.wgink.module.wechat.utils.pay.PaySignAuthorizationUtil; import ink.wgink.properties.wechat.pay.v3.PayProperties; import ink.wgink.util.UUIDUtil; @@ -13,10 +14,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.FileSystemResource; import org.springframework.http.*; -import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; import javax.crypto.Cipher; @@ -26,11 +30,14 @@ import javax.crypto.spec.SecretKeySpec; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.charset.Charset; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.Base64; +import java.util.List; /** * @ClassName: PayRequestUtil @@ -39,7 +46,7 @@ import java.util.Base64; * @Date: 2021/8/18 9:41 下午 * @Version: 1.0 */ -public abstract class AbstractPayRequest { +public abstract class AbstractPayRequest { protected static final Logger LOG = LoggerFactory.getLogger(AbstractPayRequest.class); public static final String PAY_SERIAL = "Wechatpay-Serial"; @@ -47,26 +54,28 @@ public abstract class AbstractPayRequest { private RestTemplate restTemplate; public AbstractPayRequest() { - SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory(); - simpleClientHttpRequestFactory.setConnectTimeout(20 * 1000); - simpleClientHttpRequestFactory.setReadTimeout(60 * 1000); - this.restTemplate = new RestTemplate(simpleClientHttpRequestFactory); + HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(); + httpComponentsClientHttpRequestFactory.setConnectTimeout(20 * 1000); + httpComponentsClientHttpRequestFactory.setReadTimeout(60 * 1000); + this.restTemplate = new RestTemplate(httpComponentsClientHttpRequestFactory); } /** * bodys实体转json字符串 * - * @param requestBody + * @param requestBean * @return */ - public abstract String bodyJsonString(RequestBody requestBody); + public abstract BodyType bodyJson(RequestBean requestBean); /** * 响应结果处理 * * @param responseEntity */ - public abstract Response response(ResponseEntity responseEntity); + public abstract ResponseType response(ResponseEntity responseEntity); + + public abstract void error(HttpClientErrorException e); /** * GET 请求 @@ -75,11 +84,18 @@ public abstract class AbstractPayRequest { * @param authorization 授权信息 * @param serialNumber 公钥证书序列号 */ - public Response get(String url, String authorization, String serialNumber) { - HttpEntity httpEntity = new HttpEntity(getHttpHeaders(authorization, serialNumber)); - ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); - checkResponseCode(responseEntity); - return response(responseEntity); + public ResponseType get(String url, String authorization, String serialNumber) { + try { + HttpEntity httpEntity = new HttpEntity(getHttpHeaders(authorization, serialNumber)); + ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); + return response(responseEntity); + } catch (Exception e) { + if (e instanceof HttpClientErrorException) { + HttpClientErrorException exception = (HttpClientErrorException) e; + error(exception); + } + throw new SystemException(e.getMessage(), e); + } } /** @@ -90,11 +106,18 @@ public abstract class AbstractPayRequest { * @param serialNumber 公钥证书序列号 * @param jsonBody 请求参数 */ - public Response post(String url, String authorization, String serialNumber, String jsonBody) { - HttpEntity httpEntity = new HttpEntity(jsonBody, getHttpHeaders(authorization, serialNumber)); - ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); - checkResponseCode(responseEntity); - return response(responseEntity); + public ResponseType post(String url, String authorization, String serialNumber, BodyType jsonBody) { + try { + HttpEntity httpEntity = new HttpEntity(jsonBody, getHttpHeaders(authorization, serialNumber)); + ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); + return response(responseEntity); + } catch (Exception e) { + if (e instanceof HttpClientErrorException) { + HttpClientErrorException exception = (HttpClientErrorException) e; + error(exception); + } + throw new SystemException(e.getMessage(), e); + } } /** @@ -105,11 +128,18 @@ public abstract class AbstractPayRequest { * @param serialNumber 公钥证书序列号 * @param jsonBody 请求参数 */ - public Response put(String url, String authorization, String serialNumber, String jsonBody) { - HttpEntity httpEntity = new HttpEntity(jsonBody, getHttpHeaders(authorization, serialNumber)); - ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.PUT, httpEntity, String.class); - checkResponseCode(responseEntity); - return response(responseEntity); + public ResponseType put(String url, String authorization, String serialNumber, BodyType jsonBody) { + try { + HttpEntity httpEntity = new HttpEntity(jsonBody, getHttpHeaders(authorization, serialNumber)); + ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.PUT, httpEntity, String.class); + return response(responseEntity); + } catch (Exception e) { + if (e instanceof HttpClientErrorException) { + HttpClientErrorException exception = (HttpClientErrorException) e; + error(exception); + } + throw new SystemException(e.getMessage(), e); + } } /** @@ -119,11 +149,18 @@ public abstract class AbstractPayRequest { * @param authorization 授权信息 * @param serialNumber 公钥证书序列号 */ - public Response delete(String url, String authorization, String serialNumber) { - HttpEntity httpEntity = new HttpEntity(getHttpHeaders(authorization, serialNumber)); - ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.DELETE, httpEntity, String.class); - checkResponseCode(responseEntity); - return response(responseEntity); + public ResponseType delete(String url, String authorization, String serialNumber) { + try { + HttpEntity httpEntity = new HttpEntity(getHttpHeaders(authorization, serialNumber)); + ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.DELETE, httpEntity, String.class); + return response(responseEntity); + } catch (Exception e) { + if (e instanceof HttpClientErrorException) { + HttpClientErrorException exception = (HttpClientErrorException) e; + error(exception); + } + throw new SystemException(e.getMessage(), e); + } } /** @@ -135,15 +172,22 @@ public abstract class AbstractPayRequest { * @param jsonData 请求参数 * @param uploadFile 上传文件 */ - public Response upload(String url, String authorization, String serialNumber, String jsonData, File uploadFile) { - FileSystemResource fileSystemResource = new FileSystemResource(uploadFile); - MultiValueMap form = new LinkedMultiValueMap<>(); - form.add("file", fileSystemResource); - form.add("meta", jsonData); - HttpEntity> httpEntity = new HttpEntity<>(form, getUploadHeaders(authorization, serialNumber)); - ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); - checkResponseCode(responseEntity); - return response(responseEntity); + public ResponseType upload(String url, String authorization, String serialNumber, String jsonData, File uploadFile) { + try { + FileSystemResource fileSystemResource = new FileSystemResource(uploadFile); + MultiValueMap form = new LinkedMultiValueMap<>(); + form.add("file", fileSystemResource); + form.add("meta", jsonData); + HttpEntity> httpEntity = new HttpEntity<>(form, getUploadHeaders(authorization, serialNumber)); + ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); + return response(responseEntity); + } catch (Exception e) { + if (e instanceof HttpClientErrorException) { + HttpClientErrorException exception = (HttpClientErrorException) e; + error(exception); + } + throw new SystemException(e.getMessage(), e); + } } /** @@ -161,7 +205,7 @@ public abstract class AbstractPayRequest { String randomSubStr = WStringUtil.randomSubStr(UUIDUtil.get32UUID(), 10).toUpperCase(); return PaySignAuthorizationUtil.buildAuthorization(requestMethod, urlSuffix, payProperties.getMchid(), serialNumber, - payProperties.getKeyPath(), jsonBody, randomSubStr, System.currentTimeMillis(), + payProperties.getKeyPath(), jsonBody, randomSubStr, System.currentTimeMillis() / 1000, payAuthorizationTypeEnum.getValue()); } @@ -173,7 +217,7 @@ public abstract class AbstractPayRequest { */ private HttpHeaders getHttpBaseHeaders(String authorization) { HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE); + httpHeaders.add("Accept", MediaType.APPLICATION_JSON_VALUE); httpHeaders.add("Authorization", authorization); return httpHeaders; } @@ -187,10 +231,11 @@ public abstract class AbstractPayRequest { */ private HttpHeaders getHttpHeaders(String authorization, String serialNumber) { HttpHeaders httpHeaders = getHttpBaseHeaders(authorization); - httpHeaders.add("Content-Type", MediaType.APPLICATION_JSON_UTF8_VALUE); + httpHeaders.add("Content-Type", MediaType.APPLICATION_JSON_VALUE); if (!StringUtils.isBlank(serialNumber)) { httpHeaders.add(PAY_SERIAL, serialNumber); } + LOG.debug("header: {}", httpHeaders); return httpHeaders; } @@ -207,21 +252,77 @@ public abstract class AbstractPayRequest { if (!StringUtils.isBlank(serialNumber)) { httpHeaders.add(PAY_SERIAL, serialNumber); } + LOG.debug(httpHeaders.toString()); return httpHeaders; } - /** - * 检查返回状态码 - * - * @param responseEntity - */ - private void checkResponseCode(ResponseEntity responseEntity) { - if (responseEntity.getStatusCode().value() == HttpStatus.OK.value()) { - return; + @Deprecated + private static class HttpMessageCoverBuilder { + + /** + * string 消息转换 + * + * @return + */ + private static StringHttpMessageConverter getStringHttpMessageConverter() { + StringHttpMessageConverter stringConvert = new StringHttpMessageConverter(); + List stringMediaTypes = new ArrayList() {{ + //添加响应数据格式,不匹配会报401 + add(MediaType.TEXT_PLAIN); + add(MediaType.TEXT_HTML); + add(MediaType.APPLICATION_JSON); + add(MediaType.APPLICATION_JSON_UTF8); + }}; + stringConvert.setSupportedMediaTypes(stringMediaTypes); + return stringConvert; + } + + /** + * fastjson 消息转换 + * + * @return + */ + private static FastJsonHttpMessageConverter getFastJsonHttpMessageConverter() { + FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter(); + //2、添加fastjson的配置信息 + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + + SerializerFeature[] serializerFeatures = new SerializerFeature[]{ + // 输出key是包含双引号 +// SerializerFeature.QuoteFieldNames, + // 是否输出为null的字段,若为null 则显示该字段 +// SerializerFeature.WriteMapNullValue, + // 数值字段如果为null,则输出为0 + SerializerFeature.WriteNullNumberAsZero, + // List字段如果为null,输出为[],而非null + SerializerFeature.WriteNullListAsEmpty, + // 字符类型字段如果为null,输出为"",而非null + SerializerFeature.WriteNullStringAsEmpty, + // Boolean字段如果为null,输出为false,而非null + SerializerFeature.WriteNullBooleanAsFalse, + // Date的日期转换器 + SerializerFeature.WriteDateUseDateFormat, + // 循环引用 + SerializerFeature.DisableCircularReferenceDetect, + }; + + fastJsonConfig.setSerializerFeatures(serializerFeatures); + fastJsonConfig.setCharset(Charset.forName("UTF-8")); + fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig); + return fastJsonHttpMessageConverter; + } + + /** + * 返回格式解析 + * + * @return + */ + public static List> getMessageConverts() { + List> messageConverters = new ArrayList<>(); + messageConverters.add(getStringHttpMessageConverter()); + messageConverters.add(getFastJsonHttpMessageConverter()); + return messageConverters; } - LOG.error(responseEntity.getBody()); - PayErrorResponse payErrorResponse = JSONObject.parseObject(responseEntity.getBody(), PayErrorResponse.class); - throw new SystemException(payErrorResponse.getMessage()); } /** diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/request/pay/v3/jsapi/PlaceOrderPayRequestImpl.java b/module-wechat/src/main/java/ink/wgink/module/wechat/request/pay/v3/jsapi/PlaceOrderPayRequestImpl.java index 9186fa85..96a89040 100644 --- a/module-wechat/src/main/java/ink/wgink/module/wechat/request/pay/v3/jsapi/PlaceOrderPayRequestImpl.java +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/request/pay/v3/jsapi/PlaceOrderPayRequestImpl.java @@ -2,10 +2,13 @@ package ink.wgink.module.wechat.request.pay.v3.jsapi; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import ink.wgink.module.wechat.request.pay.v3.AbstractPayRequest; +import ink.wgink.exceptions.base.SystemException; +import ink.wgink.module.wechat.pojo.pay.v3.PayErrorResponse; import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPlaceOrder; import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPrepay; +import ink.wgink.module.wechat.request.pay.v3.AbstractPayRequest; import org.springframework.http.ResponseEntity; +import org.springframework.web.client.HttpClientErrorException; import java.util.List; @@ -16,10 +19,10 @@ import java.util.List; * @Date: 2021/8/19 3:22 下午 * @Version: 1.0 */ -public class PlaceOrderPayRequestImpl extends AbstractPayRequest { +public class PlaceOrderPayRequestImpl extends AbstractPayRequest { @Override - public String bodyJsonString(PayPlaceOrder payPlaceOrder) { + public JSONObject bodyJson(PayPlaceOrder payPlaceOrder) { JSONObject bodyObject = new JSONObject(); bodyObject.put("appid", payPlaceOrder.getAppid()); bodyObject.put("mchid", payPlaceOrder.getMchid()); @@ -40,7 +43,7 @@ public class PlaceOrderPayRequestImpl extends AbstractPayRequest