From ad4de702422ebe048c89659a80c5fc73739f921a Mon Sep 17 00:00:00 2001 From: wanggeng <450292408@qq.com> Date: Sat, 2 Oct 2021 15:01:10 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=94=AF=E4=BB=98=E8=BF=9C?= =?UTF-8?q?=E7=A8=8B=E8=B0=83=E7=94=A8=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rpc/rest/request/RestRemoteRequest.java | 3 +- ...ava => IOfficialAccountRemoteService.java} | 6 +- .../remote/pay/v3/IOrderPayRemoteService.java | 86 +++++++++ .../remote/pay/v3/IPayRemoteService.java | 29 +++ ...cialAccountTemplateMessageServiceImpl.java | 4 +- .../impl/CertificateServiceImpl.java | 39 +++- .../service/pay/v3/impl/IPayServiceImpl.java | 4 +- .../pay/v3/jsapi/impl/JsapiServiceImpl.java | 174 +++++++++++++++++- .../v3/order/impl/OrderCloseServiceImpl.java | 27 ++- .../v3/order/impl/OrderSearchServiceImpl.java | 44 ++++- .../module/wechat/utils/pay/PayAesUtil.java | 65 +++++++ 11 files changed, 459 insertions(+), 22 deletions(-) rename module-wechat/src/main/java/ink/wgink/module/wechat/remote/official/account/{IOfficialAccountTemplateMessageRemoteService.java => IOfficialAccountRemoteService.java} (88%) create mode 100644 module-wechat/src/main/java/ink/wgink/module/wechat/remote/pay/v3/IOrderPayRemoteService.java create mode 100644 module-wechat/src/main/java/ink/wgink/module/wechat/remote/pay/v3/IPayRemoteService.java create mode 100644 module-wechat/src/main/java/ink/wgink/module/wechat/utils/pay/PayAesUtil.java diff --git a/common/src/main/java/ink/wgink/common/rpc/rest/request/RestRemoteRequest.java b/common/src/main/java/ink/wgink/common/rpc/rest/request/RestRemoteRequest.java index 1a8218de..37df2441 100644 --- a/common/src/main/java/ink/wgink/common/rpc/rest/request/RestRemoteRequest.java +++ b/common/src/main/java/ink/wgink/common/rpc/rest/request/RestRemoteRequest.java @@ -198,7 +198,8 @@ public class RestRemoteRequest { * @return */ private String getStringResponse(ResponseEntity responseEntity) { - if (responseEntity.getStatusCode() != HttpStatus.OK) { + if (responseEntity.getStatusCode() != HttpStatus.OK && + responseEntity.getStatusCode() != HttpStatus.NO_CONTENT) { throw new RemoteResponseException("远程调用响应状态码不支持: " + responseEntity.getStatusCode()); } String responseBody = responseEntity.getBody(); diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/remote/official/account/IOfficialAccountTemplateMessageRemoteService.java b/module-wechat/src/main/java/ink/wgink/module/wechat/remote/official/account/IOfficialAccountRemoteService.java similarity index 88% rename from module-wechat/src/main/java/ink/wgink/module/wechat/remote/official/account/IOfficialAccountTemplateMessageRemoteService.java rename to module-wechat/src/main/java/ink/wgink/module/wechat/remote/official/account/IOfficialAccountRemoteService.java index b8661447..c4872e1a 100644 --- a/module-wechat/src/main/java/ink/wgink/module/wechat/remote/official/account/IOfficialAccountTemplateMessageRemoteService.java +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/remote/official/account/IOfficialAccountRemoteService.java @@ -9,14 +9,14 @@ import ink.wgink.module.wechat.pojo.vos.official.account.OfficialAccountTemplate import ink.wgink.module.wechat.result.TemplateMessageWechatResult; /** - * @ClassName: ITemplateMessageRemoteService - * @Description: 模板消息 + * @ClassName: IOfficialAccountRemoteService + * @Description: 微信公众号远程调用 * @Author: wanggeng * @Date: 2021/9/30 9:19 上午 * @Version: 1.0 */ @RemoteService -public interface IOfficialAccountTemplateMessageRemoteService { +public interface IOfficialAccountRemoteService { /** * 发送消息模板 diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/remote/pay/v3/IOrderPayRemoteService.java b/module-wechat/src/main/java/ink/wgink/module/wechat/remote/pay/v3/IOrderPayRemoteService.java new file mode 100644 index 00000000..6abf5171 --- /dev/null +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/remote/pay/v3/IOrderPayRemoteService.java @@ -0,0 +1,86 @@ +package ink.wgink.module.wechat.remote.pay.v3; + +import com.alibaba.fastjson.JSONObject; +import ink.wgink.annotation.rpc.rest.RemoteService; +import ink.wgink.annotation.rpc.rest.method.RemoteGetMethod; +import ink.wgink.annotation.rpc.rest.method.RemotePostMethod; +import ink.wgink.annotation.rpc.rest.params.*; +import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPrepay; +import ink.wgink.module.wechat.pojo.pay.v3.order.OrderSearch; + +/** + * @ClassName: IOrderPayRemoteService + * @Description: 订单远程调用 + * @Author: wanggeng + * @Date: 2021/10/2 10:58 上午 + * @Version: 1.0 + */ +@RemoteService +public interface IOrderPayRemoteService { + + /** + * 下单 + * + * @param server + * @param authorization + * @param serialNumber + * @param payPlaceOrder + * @return + */ + @RemotePostMethod("/v3/pay/transactions/jsapi") + PayPrepay placeOrderJsapi(@RemoteServerParams String server, + @RemoteHeaderParams(IPayRemoteService.HEADER_AUTHORIZATION) String authorization, + @RemoteHeaderParams(IPayRemoteService.HEADER_WECHATPAY_SERIAL) String serialNumber, + @RemoteJsonBodyParams JSONObject payPlaceOrder); + + /** + * 关闭订单 + * + * @param server + * @param businessOrderId + * @param authorization + * @param serialNumber + * @param orderClose + */ + @RemotePostMethod("/v3/pay/transactions/out-trade-no/{businessOrderId}/close") + void closePlaceOrder(@RemoteServerParams String server, + @RemotePathParams("businessOrderId") String businessOrderId, + @RemoteHeaderParams(IPayRemoteService.HEADER_AUTHORIZATION) String authorization, + @RemoteHeaderParams(IPayRemoteService.HEADER_WECHATPAY_SERIAL) String serialNumber, + @RemoteJsonBodyParams JSONObject orderClose); + + /** + * 微信支付订单号查询 + * + * @param server + * @param transactionId + * @param authorization + * @param serialNumber + * @param mchid + * @return + */ + @RemoteGetMethod("/v3/pay/transactions/id/{transactionId}") + OrderSearch getOrder(@RemoteServerParams String server, + @RemotePathParams("transactionId") String transactionId, + @RemoteHeaderParams(IPayRemoteService.HEADER_AUTHORIZATION) String authorization, + @RemoteHeaderParams(IPayRemoteService.HEADER_WECHATPAY_SERIAL) String serialNumber, + @RemoteQueryParams("mchid") String mchid); + + /** + * 商户订单号查询 + * + * @param server + * @param businessOrderId + * @param authorization + * @param serialNumber + * @param mchid + * @return + */ + @RemoteGetMethod("/v3/pay/transactions/out-trade-no/{businessOrderId}") + OrderSearch getBusinessOrder(@RemoteServerParams String server, + @RemotePathParams("businessOrderId") String businessOrderId, + @RemoteHeaderParams(IPayRemoteService.HEADER_AUTHORIZATION) String authorization, + @RemoteHeaderParams(IPayRemoteService.HEADER_WECHATPAY_SERIAL) String serialNumber, + @RemoteQueryParams("mchid") String mchid); + +} diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/remote/pay/v3/IPayRemoteService.java b/module-wechat/src/main/java/ink/wgink/module/wechat/remote/pay/v3/IPayRemoteService.java new file mode 100644 index 00000000..33a6a1ff --- /dev/null +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/remote/pay/v3/IPayRemoteService.java @@ -0,0 +1,29 @@ +package ink.wgink.module.wechat.remote.pay.v3; + +import ink.wgink.annotation.rpc.rest.RemoteService; +import ink.wgink.annotation.rpc.rest.method.RemoteGetMethod; +import ink.wgink.annotation.rpc.rest.params.RemoteHeaderParams; +import ink.wgink.annotation.rpc.rest.params.RemoteServerParams; +import ink.wgink.module.wechat.pojo.pay.v3.certificates.Certificate; + +import java.util.List; + +/** + * @ClassName: IPayRemoteService + * @Description: 支付远程调用 + * @Author: wanggeng + * @Date: 2021/10/1 10:03 下午 + * @Version: 1.0 + */ +@RemoteService +public interface IPayRemoteService { + + String HEADER_AUTHORIZATION = "Authorization"; + String HEADER_WECHATPAY_SERIAL = "Wechatpay-Serial"; + + @RemoteGetMethod("/v3/certificates") + List listCertificates(@RemoteServerParams String server, + @RemoteHeaderParams(HEADER_AUTHORIZATION) String authorization, + @RemoteHeaderParams("serialNumber") String serialNumber); + +} diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/service/official/account/impl/OfficialAccountTemplateMessageServiceImpl.java b/module-wechat/src/main/java/ink/wgink/module/wechat/service/official/account/impl/OfficialAccountTemplateMessageServiceImpl.java index bd63af17..eb31e93b 100644 --- a/module-wechat/src/main/java/ink/wgink/module/wechat/service/official/account/impl/OfficialAccountTemplateMessageServiceImpl.java +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/service/official/account/impl/OfficialAccountTemplateMessageServiceImpl.java @@ -5,7 +5,7 @@ import ink.wgink.exceptions.ParamsException; import ink.wgink.exceptions.rpc.RemoteRequestException; import ink.wgink.module.wechat.manager.OfficialAccountAccessTokenManager; import ink.wgink.module.wechat.pojo.vos.official.account.OfficialAccountTemplateMessageSendVO; -import ink.wgink.module.wechat.remote.official.account.IOfficialAccountTemplateMessageRemoteService; +import ink.wgink.module.wechat.remote.official.account.IOfficialAccountRemoteService; import ink.wgink.module.wechat.result.TemplateMessageWechatResult; import ink.wgink.module.wechat.service.official.account.IOfficialAccountTemplateMessageService; import ink.wgink.properties.wechat.official.account.OfficialAccountProperties; @@ -25,7 +25,7 @@ import org.springframework.stereotype.Service; public class OfficialAccountTemplateMessageServiceImpl extends DefaultBaseService implements IOfficialAccountTemplateMessageService { @Autowired - private IOfficialAccountTemplateMessageRemoteService officialAccountTemplateMessageRemoteService; + private IOfficialAccountRemoteService officialAccountTemplateMessageRemoteService; @Autowired private OfficialAccountProperties officialAccountProperties; diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/certificates/impl/CertificateServiceImpl.java b/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/certificates/impl/CertificateServiceImpl.java index f19b606d..d3331ca5 100644 --- a/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/certificates/impl/CertificateServiceImpl.java +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/certificates/impl/CertificateServiceImpl.java @@ -3,11 +3,12 @@ package ink.wgink.module.wechat.service.pay.v3.certificates.impl; import ink.wgink.exceptions.base.SystemException; import ink.wgink.module.wechat.enums.PayAuthorizationTypeEnum; import ink.wgink.module.wechat.pojo.pay.v3.certificates.Certificate; -import ink.wgink.module.wechat.request.pay.v3.AbstractPayRequest; -import ink.wgink.module.wechat.request.pay.v3.certificates.CertificatePayRequestImpl; +import ink.wgink.module.wechat.remote.pay.v3.IPayRemoteService; import ink.wgink.module.wechat.service.pay.BasePayService; import ink.wgink.module.wechat.service.pay.v3.certificates.ICertificateService; +import ink.wgink.module.wechat.utils.pay.PayAesUtil; import ink.wgink.util.date.DateUtil; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestMethod; @@ -27,7 +28,38 @@ import java.util.List; @Service public class CertificateServiceImpl extends BasePayService implements ICertificateService { + @Autowired + private IPayRemoteService payRemoteService; + @Override + public String getNewestPlatformCertificate() throws Exception { + String urlSuffix = "/v3/certificates"; + + LOG.debug("获得证书序列号"); + String serialNumber = getSerialNumber(); + String authorization = getAuthorization(RequestMethod.GET, urlSuffix, serialNumber, payProperties, "", PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048); + List certificates = payRemoteService.listCertificates(getPayBaseUrl(), authorization, serialNumber); + + LOG.debug("获取最新的平台证书"); + Certificate newestCertificate = certificates.get(certificates.size() - 1); + LOG.debug("解析密文"); + PayAesUtil aesUtil = new PayAesUtil(payProperties.getApiV3Secretkey().getBytes(StandardCharsets.UTF_8)); + Certificate.EncryptCertificate encryptCertificate = newestCertificate.getEncryptCertificate(); + String ciphertext = aesUtil.decryptToString(encryptCertificate.getAssociatedData().getBytes(StandardCharsets.UTF_8), encryptCertificate.getNonce().getBytes(StandardCharsets.UTF_8), encryptCertificate.getCiphertext()); + String certificateFilePath = payProperties.getCertificatePath() + File.separator + DateUtil.getDays()+ "_wxp_pub.pem"; + LOG.debug("新证书文件路径:{}", certificateFilePath); + try (FileWriter fileWriter = new FileWriter(certificateFilePath)) { + fileWriter.write(ciphertext); + fileWriter.flush(); + } catch (IOException e) { + LOG.error(e.getMessage(), e); + throw new SystemException("证书生成异常"); + } + LOG.debug("保存新平台证书成功"); + return certificateFilePath; + } + + /** public String getNewestPlatformCertificate() throws Exception { String urlSuffix = "/v3/certificates"; String url = getPayBaseUrl() + urlSuffix; @@ -37,6 +69,7 @@ public class CertificateServiceImpl extends BasePayService implements ICertifica CertificatePayRequestImpl certificatesPayRequest = new CertificatePayRequestImpl(); String authorization = getAuthorization(RequestMethod.GET, urlSuffix, serialNumber, payProperties, "", PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048); List certificates = certificatesPayRequest.get(url, authorization, serialNumber); + LOG.debug("获取最新的平台证书"); Certificate newestCertificate = certificates.get(certificates.size() - 1); LOG.debug("解析密文"); @@ -55,4 +88,6 @@ public class CertificateServiceImpl extends BasePayService implements ICertifica LOG.debug("保存新平台证书成功"); return certificateFilePath; } + **/ + } diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/impl/IPayServiceImpl.java b/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/impl/IPayServiceImpl.java index cd6d3f53..2c458fae 100644 --- a/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/impl/IPayServiceImpl.java +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/impl/IPayServiceImpl.java @@ -8,9 +8,9 @@ import ink.wgink.module.wechat.manager.pay.v3.PayManager; import ink.wgink.module.wechat.pojo.pay.v3.PayErrorResponse; import ink.wgink.module.wechat.pojo.pay.v3.PayNotice; import ink.wgink.module.wechat.pojo.pay.v3.PayNoticeCiphertext; -import ink.wgink.module.wechat.request.pay.v3.AbstractPayRequest; import ink.wgink.module.wechat.service.pay.v3.IPayNoticeService; import ink.wgink.module.wechat.service.pay.v3.IPayService; +import ink.wgink.module.wechat.utils.pay.PayAesUtil; import ink.wgink.module.wechat.utils.pay.PayVerifyUtil; import ink.wgink.properties.wechat.pay.v3.PayProperties; import org.apache.commons.lang3.StringUtils; @@ -59,7 +59,7 @@ public class IPayServiceImpl extends DefaultBaseService implements IPayService { LOG.debug("解密内容"); PayNotice.Resource resource = payNotice.getResource(); - AbstractPayRequest.AesUtil aesUtil = new AbstractPayRequest.AesUtil(payProperties.getApiV3Secretkey().getBytes(StandardCharsets.UTF_8)); + PayAesUtil aesUtil = new PayAesUtil(payProperties.getApiV3Secretkey().getBytes(StandardCharsets.UTF_8)); String payNoticeCiphertextJsonString = aesUtil.decryptToString(resource.getAssociated_data().getBytes(StandardCharsets.UTF_8), resource.getNonce().getBytes(StandardCharsets.UTF_8), resource.getCiphertext()); PayNoticeCiphertext payNoticeCiphertext = JSONObject.parseObject(payNoticeCiphertextJsonString, PayNoticeCiphertext.class); payNoticeService.handle(payNoticeCiphertext); diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/jsapi/impl/JsapiServiceImpl.java b/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/jsapi/impl/JsapiServiceImpl.java index e33c850d..ad99a1be 100644 --- a/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/jsapi/impl/JsapiServiceImpl.java +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/jsapi/impl/JsapiServiceImpl.java @@ -1,11 +1,12 @@ package ink.wgink.module.wechat.service.pay.v3.jsapi.impl; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import ink.wgink.module.wechat.enums.PayAuthorizationTypeEnum; import ink.wgink.module.wechat.pojo.pay.v3.PaySign; 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.jsapi.PlaceOrderPayRequestImpl; +import ink.wgink.module.wechat.remote.pay.v3.IOrderPayRemoteService; import ink.wgink.module.wechat.service.pay.BasePayService; import ink.wgink.module.wechat.service.pay.v3.jsapi.IJsapiService; import ink.wgink.module.wechat.utils.pay.PayPrivateKeyUtil; @@ -17,6 +18,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestMethod; +import java.util.List; + /** * @ClassName: JsapiServiceImpl * @Description: Jsapi业务 @@ -30,8 +33,41 @@ public class JsapiServiceImpl extends BasePayService implements IJsapiService { @Autowired private MiniappProperties miniappProperties; + @Autowired + private IOrderPayRemoteService orderPayRemoteService; @Override + public PaySign placeOrder(PayPlaceOrder payPlaceOrder) throws Exception { + payPlaceOrder.setAppid(miniappProperties.getAppKey()); + payPlaceOrder.setMchid(payProperties.getMchid()); + BeanPropertyCheckUtil.checkField(payPlaceOrder); + String urlSuffix = "/v3/pay/transactions/jsapi"; + + LOG.debug("获得证书序列号"); + String serialNumber = getSerialNumber(); + + LOG.debug("调用微信支付,发起预支付"); + JSONObject body = getPlaceOrderJsonObject(payPlaceOrder); + String authorization = getAuthorization(RequestMethod.POST, urlSuffix, serialNumber, payProperties, body.toString(), PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048); + + LOG.debug("请求获得结果"); + PayPrepay payPrepay = orderPayRemoteService.placeOrderJsapi(getPayBaseUrl(), authorization, serialNumber, body); + + LOG.debug("生成返回结果"); + long timestamp = System.currentTimeMillis() / 1000; + String nonceStr = WStringUtil.randomSubStr(UUIDUtil.get32UUID(), 10).toUpperCase(); + + PaySign paySign = new PaySign(); + paySign.setAppId(miniappProperties.getAppKey()); + paySign.setPrepayId(payPrepay.getPrepayId()); + paySign.setNonceStr(nonceStr); + paySign.setTimestamp(String.valueOf(timestamp)); + paySign.setPaySign(getPaySign(timestamp, nonceStr, payPrepay.getPrepayId())); + return paySign; + } + + /** + * 没问题会删除` public PaySign placeOrder(PayPlaceOrder payPlaceOrder) throws Exception { payPlaceOrder.setAppid(miniappProperties.getAppKey()); payPlaceOrder.setMchid(payProperties.getMchid()); @@ -44,7 +80,7 @@ public class JsapiServiceImpl extends BasePayService implements IJsapiService { LOG.debug("调用微信支付,发起预支付"); PlaceOrderPayRequestImpl placeOrderPayRequest = new PlaceOrderPayRequestImpl(); - JSONObject body = placeOrderPayRequest.bodyJson(payPlaceOrder); + JSONObject body = getPlaceOrderJsonObject(payPlaceOrder); String authorization = getAuthorization(RequestMethod.POST, urlSuffix, serialNumber, payProperties, body.toString(), PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048); LOG.debug("请求获得结果"); @@ -62,6 +98,7 @@ public class JsapiServiceImpl extends BasePayService implements IJsapiService { paySign.setPaySign(getPaySign(timestamp, nonceStr, payPrepay.getPrepayId())); return paySign; } + **/ /** * 获得小程序签名 @@ -83,4 +120,137 @@ public class JsapiServiceImpl extends BasePayService implements IJsapiService { return PayPrivateKeyUtil.encryptByPrivateKey(signBS.toString(), key); } + /** + * 获取 + * @param payPlaceOrder + * @return + */ + private JSONObject getPlaceOrderJsonObject(PayPlaceOrder payPlaceOrder) { + JSONObject bodyObject = new JSONObject(); + bodyObject.put("appid", payPlaceOrder.getAppid()); + bodyObject.put("mchid", payPlaceOrder.getMchid()); + bodyObject.put("description", payPlaceOrder.getDescription()); + bodyObject.put("out_trade_no", payPlaceOrder.getOutTradeNo()); + bodyObject.put("time_expire", payPlaceOrder.getTimeExpire()); + bodyObject.put("attach", payPlaceOrder.getAttach()); + bodyObject.put("notify_url", payPlaceOrder.getNotifyUrl()); + bodyObject.put("goods_tag", payPlaceOrder.getGoodsTag()); + bodyObject.put("amount", getAmountJsonObject(payPlaceOrder.getAmount())); + bodyObject.put("payer", getPayer(payPlaceOrder.getPayer())); + if (payPlaceOrder.getDetail() != null) { + bodyObject.put("detail", getDetail(payPlaceOrder.getDetail())); + } + if (payPlaceOrder.getSceneInfo() != null) { + bodyObject.put("scene_info", getSceneInfo(payPlaceOrder.getSceneInfo())); + } + if (payPlaceOrder.getSettleInfo() != null) { + bodyObject.put("settle_info", getSettleInfo(payPlaceOrder.getSettleInfo())); + } + return bodyObject; + } + + /** + * 订单金额 + * + * @param amount + * @return + */ + private JSONObject getAmountJsonObject(PayPlaceOrder.Amount amount) { + JSONObject amountJsonObject = new JSONObject(); + amountJsonObject.put("total", amount.getTotal()); + amountJsonObject.put("currency", amount.getCurrency()); + return amountJsonObject; + } + + /** + * 支付者 + * + * @param payer + * @return + */ + private JSONObject getPayer(PayPlaceOrder.Payer payer) { + JSONObject payerJsonObject = new JSONObject(); + payerJsonObject.put("openid", payer.getOpenid()); + return payerJsonObject; + } + + /** + * 优惠功能 + * + * @param detail + * @return + */ + private JSONObject getDetail(PayPlaceOrder.Detail detail) { + JSONObject detailJsonObject = new JSONObject(); + detailJsonObject.put("cost_price", detail.getCostPrice()); + detailJsonObject.put("invoice_id", detail.getInvoiceId()); + if (detail.getGoodsDetail() != null || !detail.getGoodsDetail().isEmpty()) { + detailJsonObject.put("goods_detail", listGoodsDetail(detail.getGoodsDetail())); + } + return detailJsonObject; + } + + /** + * 商品列表 + * + * @param goodsList + * @return + */ + private JSONArray listGoodsDetail(List goodsList) { + JSONArray goodsDetailJsonArray = new JSONArray(); + for (PayPlaceOrder.Detail.Goods goods : goodsList) { + JSONObject goodsJsonObject = new JSONObject(); + goodsJsonObject.put("merchant_goods_id", goods.getMerchantGoodsId()); + goodsJsonObject.put("wechatpay_goods_id", goods.getWechatpayGoodsId()); + goodsJsonObject.put("goods_name", goods.getGoodsName()); + goodsJsonObject.put("quantity", goods.getQuantity()); + goodsJsonObject.put("unit_price", goods.getUnitPrice()); + goodsDetailJsonArray.add(goodsJsonObject); + } + return goodsDetailJsonArray; + } + + /** + * 场景信息 + * + * @param sceneInfo + * @return + */ + private JSONObject getSceneInfo(PayPlaceOrder.SceneInfo sceneInfo) { + JSONObject sceneInfoJsonObject = new JSONObject(); + sceneInfoJsonObject.put("payer_client_ip", sceneInfo.getPayerClientIp()); + sceneInfoJsonObject.put("device_id", sceneInfo.getDeviceId()); + if (sceneInfo.getStoreInfo() != null) { + sceneInfoJsonObject.put("store_info", getStoreInfo(sceneInfo.getStoreInfo())); + } + return sceneInfoJsonObject; + } + + /** + * 商户门店信息 + * + * @param storeInfo + * @return + */ + private JSONObject getStoreInfo(PayPlaceOrder.SceneInfo.StoreInfo storeInfo) { + JSONObject storeInfoJsonObject = new JSONObject(); + storeInfoJsonObject.put("id", storeInfo.getId()); + storeInfoJsonObject.put("name", storeInfo.getName()); + storeInfoJsonObject.put("area_code", storeInfo.getAreaCode()); + storeInfoJsonObject.put("address", storeInfo.getAddress()); + return storeInfoJsonObject; + } + + /** + * 是否指定分账 + * + * @param settleInfo + * @return + */ + private JSONObject getSettleInfo(PayPlaceOrder.SettleInfo settleInfo) { + JSONObject settleJsonObject = new JSONObject(); + settleJsonObject.put("profit_sharing", settleInfo.getProfitSharing()); + return settleJsonObject; + } + } diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/order/impl/OrderCloseServiceImpl.java b/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/order/impl/OrderCloseServiceImpl.java index 44a347c1..a9e127a4 100644 --- a/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/order/impl/OrderCloseServiceImpl.java +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/order/impl/OrderCloseServiceImpl.java @@ -1,10 +1,11 @@ package ink.wgink.module.wechat.service.pay.v3.order.impl; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import ink.wgink.exceptions.ParamsException; import ink.wgink.module.wechat.enums.PayAuthorizationTypeEnum; import ink.wgink.module.wechat.pojo.pay.v3.order.OrderClose; -import ink.wgink.module.wechat.request.pay.v3.order.OrderClosePayRequestImpl; +import ink.wgink.module.wechat.remote.pay.v3.IOrderPayRemoteService; import ink.wgink.module.wechat.service.pay.BasePayService; import ink.wgink.module.wechat.service.pay.v3.order.IOrderCloseService; import ink.wgink.properties.wechat.pay.v3.PayProperties; @@ -25,6 +26,8 @@ public class OrderCloseServiceImpl extends BasePayService implements IOrderClose @Autowired private PayProperties payProperties; + @Autowired + private IOrderPayRemoteService orderPayRemoteService; @Override public void closeOrder(String businessOrderId) throws Exception { @@ -34,6 +37,27 @@ public class OrderCloseServiceImpl extends BasePayService implements IOrderClose OrderClose orderClose = new OrderClose(); orderClose.setMchid(payProperties.getMchid()); + String urlSuffix = "/v3/pay/transactions/out-trade-no/" + businessOrderId + "/close"; + String serialNumber = getSerialNumber(); + JSONObject body = bodyJson(orderClose); + String authorization = getAuthorization(RequestMethod.POST, urlSuffix, serialNumber, payProperties, body.toString(), PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048); + orderPayRemoteService.closePlaceOrder(getPayBaseUrl(), businessOrderId, authorization, serialNumber, body); + } + + private JSONObject bodyJson(OrderClose orderClose) { + JSONObject bodyJsonObject = new JSONObject(); + bodyJsonObject.put("mchid", orderClose.getMchid()); + return bodyJsonObject; + } + + /** + public void closeOrder(String businessOrderId) throws Exception { + if (StringUtils.isBlank(businessOrderId)) { + throw new ParamsException("订单不能为空"); + } + OrderClose orderClose = new OrderClose(); + orderClose.setMchid(payProperties.getMchid()); + String urlSuffix = "/v3/pay/transactions/out-trade-no/" + businessOrderId + "/close"; OrderClosePayRequestImpl orderClosePayRequest = new OrderClosePayRequestImpl(); String url = getPayBaseUrl() + urlSuffix; @@ -42,4 +66,5 @@ public class OrderCloseServiceImpl extends BasePayService implements IOrderClose String authorization = getAuthorization(RequestMethod.POST, urlSuffix, serialNumber, payProperties, body.toString(), PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048); orderClosePayRequest.post(url, authorization, serialNumber, body); } + **/ } diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/order/impl/OrderSearchServiceImpl.java b/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/order/impl/OrderSearchServiceImpl.java index 5479087a..23bc070d 100644 --- a/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/order/impl/OrderSearchServiceImpl.java +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/service/pay/v3/order/impl/OrderSearchServiceImpl.java @@ -3,7 +3,7 @@ package ink.wgink.module.wechat.service.pay.v3.order.impl; import ink.wgink.exceptions.ParamsException; import ink.wgink.module.wechat.enums.PayAuthorizationTypeEnum; import ink.wgink.module.wechat.pojo.pay.v3.order.OrderSearch; -import ink.wgink.module.wechat.request.pay.v3.order.OrderSearchPayRequestImpl; +import ink.wgink.module.wechat.remote.pay.v3.IOrderPayRemoteService; import ink.wgink.module.wechat.service.pay.BasePayService; import ink.wgink.module.wechat.service.pay.v3.order.IOrderSearchService; import ink.wgink.properties.wechat.pay.v3.PayProperties; @@ -24,6 +24,9 @@ public class OrderSearchServiceImpl extends BasePayService implements IOrderSear @Autowired private PayProperties payProperties; + @Autowired + private IOrderPayRemoteService orderPayRemoteService; + @Override public OrderSearch getOrder(String transactionId) throws Exception { @@ -31,7 +34,9 @@ public class OrderSearchServiceImpl extends BasePayService implements IOrderSear throw new ParamsException("微信订单号参数不能为空"); } String urlSuffix = "/v3/pay/transactions/id/" + transactionId + "?mchid=" + payProperties.getMchid(); - return getOrderInfo(urlSuffix); + String serialNumber = getSerialNumber(); + String authorization = getAuthorization(RequestMethod.GET, urlSuffix, serialNumber, payProperties, null, PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048); + return orderPayRemoteService.getOrder(getPayBaseUrl(), transactionId, authorization, serialNumber, payProperties.getMchid()); } @Override @@ -40,14 +45,35 @@ public class OrderSearchServiceImpl extends BasePayService implements IOrderSear throw new ParamsException("商家订单号参数不能为空"); } String urlSuffix = "/v3/pay/transactions/out-trade-no/" + businessOrderId + "?mchid=" + payProperties.getMchid(); - return getOrderInfo(urlSuffix); - } - - private OrderSearch getOrderInfo(String urlSuffix) throws Exception { - OrderSearchPayRequestImpl orderSearchPayRequest = new OrderSearchPayRequestImpl(); - String url = getPayBaseUrl() + urlSuffix; String serialNumber = getSerialNumber(); String authorization = getAuthorization(RequestMethod.GET, urlSuffix, serialNumber, payProperties, null, PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048); - return orderSearchPayRequest.get(url, authorization, serialNumber); + return orderPayRemoteService.getBusinessOrder(getPayBaseUrl(), businessOrderId, authorization, serialNumber, payProperties.getMchid()); } + + + /** + @Override public OrderSearch getOrder(String transactionId) throws Exception { + if (StringUtils.isBlank(transactionId)) { + throw new ParamsException("微信订单号参数不能为空"); + } + String urlSuffix = "/v3/pay/transactions/id/" + transactionId + "?mchid=" + payProperties.getMchid(); + return getOrderInfo(urlSuffix); + } + + @Override public OrderSearch getBusinessOrder(String businessOrderId) throws Exception { + if (StringUtils.isBlank(businessOrderId)) { + throw new ParamsException("商家订单号参数不能为空"); + } + String urlSuffix = "/v3/pay/transactions/out-trade-no/" + businessOrderId + "?mchid=" + payProperties.getMchid(); + return getOrderInfo(urlSuffix); + } + + private OrderSearch getOrderInfo(String urlSuffix) throws Exception { + OrderSearchPayRequestImpl orderSearchPayRequest = new OrderSearchPayRequestImpl(); + String url = getPayBaseUrl() + urlSuffix; + String serialNumber = getSerialNumber(); + String authorization = getAuthorization(RequestMethod.GET, urlSuffix, serialNumber, payProperties, null, PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048); + return orderSearchPayRequest.get(url, authorization, serialNumber); + } + **/ } diff --git a/module-wechat/src/main/java/ink/wgink/module/wechat/utils/pay/PayAesUtil.java b/module-wechat/src/main/java/ink/wgink/module/wechat/utils/pay/PayAesUtil.java new file mode 100644 index 00000000..e5db6216 --- /dev/null +++ b/module-wechat/src/main/java/ink/wgink/module/wechat/utils/pay/PayAesUtil.java @@ -0,0 +1,65 @@ +package ink.wgink.module.wechat.utils.pay; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +/** + * @ClassName: PayAesUtil + * @Description: 支付AES加密 + * @Author: wanggeng + * @Date: 2021/10/2 2:23 下午 + * @Version: 1.0 + */ +public class PayAesUtil { + + static final int KEY_LENGTH_BYTE = 32; + static final int TAG_LENGTH_BIT = 128; + private final byte[] aesKey; + + /** + * @param key APIv3秘钥 + */ + public PayAesUtil(byte[] key) { + if (key.length != KEY_LENGTH_BYTE) { + throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节"); + } + this.aesKey = key; + } + + /** + * 解密 + * + * @param associatedData 关联数据 + * @param nonce 加密使用的随机串初始化向量 + * @param ciphertext 密文 + * @return + * @throws GeneralSecurityException + * @throws IOException + */ + public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException { + try { + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + + SecretKeySpec key = new SecretKeySpec(aesKey, "AES"); + GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce); + + cipher.init(Cipher.DECRYPT_MODE, key, spec); + cipher.updateAAD(associatedData); + + return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8"); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + throw new IllegalStateException(e); + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + throw new IllegalArgumentException(e); + } + } + +}