diff --git a/README.md b/README.md
index 96b4847..2ffa6b3 100644
--- a/README.md
+++ b/README.md
@@ -77,31 +77,30 @@

-- 加签失败邮件通知告警
+- 加签失败邮件告警
- > [此功能需手动开启](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-app/src/main/resources/application-dev.yml#L25-L43),开关属性: `spring.mail.enable`, 取值: `on/off`
+ > [此功能需手动开启](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-webapp/src/main/resources/application-dev.yml#L25-L43),开关属性: `spring.mail.enable`, 取值: `on/off`,也可以告警消息接入企业微信、钉钉、飞书、Discord等企业沟通软件。
加签失败邮件通知
-
+
## 1 支持的电子口岸
-> [核心加签接口](https://github.com/Weasley-J/chinaport-data-signature/blob/main/%E4%B8%AD%E5%9B%BD%E7%94%B5%E5%AD%90%E5%8F%A3%E5%B2%B8%E6%8A%A5%E6%96%87%E5%8A%A0%E7%AD%BE%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3.md#%E6%B5%B7%E5%85%B3%E6%95%B0%E6%8D%AE%E5%8A%A0%E7%AD%BE)理论上支持中国内地的大部分**地方电子口岸**
-
-| 电子口岸 | 是否支持 | 是否验证 |
-| ------------ | -------- |-----|
-| 海口电子口岸 | ✅ | ✅ |
-| 广州电子口岸 | ✅ | ✅ |
-| 郑州电子口岸 | ✅ | 待验证 |
-| 上海电子口岸 | ✅ | 待验证 |
-| 浙江电子口岸 | ✅ | 待验证 |
-| ... | | |
-
+> [核心加签接口](https://github.com/Weasley-J/chinaport-data-signature/blob/main/%E4%B8%AD%E5%9B%BD%E7%94%B5%E5%AD%90%E5%8F%A3%E5%B2%B8%E6%8A%A5%E6%96%87%E5%8A%A0%E7%AD%BE%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3.md#%E6%B5%B7%E5%85%B3%E6%95%B0%E6%8D%AE%E5%8A%A0%E7%AD%BE)
+> 理论上支持中国内地的大部分**地方电子口岸**
+| 电子口岸 | 是否支持 | 是否验证 |
+|--------|------|------|
+| 海口电子口岸 | ✅ | ✅ |
+| 广州电子口岸 | ✅ | ✅ |
+| 郑州电子口岸 | ✅ | 待验证 |
+| 上海电子口岸 | ✅ | 待验证 |
+| 杭州电子口岸 | ✅ | 待验证 |
+| ... | | |
## 2 项目代码质量
@@ -123,23 +122,23 @@
> 本应用是标准的`springboot`应用,支持`springboot`
> 的所有配置参数,推荐通过在[线`yaml`转`properties`](https://www.toyaml.com/index.html)将配置元数据复制到命令行参数中按需使用,
-- [推荐元数据配置示例](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-app/src/main/resources/application-dev.yml#L43-L71)
+- [推荐元数据配置示例](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-webapp/src/main/resources/application-dev.yml#L43-L71)
-- [加签异常邮件通知配置示例](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-app/src/main/resources/application-dev.yml#L23-L41)
+- [加签异常邮件通知配置示例](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-webapp/src/main/resources/application-dev.yml#L23-L41)
| 配置参数 | 是否必须(Y/N) | 解释 |
| ------------------------------------------------ | --------------- | ------------------------------------------------------------ |
-| eport.signature.algorithm | N | [XML签名的算法类型](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/SignatureAlgorithmProperties.java#L20),不指定时使用程序自动推断的算法, 推荐使用程序自动推断的算法 |
+| eport.signature.algorithm | N | [XML签名的算法类型](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-webapp/src/main/java/cn/alphahub/eport/signature/config/SignatureAlgorithmProperties.java#L20),不指定时使用程序自动推断的算法, 推荐使用程序自动推断的算法 |
| eport.signature.ukey.ws-url | Y | `u-key`所连接的`Windows`电脑的`socket`链接`url`,如: `ws://127.0.0.1:61232`,下载`release`直接运行的修改全局配置的`UKEY_HOST`即可 |
| eport.signature.ukey.password | N | u-key密码的密码,默认: `88888888`, 如果密码改过,需要指定下,下载`release`直接运行的修改全局配置的`UKEY_PASSWORD`即可 |
| eport.signature.ukey.health.endpoint.client-name | N | Windows上重启的ukey可执行文件全限定文件名称,不指定将自动查找(将程序安装到Windows平台上会生效,Linux、Uni环境无效) |
-| eport.signature.auth.enable | N | [是否启用token鉴权](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/AuthenticationProperties.java#L17),取值:on/off,生产环境建议开启 |
-| eport.signature.auth.token | N | 客户端请求鉴权token, 默认值: DefaultAuthToken, [请求头](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/AuthenticationProperties.java#L24),生产环境不建议使用默认值 |
-| eport.signature.report.ceb-message.cop-code | Y | [电子口岸XML报文](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/ChinaEportProperties.java#L20)传输企业代码 |
+| eport.signature.auth.enable | N | [是否启用token鉴权](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-webapp/src/main/java/cn/alphahub/eport/signature/config/AuthenticationProperties.java#L17),取值:on/off,生产环境建议开启 |
+| eport.signature.auth.token | N | 客户端请求鉴权token, 默认值: DefaultAuthToken, [请求头](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-webapp/src/main/java/cn/alphahub/eport/signature/config/AuthenticationProperties.java#L24),生产环境不建议使用默认值 |
+| eport.signature.report.ceb-message.cop-code | Y | [电子口岸XML报文](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-webapp/src/main/java/cn/alphahub/eport/signature/config/ChinaEportProperties.java#L20)传输企业代码 |
| eport.signature.report.ceb-message.cop-name | Y | 传输企业名称,报文传输的企业名称 |
| eport.signature.report.ceb-message.dxp-id | Y | 文传输编号,向中国电子口岸数据中心申请数据交换平台的用户编号 |
-| eport.signature.report.ceb-message.server | N | [海关服务器地址](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/ChinaEportProperties.java#L43),缺省则采用Client中的密文作文默认Server URL |
-| eport.signature.report.customs179.ebp-code | Y | [海关 179 数据上报](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/Customs179Properties.java#L24)的电商平台代码 |
+| eport.signature.report.ceb-message.server | N | [海关服务器地址](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-webapp/src/main/java/cn/alphahub/eport/signature/config/ChinaEportProperties.java#L43),缺省则采用Client中的密文作文默认Server URL |
+| eport.signature.report.customs179.ebp-code | Y | [海关 179 数据上报](https://github.com/Weasley-J/chinaport-data-signature/blob/main/chinaport-data-signature-webapp/src/main/java/cn/alphahub/eport/signature/config/Customs179Properties.java#L24)的电商平台代码 |
| eport.signature.report.customs179.server | N | 数据上报服务器URL地址,链接格式: https://域名联系海关/ceb2grab/grab/realTimeDataUpload,没有配置的话采用项目内置的URL密文地址 |
## 5 项目启动脚本
@@ -156,7 +155,7 @@
#!/bin/bash
# Environment args
-APP="chinaport-data-signature-app"
+APP="chinaport-data-signature-webapp"
UKEY_HOST="127.0.0.1"
UKEY_PASSWORD="88888888"
JVM_ARGS="-Xms1g -Xmx1g"
diff --git a/chinaport-data-signature-app/Dockerfile b/chinaport-data-signature-app/Dockerfile
deleted file mode 100644
index f11d859..0000000
--- a/chinaport-data-signature-app/Dockerfile
+++ /dev/null
@@ -1,11 +0,0 @@
-FROM azul/zulu-openjdk:17-jre
-MAINTAINER weasley
-WORKDIR /app
-COPY target/chinaport-data-signature-*.jar /app/chinaport-data-signature.jar
-EXPOSE 8080
-ENV TZ=PRC
-RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ >/etc/timezone
-
-ENV JAVA_OPTS=""
-ENV SPRING_ARGS=""
-ENTRYPOINT ["sh", "-c", "java ${JVM_OPTIONS} -jar chinaport-data-signature.jar ${SPRING_ARGS}"]
diff --git a/chinaport-data-signature-app/docker-push-arm64.sh b/chinaport-data-signature-app/docker-push-arm64.sh
deleted file mode 100644
index b12f34c..0000000
--- a/chinaport-data-signature-app/docker-push-arm64.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-TAG="1.1.1"
-docker stop chinaport-data-signature && docker rm -f chinaport-data-signature
-docker rmi -f weasleyj/chinaport-data-signature:${TAG}-arm64
-docker build -t weasleyj/chinaport-data-signature:${TAG}-arm64 . -f ./Dockerfile
-docker login -u weasleyj
-docker push weasleyj/chinaport-data-signature:${TAG}-arm64
-exit 0
diff --git a/chinaport-data-signature-app/docker-push-latest.sh b/chinaport-data-signature-app/docker-push-latest.sh
deleted file mode 100644
index ae11f86..0000000
--- a/chinaport-data-signature-app/docker-push-latest.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-TAG="latest"
-docker stop chinaport-data-signature && docker rm -f chinaport-data-signature
-docker rmi -f weasleyj/chinaport-data-signature:${TAG}
-docker build -t weasleyj/chinaport-data-signature:${TAG} . -f ./Dockerfile
-docker login -u weasleyj
-docker push weasleyj/chinaport-data-signature:${TAG}
-exit 0
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/ChinaEportSignatureApplication.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/ChinaEportSignatureApplication.java
deleted file mode 100644
index 153c1d5..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/ChinaEportSignatureApplication.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package cn.alphahub.eport.signature;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.web.socket.config.annotation.EnableWebSocket;
-
-/**
- * 中国电子口岸(海口海关)报文加签推送应用
- *
- * @author Weasley J
- * @date 2022-02-13
- * @since 1.0.0
- */
-@EnableWebSocket
-@SpringBootApplication
-public class ChinaEportSignatureApplication {
- public static void main(String[] args) {
- SpringApplication.run(ChinaEportSignatureApplication.class, args);
- }
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/base/exception/EportWebClientException.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/base/exception/EportWebClientException.java
deleted file mode 100644
index 7e96192..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/base/exception/EportWebClientException.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package cn.alphahub.eport.signature.base.exception;
-
-import lombok.Getter;
-
-import java.io.Serial;
-
-/**
- * The eport web client exception
- *
- * @author weasley
- * @version 1.1.0
- */
-@Getter
-public class EportWebClientException extends RuntimeException {
- @Serial
- private static final long serialVersionUID = 1L;
- /**
- * 异常消息
- */
- private String msg;
- /**
- * 错误码, 默认: 500
- */
- private int code = 500;
-
- public EportWebClientException(String msg) {
- super(msg);
- this.msg = msg;
- }
-
- public EportWebClientException(String msg, Throwable e) {
- super(msg, e);
- this.msg = msg;
- }
-
- public EportWebClientException(String msg, int code, Throwable e) {
- super(msg, e);
- this.msg = msg;
- this.code = code;
- }
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/base/exception/SignException.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/base/exception/SignException.java
deleted file mode 100644
index 0204f25..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/base/exception/SignException.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package cn.alphahub.eport.signature.base.exception;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-
-import java.io.Serial;
-
-/**
- * 自定义异常
- *
- * @author liuwenjing
- */
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-@EqualsAndHashCode(callSuper = true)
-public class SignException extends RuntimeException {
-
- @Serial
- private static final long serialVersionUID = 1L;
-
- /**
- * 异常消息
- */
- private String msg;
-
- /**
- * 错误码, 默认500
- */
- private int code = 500;
-
- public SignException(String msg) {
- super(msg);
- this.msg = msg;
- }
-
- public SignException(String msg, Throwable e) {
- super(msg, e);
- this.msg = msg;
- }
-
- public SignException(String msg, int code, Throwable e) {
- super(msg, e);
- this.msg = msg;
- this.code = code;
- }
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/ChinaEportProperties.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/ChinaEportProperties.java
deleted file mode 100644
index cf83eb3..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/ChinaEportProperties.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package cn.alphahub.eport.signature.config;
-
-import cn.alphahub.eport.signature.core.ChinaEportReportClient;
-import jakarta.validation.constraints.NotBlank;
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.validation.annotation.Validated;
-
-/**
- * 电子口岸XML报文传输的企业元数据配置
- *
- * @author weasley
- * @version 1.1.0
- */
-@Data
-@Validated
-@Configuration
-@ConfigurationProperties(prefix = ChinaEportProperties.PREFIX)
-public class ChinaEportProperties {
- public static final String PREFIX = "eport.signature.report.ceb-message";
- /**
- * 传输企业代码,报文传输的企业代码(需要与接入客户端的企业身份一致)
- */
- @NotBlank(message = "配置文件中的报文传输的企业代码不能为空")
- private String copCode;
- /**
- * 传输企业名称,报文传输的企业名称
- */
- @NotBlank(message = "报文传输的企业名称不能为空")
- private String copName;
- /**
- * 报文传输编号,向中国电子口岸数据中心申请数据交换平台的用户编号
- */
- @NotBlank(message = "向中国电子口岸数据中心申请数据交换平台的用户编号不能为空")
- private String dxpId;
- /**
- * 海关服务器地址,缺省则采用Client中的密文作文默认Server URL
- *
- * @apiNote CEMMessage XML数据上报服务器地址,格式: http://ip:port
- * @see ChinaEportReportClient#EPORT_CEBMESSAGE_SERVER_ENCODE
- */
- private String server;
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/Customs179Properties.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/Customs179Properties.java
deleted file mode 100644
index f40ae13..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/Customs179Properties.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package cn.alphahub.eport.signature.config;
-
-import jakarta.validation.constraints.NotBlank;
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.validation.annotation.Validated;
-
-/**
- * 海关 179 数据上报配置元数据
- *
- * @author weasley
- * @version 1.1.0
- * @apiNote 如果接口没有传过来, 就取
- */
-@Data
-@Validated
-@ConfigurationProperties(prefix = Customs179Properties.PREFIX)
-public class Customs179Properties {
- public static final String PREFIX = "eport.signature.report.customs179";
- /**
- * 电商平台代码
- *
- * @apiNote 电商平台海关注册登记编号或统一社会信用代码。境内企业需据实填写海关注册登记编号或统一社会信用代码,境外平台企业如无法提供电商平台代码可填“无”。
- */
- @NotBlank(message = "电商平台代码不能为空;如果你想对接CEBMessage进出口单, 先随便填一个,后面改成正确的")
- private String ebpCode;
- /**
- * 数据上报服务器URL地址,链接格式: https://域名联系海关获取/ceb2grab/grab/realTimeDataUpload
- *
- * @apiNote 没有配置的话采用项目内置的URL地址
- */
- private String server;
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/SignatureAlgorithm.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/SignatureAlgorithm.java
deleted file mode 100644
index 02af1a2..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/SignatureAlgorithm.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package cn.alphahub.eport.signature.config;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * XML Signature Algorithm
- *
- * @author weasley
- * @version 1.0.0
- * @apiNote 签名算法
- */
-@Getter
-@AllArgsConstructor
-public enum SignatureAlgorithm {
- RSA_SHA1("rsa-sha1", "SHA1WITHRSA", "http://www.w3.org/2000/09/xmldsig#rsa-sha1"),
- SM2_SM3("sm2-sm3", "SM3WITHSM2", "http://www.w3.org/2000/09/xmldsig#sm2-sm3"),
- ;
- /**
- * 算法类型
- */
- private final String algorithmType;
- /**
- * 算法名称
- */
- private final String algorithmName;
- /**
- * XML代码段中 ds:SignatureMethod 的算法值
- *
- * XML Signature Method:
- *
- * {@code }
- *
- */
- private final String signatureMethod;
-
- public static SignatureAlgorithm getSignatureAlgorithmSigAlgName(String sigAlgName) {
- return Arrays.stream(values())
- .filter(original -> Objects.equals(original.getAlgorithmName(), sigAlgName))
- .findFirst().orElse(null);
- }
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/UkeyAccessClientProperties.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/UkeyAccessClientProperties.java
deleted file mode 100644
index a2d7cb8..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/UkeyAccessClientProperties.java
+++ /dev/null
@@ -1,158 +0,0 @@
-package cn.alphahub.eport.signature.config;
-
-import cn.alphahub.eport.signature.support.CommandClient;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.Getter;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.SystemUtils;
-import org.apache.logging.log4j.util.Strings;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-import static cn.alphahub.eport.signature.config.ICommand.EPORT_ACCESS_CONTROL;
-import static cn.alphahub.eport.signature.config.ICommand.EPORT_WS_SERVER;
-import static cn.alphahub.eport.signature.config.UkeyProperties.PREFIX;
-
-/**
- * An interface to build command
- */
-@FunctionalInterface
-interface ICommand extends Serializable {
- /**
- * WebSocketServer.exe
- */
- String EPORT_WS_SERVER = "CnEport.Pub.WebSocketServer.exe";
- /**
- * SetAccessControl.exe
- */
- String EPORT_ACCESS_CONTROL = "SetAccessControl.exe";
-
- /**
- * To build command
- *
- * @param exeClient e.g: C:\中国电子口岸客户端控件\SetAccessControl.exe
- * @return command script
- */
- String build(String exeClient);
-}
-
-/**
- * Ukey自我重启相关
- *
- * Windows上的可执行文件: C:\中国电子口岸客户端控件\SetAccessControl.exe
- *
- * @author weasley
- * @version 1.0.0
- * @apiNote 可执行文件 SetAccessControl.exe 的安装位置以实际为准
- */
-@Data
-@Slf4j
-@ConfigurationProperties(prefix = PREFIX + ".health.endpoint")
-public class UkeyAccessClientProperties {
-
- /**
- * Windows上重启的ukey可执行文件全限定文件名称
- *
- * @apiNote 建议指定 clientName,可以避免全盘查找 SetAccessControl.exe, 提高性能
- * @apiNote 全限定文件名称,包含文件后缀, 建议不要安装到中文目录里面,如: C:\中国电子口岸客户端控件\SetAccessControl.exe
- */
- private String clientName;
-
- /**
- * 查找中国电子口岸客户端控件重启客户端的Windows可执行文件的具体位置
- *
- * @return SetAccessControl.exe 文件的绝对路径
- * @apiNote 以下命令行只适用于Windows平台,其他平台报错直接忽略
- */
- public String findClient() {
- if (!SystemUtils.IS_OS_WINDOWS) return null;
- CommandClient sharedInstance = CommandClient.getSharedInstance();
-
- List accessControlStdOutList;
- List eportWsServerStdOutList;
-
- sharedInstance.execute("where " + EPORT_ACCESS_CONTROL);
- accessControlStdOutList = new ArrayList<>(sharedInstance.getStdOutList());
- if (CollectionUtils.isEmpty(accessControlStdOutList)) return null;
-
- sharedInstance.execute("where " + EPORT_WS_SERVER);
- eportWsServerStdOutList = new ArrayList<>(sharedInstance.getStdOutList());
- if (CollectionUtils.isEmpty(eportWsServerStdOutList)) return null;
-
- String accessControlStdOut = FilenameUtils.getFullPathNoEndSeparator(accessControlStdOutList.get(0));
- String eportWsServerStdOut = FilenameUtils.getFullPathNoEndSeparator(eportWsServerStdOutList.get(0));
- if (accessControlStdOut.equals(eportWsServerStdOut)) {
- log.info("找到u-key Windows客户端执行文件: {} {}", EPORT_WS_SERVER, EPORT_ACCESS_CONTROL);
- return accessControlStdOutList.get(0);
- }
- return null;
- }
-
- /**
- * 执行指令
- *
- * -h 或 -help: 帮助
- * -restart: 重启控件
- * -start: 启动控件
- * -stop: 停止控件
- * -repair: 修复证书
- *
- */
- @Getter
- @AllArgsConstructor
- public enum Command implements ICommand {
- /**
- * 重启控件
- */
- RESTART("-restart", "重启控件"),
- /**
- * 启动控件
- */
- START("-start", "启动控件"),
- /**
- * 停止控件
- */
- STOP("-stop", "停止控件"),
- /**
- * 修复证书
- */
- REPAIR("-repair", "修复证书"),
- /**
- * 缺省符,无业务意义
- */
- DEFAULT("", "缺省符");
-
- /**
- * 指令
- */
- private final String cmd;
- /**
- * 描述
- */
- private final String desc;
-
- public String getCmd() {
- if (RESTART.cmd.equals(cmd)) {
- return cmd + " -i";
- }
- return cmd;
- }
-
- @Override
- public String build(String exeClient) {
- if (null == exeClient) return Strings.EMPTY;
- if (StringUtils.isBlank(this.getCmd())) {
- return "cmd /c \"" + exeClient + "\"";
- }
- return "cmd /c \"" + exeClient + " " + this.getCmd() + "\"";
- }
- }
-
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/UkeyInitialConfig.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/UkeyInitialConfig.java
deleted file mode 100644
index 0a80735..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/UkeyInitialConfig.java
+++ /dev/null
@@ -1,300 +0,0 @@
-package cn.alphahub.eport.signature.config;
-
-import cn.alphahub.dtt.plus.util.JacksonUtil;
-import cn.alphahub.dtt.plus.util.SpringUtil;
-import cn.alphahub.eport.signature.core.CertificateHandler;
-import cn.alphahub.eport.signature.core.SignHandler;
-import cn.alphahub.eport.signature.core.WebSocketClientHandler;
-import cn.alphahub.eport.signature.entity.SignRequest;
-import cn.alphahub.eport.signature.entity.SpcValidTime;
-import cn.alphahub.eport.signature.entity.UkeyRequest;
-import cn.alphahub.eport.signature.entity.UkeyResponse;
-import cn.alphahub.eport.signature.entity.WebSocketWrapper;
-import cn.alphahub.eport.signature.support.CertificateParser;
-import cn.hutool.core.lang.TypeReference;
-import lombok.Data;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.ObjectUtils;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.boot.ApplicationArguments;
-import org.springframework.boot.ApplicationRunner;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Scope;
-import org.springframework.web.socket.TextMessage;
-import org.springframework.web.socket.WebSocketSession;
-import org.springframework.web.socket.client.WebSocketConnectionManager;
-import org.springframework.web.socket.client.standard.StandardWebSocketClient;
-import org.springframework.web.socket.handler.TextWebSocketHandler;
-
-import java.io.IOException;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.LockSupport;
-
-import static cn.alphahub.eport.signature.core.CertificateHandler.SING_DATA_METHOD;
-import static cn.hutool.json.JSONUtil.toBean;
-import static cn.hutool.json.JSONUtil.toJsonStr;
-
-/**
- * 初始化配置
- *
- * @author lwj
- * @version 1.0
- * @date 2022-01-11 15:29
- */
-@Data
-@Slf4j
-@Configuration
-@EnableConfigurationProperties({UkeyProperties.class, EmailProperties.class, SignatureAlgorithmProperties.class, Customs179Properties.class})
-public class UkeyInitialConfig implements ApplicationRunner {
- /**
- * u-key默认密码8个8不要修改
- */
- private static final String DEFAULT_PASSWORD = "88888888";
-
- /**
- * 取海关签名证书PEM, X509Certificate证书(未经HASH算法散列过)
- *
- * @return 取海关签名证书PEM, X509Certificate证书是加签证书,真正的X509Certificate证书
- */
- public static String getX509CertificateParameter() {
- UkeyRequest ukeyRequest = new UkeyRequest();
- ukeyRequest.set_method("cus-sec_SpcGetSignCertAsPEM");
- ukeyRequest.set_id(1);
- ukeyRequest.setArgs(new HashMap<>());
- return JacksonUtil.toJson(ukeyRequest);
- }
-
- /**
- * 使用卡计算摘要,返回PEM格式信息, 这个不调也罢,已经硬核计算出来了
- *
- * @param sourceXml 不含ds:Signature节点的源xml原文数据
- * @param uniqueId uniqueId 唯一id, 用来区分是哪一次发送的消息,int32,最大32位大于0
- * @return DigestValue的值
- */
- public static String getDigestValueParameter(String sourceXml, Integer uniqueId) {
- Map args = new LinkedHashMap<>(2);
- args.put("szInfo", sourceXml);
- args.put("passwd", ObjectUtils.defaultIfNull(SpringUtil.getBean(UkeyProperties.class).getPassword(), DEFAULT_PASSWORD));
- UkeyRequest ukeyRequest = new UkeyRequest();
- ukeyRequest.set_method("sec_SpcSHA1DigestAsPEM");
- ukeyRequest.set_id(uniqueId);
- ukeyRequest.setArgs(args);
- return JacksonUtil.toJson(ukeyRequest);
- }
-
- /**
- * 签名, 不对原文计算摘要, 请您自行计算好摘要传入
- *
- * @param request 原文入参
- * @return SignatureValue的值, 返回的数组,包含您的证书编号,可作为KeyName的值
- */
- public static String getSignDataAsPEM(SignRequest request) {
- String initData = SignHandler.getInitData(request);
- log.warn("发送给ukey的真正请求入参: {}\n原始报文: {}", initData, request.getData());
- @SuppressWarnings({"all"}) UkeyRequest ukeyRequest = new UkeyRequest("cus-sec_SpcSignDataAsPEM", new HashMap<>() {{
- put("inData", initData);
- put("passwd", ObjectUtils.defaultIfNull(SpringUtil.getBean(UkeyProperties.class).getPassword(), DEFAULT_PASSWORD));
- }});
- ukeyRequest.set_id(request.getId());
- return JacksonUtil.toJson(ukeyRequest);
- }
-
- /**
- * 使用卡计算摘要,返回PEM格式信息
- *
- * @return ukey响应数据,示例: B959CD298E3BA6DAE360FB8CDB87B68B66D8BD221474046232910DD5FDA54354
- */
- public static String getSHA1DigestAsPEMParams(SignRequest request) {
- Map args = new LinkedHashMap<>();
- String initData = SignHandler.getInitData(request);
- log.warn("使用卡计算摘要,返回PEM格式信息: \n{}原始报文:\n{}", initData, request.getData());
- args.put("szInfo", initData);
- args.put("passwd", ObjectUtils.defaultIfNull(SpringUtil.getBean(UkeyProperties.class).getPassword(), DEFAULT_PASSWORD));
- UkeyRequest ukeyRequest = new UkeyRequest();
- ukeyRequest.set_method("cus-sec_SpcSHA1DigestAsPEM");
- ukeyRequest.set_id(request.getId());
- ukeyRequest.setArgs(args);
- return JacksonUtil.toJson(ukeyRequest);
- }
-
- /**
- * To park thread
- */
- private static void parkThread(AtomicReference reference, WebSocketConnectionManager socketConnectionManager) {
- socketConnectionManager.start();
- try {
- LockSupport.parkNanos(reference.get(), 1000 * 1000 * 1000 * 3L);
- } catch (Exception e) {
- log.error("线程自动unpark异常 {}", e.getLocalizedMessage(), e);
- } finally {
- socketConnectionManager.stop();
- }
- }
-
- /**
- * Callback used to run the bean.
- *
- * @param args incoming application arguments
- */
- @Override
- public void run(ApplicationArguments args) throws IOException {
- org.apache.xml.security.Init.init();
- if (log.isDebugEnabled()) {
- log.debug("XMl output format with C14n Initial Succeed.");
- }
- }
-
- /**
- * IOC中返回一个WebSocket包装类的实例对象
- *
- * @return WebSocket包装类
- */
- @Bean
- @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- public WebSocketWrapper webSocketWrapper() {
- return new WebSocketWrapper();
- }
-
- /**
- * 基于标准 Java WebSocket API 的 WebSocketClient
- *
- * @return An instance of StandardWebSocketClient
- */
- @Bean
- @ConditionalOnMissingBean({StandardWebSocketClient.class})
- public StandardWebSocketClient standardWebSocketClient() {
- return new StandardWebSocketClient();
- }
-
- /**
- * 注入一个X509Certificate证书判断的Bean
- *
- * @return X509Certificate证书判断
- */
- @Bean
- @SneakyThrows
- public CertificateHandler certificateHandler(UkeyProperties ukeyProperties, StandardWebSocketClient standardWebSocketClient) {
- CertificateHandler certificateHandler = new CertificateHandler();
-
- Map certMap = new ConcurrentHashMap<>();
- AtomicReference reference = new AtomicReference<>();
- reference.set(Thread.currentThread());
-
- // 获取u-key内的证书相关
- WebSocketConnectionManager certManager = new WebSocketConnectionManager(standardWebSocketClient, new TextWebSocketHandler() {
- final UkeyRequest ukeyRequest = new UkeyRequest("cus-sec_SpcGetSignCertAsPEM", new HashMap<>());
-
- @Override
- public void afterConnectionEstablished(WebSocketSession session) throws Exception {
- session.sendMessage(new TextMessage(JacksonUtil.toJson(ukeyRequest)));
- }
-
- @Override
- protected void handleTextMessage(WebSocketSession session, TextMessage message) {
- UkeyResponse response = toBean(message.getPayload(), new TypeReference<>() {
- }, true);
- try {
- if (Objects.equals(response.get_id(), 1)) {
- UkeyResponse.Args responseArgs = response.get_args();
- if (responseArgs.getResult().equals(true) && CollectionUtils.isNotEmpty(responseArgs.getData())) {
- certMap.put(SING_DATA_METHOD, responseArgs.getData().get(0));
- log.warn("已从电子口岸u-key中获取到x509Certificate证书: {}", JacksonUtil.toJson(certMap));
- }
- }
- } catch (Exception e) {
- log.error("唤醒线程异常 {}", e.getLocalizedMessage(), e);
- } finally {
- LockSupport.unpark(reference.get());
- }
- }
- }, ukeyProperties.getWsUrl());
- parkThread(reference, certManager);
-
- // 获取u-key签发日期, 查看海关证书有效期
- WebSocketConnectionManager ukeyValidTimeManager = new WebSocketConnectionManager(standardWebSocketClient, new TextWebSocketHandler() {
- @Override
- public void afterConnectionEstablished(WebSocketSession session) throws Exception {
- session.sendMessage(new TextMessage(toJsonStr(new UkeyRequest("cus-sec_SpcGetValidTimeFromCert", 1, new LinkedHashMap<>()))));
- }
-
- @Override
- protected void handleTextMessage(WebSocketSession session, TextMessage message) {
- UkeyResponse response = toBean(message.getPayload(), new TypeReference<>() {
- }, true);
- try {
- if (Objects.equals(response.get_id(), 1)) {
- UkeyResponse.Args responseArgs = response.get_args();
- if (responseArgs.getResult().equals(true) && CollectionUtils.isNotEmpty(responseArgs.getData())) {
- log.warn("从电子口岸u-key中获取到u-key有效期区间: {}", responseArgs.getData());
- SpcValidTime validTime = toBean(responseArgs.getData().get(0), new TypeReference<>() {
- }, true);
- certificateHandler.setUkeyValidTimeBegin(validTime.getSzStartTime());
- certificateHandler.setUkeyValidTimeEnd(validTime.getSzEndTime());
- }
- }
- } catch (Exception e) {
- log.error("唤醒线程异常 {}", e.getLocalizedMessage(), e);
- } finally {
- LockSupport.unpark(reference.get());
- }
- }
- }, ukeyProperties.getWsUrl());
- parkThread(reference, ukeyValidTimeManager);
-
- //自动推断ukey使用的签名算法
- WebSocketConnectionManager certSignatureAlgorithmManager = new WebSocketConnectionManager(standardWebSocketClient, new TextWebSocketHandler() {
- @Override
- public void afterConnectionEstablished(WebSocketSession session) throws Exception {
- log.info("开始推断ukey使用的签名算法:");
- session.sendMessage(new TextMessage(toJsonStr(new UkeyRequest("cus-sec_SpcGetSignCertAsPEM", new LinkedHashMap<>()))));
- }
-
- @Override
- protected void handleTextMessage(WebSocketSession session, TextMessage message) {
- UkeyResponse response = toBean(message.getPayload(), new TypeReference<>() {
- }, true);
- try {
- if (Objects.equals(response.get_id(), 1)) {
- UkeyResponse.Args responseArgs = response.get_args();
- if (responseArgs.getResult().equals(true) && CollectionUtils.isNotEmpty(responseArgs.getData())) {
- String x509Certificate = CertificateHandler.buildX509CertificateWithHeader(responseArgs.getData().get(0));
- X509Certificate certificateByCertText = CertificateParser.parseCertificateByCertText(x509Certificate);
- if (null != SignatureAlgorithm.getSignatureAlgorithmSigAlgName(certificateByCertText.getSigAlgName())) {
- certificateHandler.setAlgorithm(SignatureAlgorithm.getSignatureAlgorithmSigAlgName(certificateByCertText.getSigAlgName()));
- }
- }
- }
- } catch (Exception e) {
- log.error("唤醒线程异常 {}", e.getLocalizedMessage(), e);
- } finally {
- LockSupport.unpark(reference.get());
- }
- }
- }, ukeyProperties.getWsUrl());
- parkThread(reference, certSignatureAlgorithmManager);
-
- certificateHandler.setX509Map(certMap);
- return certificateHandler;
- }
-
- /**
- * @return An instance of WebSocketClientHandler
- */
- @Bean
- @ConditionalOnMissingBean({WebSocketClientHandler.class})
- public WebSocketClientHandler webSocketClientHandler(UkeyProperties ukeyProperties, WebSocketWrapper webSocketWrapper, CertificateHandler certificateHandler) {
- return new WebSocketClientHandler(ukeyProperties, webSocketWrapper, certificateHandler);
- }
-
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/UkeyProperties.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/UkeyProperties.java
deleted file mode 100644
index 728c8e2..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/UkeyProperties.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package cn.alphahub.eport.signature.config;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.validation.annotation.Validated;
-
-import static cn.alphahub.eport.signature.config.UkeyProperties.PREFIX;
-
-/**
- * 电子口岸u-key的配置参数
- *
- * @author weasley
- * @version 1.0
- * @date 2022/2/13
- */
-@Data
-@Validated
-@ConfigurationProperties(prefix = PREFIX)
-public class UkeyProperties {
- public static final String PREFIX = "eport.signature.ukey";
- /**
- * socket链接url
- */
- private String wsUrl = "ws://127.0.0.1:61232";
- /**
- * u-key密码
- */
- private String password = "88888888";
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/WebClientConfiguration.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/WebClientConfiguration.java
deleted file mode 100644
index 4792d91..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/config/WebClientConfiguration.java
+++ /dev/null
@@ -1,197 +0,0 @@
-package cn.alphahub.eport.signature.config;
-
-import cn.alphahub.eport.signature.base.exception.EportWebClientException;
-import cn.alphahub.eport.signature.core.web.EportCebMessageHttpClient;
-import cn.alphahub.eport.signature.core.web.EportCustoms179HttpClient;
-import cn.alphahub.eport.signature.core.web.EportReportResultHttpClient;
-import cn.alphahub.eport.signature.core.web.WebfluxDemoHttpClient;
-import cn.alphahub.eport.signature.support.OriginalPropertyNamingStrategy;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.tomcat.util.codec.binary.Base64;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatusCode;
-import org.springframework.http.codec.json.Jackson2JsonEncoder;
-import org.springframework.web.reactive.function.client.ClientRequest;
-import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
-import org.springframework.web.reactive.function.client.ExchangeStrategies;
-import org.springframework.web.reactive.function.client.WebClient;
-import org.springframework.web.reactive.function.client.support.WebClientAdapter;
-import org.springframework.web.service.invoker.HttpServiceProxyFactory;
-import reactor.core.publisher.Mono;
-
-import java.util.Objects;
-import java.util.function.Consumer;
-
-import static cn.alphahub.eport.signature.core.ChinaEportReportClient.EPORT_CEBMESSAGE_SERVER_ENCODE;
-import static cn.alphahub.eport.signature.core.ChinaEportReportClient.REPORT_PROD_ENV_179_URL_ENCODE;
-
-/**
- * The WebClient Configuration
- *
- * @author weasley
- * @version 1.0.0
- */
-@Slf4j
-@Configuration
-@EnableConfigurationProperties({Customs179Properties.class, ChinaEportProperties.class})
-public class WebClientConfiguration {
- public static final ThreadLocal> HTTP_HEADERS = new ThreadLocal<>();
-
- /**
- * @return A proxy bean of EportCebMessageHttpClient
- */
- @Bean
- public EportCebMessageHttpClient eportCebMessageHttpClient(ObjectMapper objectMapper, ChinaEportProperties chinaEportProperties) {
- WebClient webClient = WebClient.builder()
- .exchangeStrategies(customExchangeStrategies(objectMapper))
- .filter(((request, next) -> next.exchange(Objects.requireNonNull(injectHeader(request).block()))))
- .filters(exchangeFilters -> {
- exchangeFilters.add(logRequest());
- exchangeFilters.add(logResponse());
- })
- .defaultStatusHandler(HttpStatusCode::isError, resp -> Mono.just(new EportWebClientException("Web Client 调用发生异常!")))
- .baseUrl(StringUtils.defaultIfBlank(chinaEportProperties.getServer(), new String(Base64.decodeBase64(EPORT_CEBMESSAGE_SERVER_ENCODE))))
- .build();
- HttpServiceProxyFactory httpServiceProxyFactory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient))
- .build();
- return httpServiceProxyFactory.createClient(EportCebMessageHttpClient.class);
- }
-
-
- /**
- * @return A proxy bean of EportCustoms179HttpClient
- */
- @Bean
- public EportCustoms179HttpClient eportCustoms179HttpClient(ObjectMapper objectMapper, Customs179Properties customs179Properties) {
- WebClient webClient = WebClient.builder()
- .exchangeStrategies(ExchangeStrategies.builder().codecs(configurer -> {
- configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(enhanceSourceMapper(objectMapper)));
- }).build())
- .filters(exchangeFilters -> {
- exchangeFilters.add(((request, next) -> next.exchange(Objects.requireNonNull(injectHeader(request).block()))));
- exchangeFilters.add(logRequest());
- exchangeFilters.add(logResponse());
- })
- .defaultStatusHandler(HttpStatusCode::isError, resp -> Mono.just(new EportWebClientException("Web Client 调用发生异常!")))
- .baseUrl(StringUtils.defaultIfBlank(customs179Properties.getServer(), new String(Base64.decodeBase64(REPORT_PROD_ENV_179_URL_ENCODE))))
- .build();
- HttpServiceProxyFactory httpServiceProxyFactory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient)).build();
- return httpServiceProxyFactory.createClient(EportCustoms179HttpClient.class);
- }
-
- /**
- * @return A proxy bean of EportReportResultHttpClient
- */
- @Bean
- public EportReportResultHttpClient eportReportResultHttpClient(ChinaEportProperties chinaEportProperties) {
- String baseUrl = StringUtils.defaultIfBlank(chinaEportProperties.getServer(), new String(Base64.decodeBase64(EPORT_CEBMESSAGE_SERVER_ENCODE)));
- WebClient webClient = WebClient.builder()
- .filter(logRequest())
- .filter(logResponse())
- .defaultStatusHandler(HttpStatusCode::isError, resp -> Mono.just(new EportWebClientException("Web Client 调用发生异常!")))
- .baseUrl(baseUrl)
- .build();
- return HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient)).build()
- .createClient(EportReportResultHttpClient.class);
- }
-
- /**
- * @return A proxy bean of WebfluxDemoHttpClient
- */
- @Bean
- public WebfluxDemoHttpClient webfluxDemoHttpClient(ObjectMapper objectMapper) {
- WebClient webClient = WebClient.builder()
- .exchangeStrategies(customExchangeStrategies(objectMapper))
- .filters(exchangeFilters -> {
- exchangeFilters.add(((request, next) -> next.exchange(Objects.requireNonNull(injectHeader(request).block()))));
- exchangeFilters.add(logRequest());
- exchangeFilters.add(logResponse());
- })
- .defaultStatusHandler(HttpStatusCode::isError, resp -> Mono.just(new EportWebClientException("Web Client 调用发生异常!")))
- .baseUrl("http://127.0.0.1:8080")
- .build();
- WebClientAdapter clientAdapter = WebClientAdapter.forClient(webClient);
- HttpServiceProxyFactory httpServiceProxyFactory = HttpServiceProxyFactory.builder(clientAdapter).build();
- return httpServiceProxyFactory.createClient(WebfluxDemoHttpClient.class);
- }
-
- /**
- * To inject headers
- */
- public Mono injectHeader(final ClientRequest clientRequest) {
- if (null != HTTP_HEADERS.get()) {
- Mono clientRequestMono = Mono.just(ClientRequest.from(clientRequest)
- .headers(HTTP_HEADERS.get())
- .build());
- clearHttpHeaders();
- return clientRequestMono;
- }
- return Mono.just(ClientRequest.from(clientRequest)
- .build());
- }
-
- /**
- * Clear Http Headers
- */
- public void clearHttpHeaders() {
- if (null != HTTP_HEADERS.get()) {
- HTTP_HEADERS.remove();
- }
- }
-
- /**
- * Custom exchange strategies
- */
- public ExchangeStrategies customExchangeStrategies(ObjectMapper objectMapper) {
- return ExchangeStrategies.builder()
- .codecs(configurer -> {
- configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(enhanceSourceMapper(objectMapper)));
- }).build();
- }
-
- /**
- * To enhance mapper
- */
- private ObjectMapper enhanceSourceMapper(ObjectMapper objectMapper) {
- ObjectMapper enhanceMapper = objectMapper.copy();
- enhanceMapper.setPropertyNamingStrategy(new OriginalPropertyNamingStrategy());
- return enhanceMapper;
- }
-
- /**
- * log web request
- */
- private ExchangeFilterFunction logRequest() {
- return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
- if (log.isInfoEnabled()) {
- log.info("Request URL: " + clientRequest.url());
- log.info("Request Method: " + clientRequest.method());
- log.info("Request Headers: " + clientRequest.headers());
- if (clientRequest.method() == HttpMethod.POST || clientRequest.method() == HttpMethod.PUT) {
- log.info("Request Body: " + clientRequest.body());
- }
- }
- return Mono.just(clientRequest);
- });
- }
-
- /**
- * log web response
- */
- private ExchangeFilterFunction logResponse() {
- return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
- if (log.isInfoEnabled()) {
- log.info("Response status: {}", clientResponse.statusCode());
- log.info("Response headers: {}", clientResponse.headers().asHttpHeaders());
- }
- return Mono.just(clientResponse);
- });
- }
-
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/controller/rpc/EportReportResultController.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/controller/rpc/EportReportResultController.java
deleted file mode 100644
index cc01907..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/controller/rpc/EportReportResultController.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package cn.alphahub.eport.signature.controller.rpc;
-
-import cn.alphahub.eport.signature.base.domain.Result;
-import cn.alphahub.eport.signature.config.ChinaEportProperties;
-import cn.alphahub.eport.signature.core.web.EportReportResultHttpClient;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.ObjectUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.format.annotation.DateTimeFormat;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-import reactor.core.publisher.Mono;
-
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-
-/**
- * 查询申报回执结果
- *
- * @author weasley
- * @version 1.1.0
- * @apiNote 目前仅实现:CEB311Message、CEB621Message 申报结果查询
- */
-@Slf4j
-@RestController
-@RequestMapping("/rpc/eport/result")
-public class EportReportResultController {
- private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
- @Autowired
- private ChinaEportProperties chinaEportProperties;
- @Autowired
- private EportReportResultHttpClient eportReportResultHttpClient;
-
- /**
- * 查询311进口单申报结果
- *
- * @param qryId 查询时间,日期时间格式:yyyyMMddHHmmss
- * @response {
- * "message": "操作成功",
- * "success": true,
- * "timestamp": "2023-08-09 15:18:25",
- * "code": 200,
- * "data": "[{org_id=1, instm=1691397836000, re_order_guid=NWIVQA-WEASLEY-20230807164347-GCVZ4S, returnstatus=2, ebpcode=46016602EV, returntime2=20230807164356, ebccode=46016602EV, trans_dxpid=DXPENT0000530815, returninfo=新增申报成功[NWIVQA-WEASLEY-20230807164347-GCVZ4S], returntime=1691397830000, orderno=JO_D8079556739228400022}]"
- * }
- * @apiNote 查询此时间点之后的数据,必须在当前时间点之前,默认查询当前时间前15秒的申报数据,当前时间:20230806144417,则 qryId=20230806144401,不传的情况适用于刚刚申报成功查询回执结果,海关的处理时间间隔约为15秒
- * @since 1.1.1
- */
- @GetMapping("/ceb312msg")
- public Result getCeb312msgResult(@RequestParam(required = false) @DateTimeFormat(pattern = "yyyyMMddHHmmss") LocalDateTime qryId) {
- qryId = ObjectUtils.defaultIfNull(qryId, LocalDateTime.now().minusSeconds(15));
- log.info("开始查询311申报回执结果, qryId {}", FORMATTER.format(qryId));
- Mono msgResult = eportReportResultHttpClient.getCeb312msgResult(chinaEportProperties.getDxpId(), FORMATTER.format(qryId));
- return Result.ok(msgResult.block());
- }
-
- /**
- * 查询621进口单申报结果
- *
- * @param qryId 查询时间,日期时间格式:yyyyMMddHHmmss
- * @response {
- * "message": "操作成功",
- * "success": true,
- * "timestamp": "2023-08-09 15:26:53",
- * "code": 200,
- * "data": "[{org_id=1, instm=1691397837000, agentcode=46016602EV, re_elist_guid_cus=9422f96b-ccbc-4a69-a899-6d9dd583d501, returnstatus=2, ebpcode=46016602EV, preno=B20230807570793612, returntime2=20230807164357, ebccode=46016602EV, createtime=20230807164351, trans_dxpid=DXPENT0000530815, returninfo=清单新增申报成功[3CQHDG-WEASLEY-20230807164348-7KYRQN][电商企业编码:46016602EV订单编号:JO_D8079556739228400022], returntime=1691397830000, re_elist_guid=3CQHDG-WEASLEY-20230807164348-7KYRQN, customscode=6409}, {org_id=1, instm=1691397847000, agentcode=46016602EV, re_elist_guid_cus=9422f96b-ccbc-4a69-a899-6d9dd583d501, returnstatus=120, ebpcode=46016602EV, preno=B20230807570793612, returntime2=20230807164407, ebccode=46016602EV, createtime=20230807164355, trans_dxpid=DXPENT0000530815, returninfo=[Code:1800;Desc:逻辑校验通过], returntime=1691397831000, re_elist_guid=4e7a2dab-064b-410b-9ce6-e322c590ae3d, customscode=6409, invtno=64092023I000722460}, {org_id=1, instm=1691397847000, agentcode=46016602EV, re_elist_guid_cus=9422f96b-ccbc-4a69-a899-6d9dd583d501, returnstatus=800, ebpcode=46016602EV, preno=B20230807570793612, returntime2=20230807164407, ebccode=46016602EV, createtime=20230807164355, trans_dxpid=DXPENT0000530815, returninfo=[Code:2600;Desc:放行], returntime=1691397832000, re_elist_guid=4e7a2dab-064b-410b-9ce6-e322c590ae3d, customscode=6409, invtno=64092023I000722460}]"
- * }
- * @apiNote 查询此时间点之后的数据,必须在当前时间点之前,默认查询当前时间前15秒的申报数据,当前时间:20230806144417,则 qryId=20230806144401,不传的情况适用于刚刚申报成功查询回执结果,海关的处理时间间隔约为15秒
- * @since 1.1.1
- */
- @GetMapping("/ceb622msg")
- public Result getCe622msgResult(@RequestParam(required = false) @DateTimeFormat(pattern = "yyyyMMddHHmmss") LocalDateTime qryId) {
- qryId = ObjectUtils.defaultIfNull(qryId, LocalDateTime.now().minusSeconds(15));
- log.info("开始查询621进口单申报回执结果, qryId {}", FORMATTER.format(qryId));
- Mono msgResult = eportReportResultHttpClient.getCe622msgResult(chinaEportProperties.getDxpId(), FORMATTER.format(qryId));
- return Result.ok(msgResult.block());
- }
-
-}
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/core/CertificateHandler.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/core/CertificateHandler.java
deleted file mode 100644
index cfa8c51..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/core/CertificateHandler.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package cn.alphahub.eport.signature.core;
-
-import cn.alphahub.eport.signature.config.SignatureAlgorithm;
-import cn.hutool.core.date.LocalDateTimeUtil;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.experimental.Accessors;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-import java.util.Map;
-
-import static cn.alphahub.eport.signature.config.SignatureAlgorithm.RSA_SHA1;
-
-/**
- * X509Certificate证书
- *
- * @author weasley
- * @version 1.0
- * @date 2022/2/13
- */
-@Data
-@Slf4j
-@NoArgsConstructor
-@AllArgsConstructor
-@Accessors(chain = true)
-public class CertificateHandler implements Serializable {
- /**
- * 从u-key读取含发送推送 X509Certificate 证书对应的加签方法
- */
- public static final String SING_DATA_METHOD = "cus-sec_SpcSignDataAsPEM";
- /**
- * 暂定2022-07-01为第一个时间分界
- */
- public static final LocalDateTime DATE_TIME_202207 = LocalDateTimeUtil.parse("2022-07-01", "yyyy-MM-dd");
-
- /**
- * u-key的.cer证书是否存在
- */
- private Boolean certExists = false;
- /**
- * XML 签名算法, RSA_SHA1 兜底
- */
- private SignatureAlgorithm algorithm = RSA_SHA1;
- /**
- * 判断用那一个证书的集合
- *
- * - key -> 从u-key读取的方法名
- * - value -> 从u-key读取的方法名对应的X509Certificate证书
- *
- */
- @Getter
- private Map x509Map;
- /**
- * 海关u-key证书有效期开始
- */
- private LocalDateTime ukeyValidTimeBegin;
- /**
- * 海关u-key证书有效期结束
- */
- private LocalDateTime ukeyValidTimeEnd;
-
- /**
- * 组装X509Certificate证书
- *
- * 组装64位长度一行的pem分割的pem
- *
- * @param certPomFromUkey 从ukey里面读取的pem
- * @return 64位长度一行的pem分割的pem
- * @apiNote 不带Header
- */
- public static String buildX509CertificateWithoutHeader(String certPomFromUkey) {
- certPomFromUkey = certPomFromUkey.trim();
- StringBuilder sb = new StringBuilder();
- int count = 0;
- for (char c : certPomFromUkey.toCharArray()) {
- sb.append(c);
- count++;
- if (count == 64) {
- sb.append("\n");
- count = 0;
- }
- }
- return sb.toString().trim();
- }
-
- /**
- * 组装X509Certificate证书
- *
- * 组装64位长度一行的pem分割的pem
- *
- * @param certPomFromUkey 从ukey里面读取的pem
- * @return 64位长度一行的pem分割的pem
- * @apiNote 带Header
- */
- public static String buildX509CertificateWithHeader(String certPomFromUkey) {
- return "-----BEGIN CERTIFICATE-----\n"
- .concat(buildX509CertificateWithoutHeader(certPomFromUkey)).concat("\n")
- .concat("-----END CERTIFICATE-----");
- }
-
- public LocalDateTime getUkeyValidTimeBegin() {
- if (ukeyValidTimeBegin == null) {
- return LocalDateTime.now();
- }
- return ukeyValidTimeBegin;
- }
-
- public void setX509Map(Map x509Map) {
- this.x509Map = x509Map;
- }
-
- /**
- * 获取509Certificate证书
- *
- * @param method 发送给电子口岸u-key的入参的[_method]字段的值
- * @return 509Certificate证书
- */
- public String getX509Certificate(String method) {
- return switch (method) {
- case SING_DATA_METHOD -> this.getX509Map().get(SING_DATA_METHOD);
- default -> throw new IllegalStateException("Unexpected value: " + method);
- };
- }
-
-}
-
diff --git a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/core/ChinaEportReportClient.java b/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/core/ChinaEportReportClient.java
deleted file mode 100644
index d2fb8c5..0000000
--- a/chinaport-data-signature-app/src/main/java/cn/alphahub/eport/signature/core/ChinaEportReportClient.java
+++ /dev/null
@@ -1,476 +0,0 @@
-package cn.alphahub.eport.signature.core;
-
-import cn.alphahub.eport.signature.base.exception.SignException;
-import cn.alphahub.eport.signature.config.ChinaEportProperties;
-import cn.alphahub.eport.signature.config.Customs179Properties;
-import cn.alphahub.eport.signature.config.UkeyProperties;
-import cn.alphahub.eport.signature.entity.Capture179DataRequest;
-import cn.alphahub.eport.signature.entity.Capture179DataResponse;
-import cn.alphahub.eport.signature.entity.SignRequest;
-import cn.alphahub.eport.signature.entity.SignResult;
-import cn.alphahub.eport.signature.entity.ThirdAbstractResponse;
-import cn.alphahub.eport.signature.entity.UkeyRequest;
-import cn.alphahub.eport.signature.entity.UkeyResponse.Args;
-import cn.alphahub.eport.signature.entity.UploadCEBMessageRequest;
-import cn.hutool.core.codec.Base64;
-import cn.hutool.core.lang.TypeReference;
-import cn.hutool.http.ContentType;
-import cn.hutool.http.HttpResponse;
-import cn.hutool.http.HttpUtil;
-import cn.hutool.json.JSONUtil;
-import io.github.weasleyj.china.eport.sign.AbstractCebMessage;
-import io.github.weasleyj.china.eport.sign.IMessageType;
-import io.github.weasleyj.china.eport.sign.model.cebmessage.BaseTransfer;
-import io.github.weasleyj.china.eport.sign.model.cebmessage.CEB311Message;
-import io.github.weasleyj.china.eport.sign.model.cebmessage.CEB621Message;
-import io.github.weasleyj.china.eport.sign.model.cebmessage.export.CEB303Message;
-import io.github.weasleyj.china.eport.sign.model.customs179.Customs179Request;
-import io.github.weasleyj.china.eport.sign.model.request.Message;
-import io.github.weasleyj.china.eport.sign.model.request.MessageBody;
-import io.github.weasleyj.china.eport.sign.model.request.MessageHead;
-import io.github.weasleyj.china.eport.sign.model.request.MessageRequest;
-import io.github.weasleyj.china.eport.sign.model.signature.CanonicalizationMethod;
-import io.github.weasleyj.china.eport.sign.model.signature.DigestMethod;
-import io.github.weasleyj.china.eport.sign.model.signature.KeyInfo;
-import io.github.weasleyj.china.eport.sign.model.signature.Reference;
-import io.github.weasleyj.china.eport.sign.model.signature.Signature;
-import io.github.weasleyj.china.eport.sign.model.signature.SignatureMethod;
-import io.github.weasleyj.china.eport.sign.model.signature.SignedInfo;
-import io.github.weasleyj.china.eport.sign.model.signature.Transforms;
-import io.github.weasleyj.china.eport.sign.model.signature.X509Data;
-import io.github.weasleyj.china.eport.sign.util.GUIDUtil;
-import io.github.weasleyj.china.eport.sign.util.JAXBUtil;
-import lombok.AllArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.stereotype.Component;
-
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-
-import static cn.alphahub.dtt.plus.util.JacksonUtil.readValue;
-import static cn.alphahub.dtt.plus.util.JacksonUtil.toJson;
-import static cn.alphahub.eport.signature.core.CertificateHandler.SING_DATA_METHOD;
-
-/**
- * 电子口岸上报客户端
- *
- * @author weasley
- * @since 1.1.0
- */
-@Slf4j
-@Component
-@AllArgsConstructor
-public class ChinaEportReportClient {
- /**
- * 海关服务器地址,格式: http://ip:port
- *
- * @apiNote base64加密下,不适合直接公布到公网
- */
- public static final String EPORT_CEBMESSAGE_SERVER_ENCODE = "aHR0cDovLzM2LjEwMS4yMDguMjMwOjgwOTA=";
- /**
- * 海关 179 数据抓取测试环境 URL (base64加密,不适合直接公布到外网)
- */
- public static final String REPORT_TEST_ENV_179_URL_ENCODE = "aHR0cHM6Ly9zd2FwcHRlc3Quc2luZ2xld2luZG93LmNuL2NlYjJncmFiL2dyYWIvcmVhbFRpbWVEYXRhVXBsb2Fk";
- /**
- * 海关 179 数据抓取生产环境 URL (base64加密,不适合直接公布到外网)
- */
- public static final String REPORT_PROD_ENV_179_URL_ENCODE = "aHR0cHM6Ly9jdXN0b21zLmNoaW5hcG9ydC5nb3YuY24vY2ViMmdyYWIvZ3JhYi9yZWFsVGltZURhdGFVcGxvYWQ=";
- private final SignHandler signHandler;
- private final UkeyProperties ukeyProperties;
- private final Customs179Properties customs179Properties;
- private final ChinaEportProperties chinaEportProperties;
-
- /**
- * 构建 ds:Signature 节点
- *
- * @param signResult 加签结果
- * @return ds:Signature 节点
- */
- public static String buildSignatureNode(SignResult signResult) {
- KeyInfo keyInfo = KeyInfo.builder()
- .keyName(signResult.getCertNo())
- .x509Data(new X509Data(signResult.getX509Certificate()))
- .build();
-
- Reference reference = Reference.builder()
- .digestMethod(new DigestMethod())
- .uri("")
- .transforms(new Transforms())
- .digestValue(signResult.getDigestValue())
- .build();
-
- SignedInfo signedInfo = SignedInfo.builder()
- .CanonicalizationMethod(new CanonicalizationMethod())
- .SignatureMethod(new SignatureMethod().setAlgorithm(SignatureHandler.getSignatureMethodAlgorithm()))
- .reference(reference)
- .build();
-
- Signature signature = Signature.builder()
- .keyInfo(keyInfo)
- .signatureValue(signResult.getSignatureValue())
- .signedInfo(signedInfo)
- .build();
-
- return JAXBUtil.toXml(signature);
- }
-
- /**
- * 构建 ds:SignedInfo 节点
- *
- * @param signResult 加签结果
- * @return ds:SignedInfo 节点
- */
- public static String buildSignedInfoNode(SignResult signResult) {
- Reference reference = Reference.builder()
- .digestMethod(new DigestMethod())
- .uri("")
- .transforms(new Transforms())
- .digestValue(signResult.getDigestValue())
- .build();
- SignedInfo signedInfo = SignedInfo.builder()
- .CanonicalizationMethod(new CanonicalizationMethod())
- .SignatureMethod(new SignatureMethod().setAlgorithm(SignatureHandler.getSignatureMethodAlgorithm()))
- .reference(reference)
- .build();
- return JAXBUtil.toXml(signedInfo);
- }
-
- /**
- * CebXxxMessage数据上报海关
- *
- * @param cebMessage 原始xml对象
- * @param messageType CEB311Message|CEB621Message|...
- * @return 推送结果, OK: 表示成功, 报关结果需要自己查询回执
- */
- public ThirdAbstractResponse report(AbstractCebMessage cebMessage, IMessageType messageType) {
- log.info("数据上报海关xml入参: {}, {}", JSONUtil.toJsonStr(cebMessage), messageType.getType());
- MessageRequest messageRequest = buildMessageRequest(cebMessage, messageType);
- String requestServer = Base64.decodeStr(EPORT_CEBMESSAGE_SERVER_ENCODE);
- requestServer = StringUtils.defaultIfBlank(chinaEportProperties.getServer(), requestServer);
- String requestBody = JSONUtil.toJsonStr(messageRequest);
- log.info("数据上报海关请求入参 {}\nRequest Server: {}", requestBody, requestServer);
- HttpResponse httpResponse = HttpUtil.createPost(requestServer + "/cebcmsg")
- .contentType(ContentType.JSON.getValue())
- .body(requestBody)
- .execute();
- String responseBody = httpResponse.body();
- log.info("数据上报Http响应结果: {}", responseBody);
- if (!"OK".equals(responseBody)) {
- log.error("上报海关请求异常, 请求入参: {}\n海关Http响应: {}", requestBody, responseBody);
- }
- ThirdAbstractResponse thirdResponse = ThirdAbstractResponse.getInstance();
- thirdResponse.setPayload(messageRequest);
- thirdResponse.setOriginal(responseBody);
- thirdResponse.setExpected("OK");
- return thirdResponse;
- }
-
- /**
- * 海关 179 数据抓取
- *
- *
- */
- public ThirdAbstractResponse