|
@@ -0,0 +1,110 @@
|
|
|
+package com.github.binarywang.wxpay.service.impl;
|
|
|
+
|
|
|
+import com.github.binarywang.wxpay.bean.customs.*;
|
|
|
+import com.github.binarywang.wxpay.exception.WxPayException;
|
|
|
+import com.github.binarywang.wxpay.service.CustomDeclarationService;
|
|
|
+import com.github.binarywang.wxpay.service.WxPayService;
|
|
|
+import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
|
|
|
+import com.google.gson.Gson;
|
|
|
+import com.google.gson.GsonBuilder;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import me.chanjar.weixin.common.error.WxRuntimeException;
|
|
|
+
|
|
|
+import javax.crypto.BadPaddingException;
|
|
|
+import javax.crypto.Cipher;
|
|
|
+import javax.crypto.IllegalBlockSizeException;
|
|
|
+import javax.crypto.NoSuchPaddingException;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.InvalidKeyException;
|
|
|
+import java.security.NoSuchAlgorithmException;
|
|
|
+import java.security.cert.X509Certificate;
|
|
|
+import java.util.Base64;
|
|
|
+
|
|
|
+/**
|
|
|
+ * <pre>
|
|
|
+ * 支付报关 实现.
|
|
|
+ * Created by xifengzhu on 2022/05/05.
|
|
|
+ * </pre>
|
|
|
+ *
|
|
|
+ * @author <a href="https://github.com/xifengzhu">xifengzhu</a>
|
|
|
+ */
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class CustomDeclarationServiceImpl implements CustomDeclarationService {
|
|
|
+ private static final Gson GSON = new GsonBuilder().create();
|
|
|
+ private final WxPayService payService;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public DeclarationResult declare(DeclarationRequest request) throws WxPayException {
|
|
|
+ String response = this.payService.postV3(DECLARATION_BASE_URL.concat("/orders"), GSON.toJson(request));
|
|
|
+ return GSON.fromJson(response, DeclarationResult.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public DeclarationQueryResult query(DeclarationQueryRequest request) throws WxPayException {
|
|
|
+ String url = String.format("%s/orders?appid=%s&mchid=%s&order_type=%s&order_no=%s&customs=%s&offset=%s&limit=%s",
|
|
|
+ DECLARATION_BASE_URL,
|
|
|
+ request.getAppid(),
|
|
|
+ request.getMchid(),
|
|
|
+ request.getOrderType(),
|
|
|
+ request.getOrderNo(),
|
|
|
+ request.getCustoms(),
|
|
|
+ request.getOffset(),
|
|
|
+ request.getLimit()
|
|
|
+ );
|
|
|
+ String result = this.payService.getV3(url);
|
|
|
+ return GSON.fromJson(result, DeclarationQueryResult.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public VerifyCertificateResult verifyCertificate(VerifyCertificateRequest request) throws WxPayException {
|
|
|
+ this.encryptFields(request);
|
|
|
+ String response = this.payService.postV3WithWechatpaySerial(DECLARATION_BASE_URL.concat("/verify-certificate"), GSON.toJson(request));
|
|
|
+ return GSON.fromJson(response, VerifyCertificateResult.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public DeclarationResult modify(DeclarationRequest request) throws WxPayException {
|
|
|
+ String response = this.payService.patchV3(DECLARATION_BASE_URL.concat("/orders"), GSON.toJson(request));
|
|
|
+ return GSON.fromJson(response, DeclarationResult.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public RedeclareResult redeclare(RedeclareRequest request) throws WxPayException {
|
|
|
+ String response = this.payService.postV3(DECLARATION_BASE_URL.concat("/redeclare"), GSON.toJson(request));
|
|
|
+ return GSON.fromJson(response, RedeclareResult.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void encryptFields(VerifyCertificateRequest request) throws WxPayException {
|
|
|
+ try {
|
|
|
+ request.setCertificateId(encryptOAEP(request.getCertificateId()));
|
|
|
+ request.setCertificateName(encryptOAEP(request.getCertificateName()));
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new WxPayException("敏感信息加密失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private X509Certificate getValidCertificate() {
|
|
|
+ return this.payService.getConfig().getVerifier().getValidCertificate();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String encryptOAEP(String message)
|
|
|
+ throws IllegalBlockSizeException {
|
|
|
+ X509Certificate certificate = getValidCertificate();
|
|
|
+ try {
|
|
|
+ // 身份信息校验 RSA 加密,填充方案使用 `RSAES-PKCS1-v1_5`
|
|
|
+ // https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_2.shtml
|
|
|
+ Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
|
|
+ cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
|
|
|
+
|
|
|
+ byte[] data = message.getBytes(StandardCharsets.UTF_8);
|
|
|
+ byte[] ciphertext = cipher.doFinal(data);
|
|
|
+ return Base64.getEncoder().encodeToString(ciphertext);
|
|
|
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
|
|
+ throw new WxRuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
|
|
|
+ } catch (InvalidKeyException e) {
|
|
|
+ throw new IllegalArgumentException("无效的证书", e);
|
|
|
+ } catch (IllegalBlockSizeException | BadPaddingException e) {
|
|
|
+ throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|