Merge branch 'feature_探索'

This commit is contained in:
Weasley J
2023-07-30 18:58:28 +08:00
17 changed files with 518 additions and 64 deletions
+2 -1
View File
@@ -26,7 +26,7 @@
- 对于单体应用,您可以直接下载[release](https://github.com/Weasley-J/chinaport-data-signature/releases)中的二进制文件使用(使用较多),根据您的实际情况适当修改运行参数。
- 对于分布式微服务,建议切换到[feature_microservice](https://github.com/Weasley-J/chinaport-data-signature/tree/feature_microservice)分支进行构建(较少使用)。
- 您还可以通过[Docker镜像快速搭建报文加签推送的环境](https://hub.docker.com/repository/docker/weasleyj/chinaport-data-signature)。
- 如果您的电商后台系统也是使用`Java`语言开发,我们在[Maven仓库中上传了项目中用到的数据模型](https://central.sonatype.com/artifact/io.github.weasley-j/chinaport-data-signature-data-model/1.0.4),可帮助您的系统与本项目快速集成。您只需要使用这些数据模型填充数据,然后使用`JSON`进行数据交互,从而降低对接成本。
- 如果您的电商后台系统也是使用`Java`语言开发,我们在[Maven仓库中上传了项目中用到的数据模型](https://central.sonatype.com/artifact/io.github.weasley-j/chinaport-data-signature-data-model),可帮助您的系统与本项目快速集成。您只需要使用这些数据模型填充数据,然后使用`JSON`进行数据交互,从而降低对接成本。
### 功能概述
@@ -277,6 +277,7 @@ java -Dfile.encoding=utf-8 ${JVM_ARGS} -jar ${APP}.jar \
感谢以下公司对我们项目的赞助和支持:
- 海南省荣誉进出口贸易有限公司:[官方网站](http://www.hnzrjck.com/)
- 广州市汇客物流有限公司
- ...
如果您的公司已赞助我们的项目,但在列表中没有找到,请及时与我们联系,我们将尽快添加您的公司名。
+2 -2
View File
@@ -36,7 +36,7 @@
<dtt-utils.version>1.4.1</dtt-utils.version>
<commons-io.version>2.13.0</commons-io.version>
<multiple-email.version>3.0.0</multiple-email.version>
<signature-data-model.version>1.0.4</signature-data-model.version>
<signature-data-model.version>1.0.5</signature-data-model.version>
<jaxb-api.version>2.3.1</jaxb-api.version>
<guava.version>32.1.1-jre</guava.version>
<sonar.host.url>http://192.168.31.140:9001</sonar.host.url>
@@ -245,7 +245,7 @@
<excludes>
<exclude>**/xml/**</exclude>
<exclude>**/cert/**</exclude>
<exclude>**/application-lwj.yml</exclude>
<exclude>**/application-lwj*.yml</exclude>
<exclude>**/smart-doc.json</exclude>
</excludes>
</resource>
@@ -41,20 +41,7 @@ public class EportTestController {
*
* @return 数据加签结果
* @apiNote 非正式调用API,只为了让你看到海关总署XML加密的数据返回格式
* @response {
* "message": "操作成功",
* "success": true,
* "timestamp": "2023-07-28 21:39:15",
* "code": 200,
* "data": {
* "success": true,
* "certNo": "03000000000cde6f",
* "x509Certificate": "MIIEoDCCBESgAwIBAgIIAwAAAAAM3m8wDAYIKoEcz1UBg3UFADCBmDELMAkGA1UEBhMCQ04xDzANBgNVBAgMBuWMl+S6rDEPMA0GA1UEBwwG5YyX5LqsMRswGQYDVQQKDBLkuK3lm73nlLXlrZDlj6PlsrgxGzAZBgNVBAsMEuivgeS5pueuoeeQhuS4reW/gzEtMCsGA1UEAwwk5Lit5Zu955S15a2Q5Lia5Yqh6K+B5Lmm566h55CG5Lit5b+DMB4XDTIzMDMyOTAwMDAwMFoXDTMzMDMyOTAwMDAwMFowVjELMAkGA1UEBhMCQ04xMzAxBgNVBAsMKua1t+WNl+ecgeiNo+iqiei/m+WHuuWPo+i0uOaYk+aciemZkOWFrOWPuDESMBAGA1UEAwwJ5p2o5aaC6YeRMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE0vOQmplAr9igPZrA8F1msqnFd0U++6G6NhG5rNuIUWft0BwQn7eSJkt5/fvSSoe7pUg2/awHUWPnzkeeQc7oVqOCArUwggKxMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCBsAwCQYDVR0TBAIwADApBgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcUAgIwHwYDVR0jBBgwFoAURCQxt0wEvoAVXmuo4N1bjKXTh0UwHQYDVR0OBBYEFAytGob5L0WqhOCZ5l6Lf2jUdNrAMGgGA1UdIARhMF8wXQYEVR0gADBVMFMGCCsGAQUFBwIBFkdodHRwczovL3d3dy5jaGluYXBvcnQuZ292LmNuL3RjbXNmaWxlL3UvY21zL3d3dy8yMDIyMDQvMTIxMzI5NDh4dDZwLnBkZjB/BgNVHR8EeDB2MHSgcqBwhm5sZGFwOi8vbGRhcC5jaGluYXBvcnQuZ292LmNuOjM4OS9jbj1jcmwwMzAwMDAsb3U9Y3JsMDAsb3U9Y3JsLGM9Y24/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP2NuPWNybDAzMDAwMDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmNoaW5hcG9ydC5nb3YuY246ODgwMC8wOgYKKwYBBAGpQ2QFAQQsDCrmtbfljZfnnIHojaPoqonov5vlh7rlj6PotLjmmJPmnInpmZDlhazlj7gwEgYKKwYBBAGpQ2QFAwQEDAIwMTAiBgorBgEEAalDZAUIBBQMEjUxMjMyNDE5NjQxMDE3Mjk3WDAgBgorBgEEAalDZAUJBBIMEDAzLUpKMEc5MDAyMjA3NTIwGQYKKwYBBAGpQ2QFCwQLDAlNQTVUTkZHWTkwEgYKKwYBBAGpQ2QFDAQEDAIwMDASBgorBgEEAalDZAIBBAQMAjEyMBIGCisGAQQBqUNkAgQEBAwCMTQwDAYIKoEcz1UBg3UFAANIADBFAiBM4OVAc8aaCZU4XFfcVMkC7bWIIenRnPLxrnwVeYO3CQIhANQ767YIurkJCoLtwyqQPbUZe/+3BjGZcIWqB1mAl9T+",
* "digestValue": "EW5//PlrSsuQ8pw+hRRtSsSDaN4=",
* "signatureValue": "MeEiFDT6H6Sn/foR5zxKrl3g/i+fsCe2humDK6LA2E9ORvFxijpAILxXLezvUBIyqXmydu4BjFwAQk62+V1QtQ==",
* "signatureNode": "<ds:SignedInfo xmlns:ceb=\"http://www.chinaport.gov.cn/ceb\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\"></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sm2-sm3\"></ds:SignatureMethod><ds:Reference URI=\"\"><ds:Transforms><ds:Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></ds:DigestMethod><ds:DigestValue>EW5//PlrSsuQ8pw+hRRtSsSDaN4=</ds:DigestValue></ds:Reference></ds:SignedInfo>"
* }
* }
* @response {"message":"操作成功","success":true,"timestamp":"2023-07-30 18:49:15","code":200,"data":{"success":true,"certNo":"03000000000cde6f","x509Certificate":"MIIEoDCCBESgAwIBAgIIAwAAAAAM3m8wDAYIKoEcz1UBg3UFADCBmDELMAkGA1UEBhMCQ04xDzANBgNVBAgMBuWMl+S6rDEPMA0GA1UEBwwG5YyX5LqsMRswGQYDVQQKDBLkuK3lm73nlLXlrZDlj6PlsrgxGzAZBgNVBAsMEuivgeS5pueuoeeQhuS4reW/gzEtMCsGA1UEAwwk5Lit5Zu955S15a2Q5Lia5Yqh6K+B5Lmm566h55CG5Lit5b+DMB4XDTIzMDMyOTAwMDAwMFoXDTMzMDMyOTAwMDAwMFowVjELMAkGA1UEBhMCQ04xMzAxBgNVBAsMKua1t+WNl+ecgeiNo+iqiei/m+WHuuWPo+i0uOaYk+aciemZkOWFrOWPuDESMBAGA1UEAwwJ5p2o5aaC6YeRMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE0vOQmplAr9igPZrA8F1msqnFd0U++6G6NhG5rNuIUWft0BwQn7eSJkt5/fvSSoe7pUg2/awHUWPnzkeeQc7oVqOCArUwggKxMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCBsAwCQYDVR0TBAIwADApBgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcUAgIwHwYDVR0jBBgwFoAURCQxt0wEvoAVXmuo4N1bjKXTh0UwHQYDVR0OBBYEFAytGob5L0WqhOCZ5l6Lf2jUdNrAMGgGA1UdIARhMF8wXQYEVR0gADBVMFMGCCsGAQUFBwIBFkdodHRwczovL3d3dy5jaGluYXBvcnQuZ292LmNuL3RjbXNmaWxlL3UvY21zL3d3dy8yMDIyMDQvMTIxMzI5NDh4dDZwLnBkZjB/BgNVHR8EeDB2MHSgcqBwhm5sZGFwOi8vbGRhcC5jaGluYXBvcnQuZ292LmNuOjM4OS9jbj1jcmwwMzAwMDAsb3U9Y3JsMDAsb3U9Y3JsLGM9Y24/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP2NuPWNybDAzMDAwMDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmNoaW5hcG9ydC5nb3YuY246ODgwMC8wOgYKKwYBBAGpQ2QFAQQsDCrmtbfljZfnnIHojaPoqonov5vlh7rlj6PotLjmmJPmnInpmZDlhazlj7gwEgYKKwYBBAGpQ2QFAwQEDAIwMTAiBgorBgEEAalDZAUIBBQMEjUxMjMyNDE5NjQxMDE3Mjk3WDAgBgorBgEEAalDZAUJBBIMEDAzLUpKMEc5MDAyMjA3NTIwGQYKKwYBBAGpQ2QFCwQLDAlNQTVUTkZHWTkwEgYKKwYBBAGpQ2QFDAQEDAIwMDASBgorBgEEAalDZAIBBAQMAjEyMBIGCisGAQQBqUNkAgQEBAwCMTQwDAYIKoEcz1UBg3UFAANIADBFAiBM4OVAc8aaCZU4XFfcVMkC7bWIIenRnPLxrnwVeYO3CQIhANQ767YIurkJCoLtwyqQPbUZe/+3BjGZcIWqB1mAl9T+","digestValue":"/uy5whbEnIhnrSkF7hSAJNm8ISI=","signatureValue":"uEG8qUT4NMS7g+QVJK6WdVQXlSK5n94PQJ+iGWec2cCyXfKh6Il2U+jmEq6nxWpoxCn3M0zNH7bICaoKrMpc6w==","signatureNode":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ds:SignedInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">\n <ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\"/>\n <ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sm2-sm3\"/>\n <ds:Reference URI=\"\">\n <ds:Transforms>\n <ds:Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/>\n </ds:Transforms>\n <ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/>\n <ds:DigestValue>/uy5whbEnIhnrSkF7hSAJNm8ISI=</ds:DigestValue>\n </ds:Reference>\n</ds:SignedInfo>"}}
*/
@GetMapping("/cebmessage/signature")
public Result<SignResult> signCebMessage() {
@@ -25,6 +25,7 @@ import o.github.weasleyj.china.eport.sign.IMessageType;
import o.github.weasleyj.china.eport.sign.model.cebmessage.BaseTransfer;
import o.github.weasleyj.china.eport.sign.model.cebmessage.CEB311Message;
import o.github.weasleyj.china.eport.sign.model.cebmessage.CEB621Message;
import o.github.weasleyj.china.eport.sign.model.cebmessage.export.CEB303Message;
import o.github.weasleyj.china.eport.sign.model.customs179.Customs179Request;
import o.github.weasleyj.china.eport.sign.model.request.Message;
import o.github.weasleyj.china.eport.sign.model.request.MessageBody;
@@ -84,6 +85,61 @@ public class ChinaEportReportClient {
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数据上报海关
*
@@ -206,6 +262,13 @@ public class ChinaEportReportClient {
buildBaseTransfer(ceb621Message.getBaseTransfer());
yield ceb621Message;
}
case CEB303Message -> {
CEB303Message ceb303Message = Objects.requireNonNull(JAXBUtil.toBean(cebMessage, CEB303Message.class));
ceb303Message.setGuid(guid);
ceb303Message.getOrder().getOrderHead().setGuid(guid);
buildBaseTransfer(ceb303Message.getBaseTransfer());
yield ceb303Message;
}
};
}
case JSON -> {
@@ -226,6 +289,14 @@ public class ChinaEportReportClient {
buildBaseTransfer(ceb621Message.getBaseTransfer());
yield ceb621Message;
}
case CEB303Message -> {
CEB303Message ceb303Message = JSONUtil.toBean(cebMessage, new TypeReference<>() {
}, false);
ceb303Message.setGuid(guid);
ceb303Message.getOrder().getOrderHead().setGuid(guid);
buildBaseTransfer(ceb303Message.getBaseTransfer());
yield ceb303Message;
}
};
}
default -> throw new IllegalStateException("Unexpected value: " + toJson(request));
@@ -310,31 +381,7 @@ public class ChinaEportReportClient {
* @param sourceXml 原始XML
*/
private String buildXml(SignResult signResult, String sourceXml, IMessageType messageType) {
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();
String signatureNode = JAXBUtil.toXml(signature);
String signatureNode = buildSignatureNode(signResult);
String xmlStart = "</ceb:" + messageType.getMessageType() + ">";
int index = sourceXml.indexOf(xmlStart);
StringBuilder builder = new StringBuilder(sourceXml);
@@ -113,7 +113,6 @@ public class SignHandler {
wrapper.setThreadReference(new AtomicReference<>(Thread.currentThread()));
if (SignHandler.isSignXml(request)) {
wrapper.getSignResult().setDigestValue(SignatureHandler.getDigestValueOfCEBXxxMessage(request.getData()));
wrapper.getSignResult().setSignatureNode(SignatureHandler.getSignatureNodeBeforeSend(request));
}
WebSocketConnectionManager manager = new WebSocketConnectionManager(standardWebSocketClient, webSocketClientHandler, ukeyProperties.getWsUrl());
@@ -56,11 +56,11 @@ public class WebSocketClientHandler extends TextWebSocketHandler {
@Getter
private final CertificateHandler certificateHandler;
@Autowired
private UkeyHealthHelper ukeyHealthHelper;
@Autowired
private EmailTemplate emailTemplate;
@Autowired
private EmailProperties emailProperties;
@Autowired
private UkeyHealthHelper ukeyHealthHelper;
public WebSocketClientHandler(UkeyProperties ukeyProperties, WebSocketWrapper webSocketWrapper, CertificateHandler certificateHandler) {
this.ukeyProperties = ukeyProperties;
@@ -91,6 +91,7 @@ public class WebSocketClientHandler extends TextWebSocketHandler {
webSocketWrapper.getSignResult().setCertNo(responseArgs.getData().get(1));
if (SignHandler.isSignXml(webSocketWrapper.getRequest())) {
webSocketWrapper.getSignResult().setX509Certificate(certificateHandler.getX509Certificate(response.get_method()));
webSocketWrapper.getSignResult().setSignatureNode(ChinaEportReportClient.buildSignedInfoNode(webSocketWrapper.getSignResult()));
}
} else {
sendAlertSignFailure(JacksonUtil.toPrettyJson(response));
File diff suppressed because one or more lines are too long
@@ -145,8 +145,6 @@ class EportSignControllerTest {
</ceb:CEB311Message>
""";
SignRequest request = new SignRequest(xml);
SignResult result = controller.signature(request).getData();
// 组装数据
CEB311Message ceb311Message = JAXBUtil.toBean(xml, CEB311Message.class);
String guid = GUIDUtil.getGuid();
@@ -0,0 +1,135 @@
package cn.alphahub.eport.signature.report.export;
import cn.alphahub.dtt.plus.util.JacksonUtil;
import cn.alphahub.eport.signature.base.domain.Result;
import cn.alphahub.eport.signature.entity.SignResult;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import o.github.weasleyj.china.eport.sign.model.cebmessage.export.CEB303Message;
import o.github.weasleyj.china.eport.sign.util.JAXBUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
/**
* 621 进口单 xml 上报测试
*
* @author weasley
* @version 1.0.0
*/
@Slf4j
@SpringBootTest
class Upload303XmlTests {
@Test
void sign() {
final String data = """
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<ceb:CEB303Message xmlns:ceb="http://www.chinaport.gov.cn/ceb" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" guid="CEB303_ZH_GZ_20230309112945042_67622" version="1.0">
<ceb:Order>
<ceb:OrderHead>
<ceb:guid>CEB303_ZH_GZ_20230309112945042_67622</ceb:guid>
<ceb:appType>1</ceb:appType>
<ceb:appTime>20230309112945</ceb:appTime>
<ceb:appStatus>2</ceb:appStatus>
<ceb:orderType>E</ceb:orderType>
<ceb:orderNo>SGFGP0003129133YKKA7</ceb:orderNo>
<ceb:ebpCode>44306650K2</ceb:ebpCode>
<ceb:ebpName>广州市汇客物流有限公司</ceb:ebpName>
<ceb:ebcCode>44306650K2</ceb:ebcCode>
<ceb:ebcName>广州市汇客物流有限公司</ceb:ebcName>
<ceb:goodsValue>13.89000</ceb:goodsValue>
<ceb:freight>0.00000</ceb:freight>
<ceb:currency>142</ceb:currency>
<ceb:note>希音</ceb:note>
</ceb:OrderHead>
<ceb:OrderList>
<ceb:gnum>1</ceb:gnum>
<ceb:itemNo>se2209024331104035</ceb:itemNo>
<ceb:itemName>手机支架</ceb:itemName>
<ceb:barCode>无</ceb:barCode>
<ceb:unit>011</ceb:unit>
<ceb:currency>142</ceb:currency>
<ceb:qty>1.00000</ceb:qty>
<ceb:price>13.89000</ceb:price>
<ceb:totalPrice>13.89000</ceb:totalPrice>
<ceb:note>希音</ceb:note>
</ceb:OrderList>
</ceb:Order>
<ceb:BaseTransfer>
<ceb:copCode>44306650K2</ceb:copCode>
<ceb:copName>广州市汇客物流有限公司</ceb:copName>
<ceb:dxpMode>DXP</ceb:dxpMode>
<ceb:dxpId>向中国电子口岸数据中心申请数据交换平台的用户编号</ceb:dxpId>
</ceb:BaseTransfer>
</ceb:CEB303Message>
""";
HttpResponse response = HttpUtil.createPost("http://localhost:8080/rpc/eport/signature")
.contentType(ContentType.JSON.getValue())
.header("x-auth-token-eport-sign", "DefaultAuthToken")
.body(JSONUtil.toJsonStr(new HashMap<String, Object>() {{
put("id", 1);
put("data", data);
}}))
.execute();
System.err.println(response.body());
Result<SignResult> result = JacksonUtil.readValue(response.body(), new TypeReference<Result<SignResult>>() {
});
System.err.println("\n" + result.getData().getSignatureNode());
}
@Test
void xmlToCEB303Message() {
String xml = """
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<ceb:CEB303Message xmlns:ceb="http://www.chinaport.gov.cn/ceb" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" guid="CEB303_ZH_GZ_20230309112945042_67615" version="1.0">
<ceb:Order>
<ceb:OrderHead>
<ceb:guid>CEB303_ZH_GZ_20230309112945042_67615</ceb:guid>
<ceb:appType>1</ceb:appType>
<ceb:appTime>20230309112945</ceb:appTime>
<ceb:appStatus>2</ceb:appStatus>
<ceb:orderType>E</ceb:orderType>
<ceb:orderNo>SGFGP0003129133YKK5</ceb:orderNo>
<ceb:ebpCode>44306650K2</ceb:ebpCode>
<ceb:ebpName>广州市汇客物流有限公司</ceb:ebpName>
<ceb:ebcCode>44306650K2</ceb:ebcCode>
<ceb:ebcName>广州市汇客物流有限公司</ceb:ebcName>
<ceb:goodsValue>13.89000</ceb:goodsValue>
<ceb:freight>0.00000</ceb:freight>
<ceb:currency>142</ceb:currency>
<ceb:note>希音</ceb:note>
</ceb:OrderHead>
<ceb:OrderList>
<ceb:gnum>1</ceb:gnum>
<ceb:itemNo>se2209024331104035</ceb:itemNo>
<ceb:itemName>手机支架</ceb:itemName>
<ceb:barCode>无</ceb:barCode>
<ceb:unit>011</ceb:unit>
<ceb:currency>142</ceb:currency>
<ceb:qty>1.00000</ceb:qty>
<ceb:price>13.89000</ceb:price>
<ceb:totalPrice>13.89000</ceb:totalPrice>
<ceb:note>test</ceb:note>
</ceb:OrderList>
</ceb:Order>
<ceb:BaseTransfer>
<ceb:copCode>44306650K2</ceb:copCode>
<ceb:copName>广州市汇客物流有限公司</ceb:copName>
<ceb:dxpMode>DXP</ceb:dxpMode>
<ceb:dxpId>向中国电子口岸数据中心申请数据交换平台的用户编号</ceb:dxpId>
</ceb:BaseTransfer>
</ceb:CEB303Message>
""";
CEB303Message ceb303Message = JAXBUtil.toBean(xml, CEB303Message.class);
System.err.println(JSONUtil.toJsonPrettyStr(ceb303Message) + "\n");
String ceb303MessageXml = JAXBUtil.toXml(ceb303Message);
System.out.println(ceb303MessageXml);
}
}
@@ -8,7 +8,11 @@
### 1.1 海关 179 数据抓取报文
### 1.2 海关总署`xml`报文, 进口单:CEB311Message, CEB621Message
### 1.2 海关总署`xml`报文
进口单:CEB311Message, CEB621Message,
出口单: CEB303Message
+1 -1
View File
@@ -5,7 +5,7 @@
<groupId>io.github.weasley-j</groupId>
<artifactId>chinaport-data-signature-data-model</artifactId>
<version>1.0.4</version>
<version>1.0.5</version>
<name>chinaport-data-signature-data-model</name>
<packaging>jar</packaging>
<url>https://github.com/Weasley-J/chinaport-data-signature/tree/main/chinaport-data-signature-data-model</url>
@@ -9,8 +9,11 @@ import o.github.weasleyj.china.eport.sign.IMessageType;
* @version 1.0.0
*/
public enum MessageType implements IMessageType {
/* 进口单 */
CEB311Message("CEB311Message"),
CEB621Message("CEB621Message"),
/* 出口单 */
CEB303Message("CEB303Message"),
;
private final String messageType;
@@ -0,0 +1,54 @@
package o.github.weasleyj.china.eport.sign.model.cebmessage.export;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import o.github.weasleyj.china.eport.sign.AbstractCebMessage;
import o.github.weasleyj.china.eport.sign.constants.NameSpace;
import o.github.weasleyj.china.eport.sign.model.cebmessage.BaseSubscribe;
import o.github.weasleyj.china.eport.sign.model.cebmessage.BaseTransfer;
import o.github.weasleyj.china.eport.sign.model.cebmessage.ExtendMessage;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
/**
* CEB303Message 出口单
*
* @author weasley
* @version 1.0.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "CEB303Message", namespace = NameSpace.NAMESPACE_CEB_URI)
public class CEB303Message extends AbstractCebMessage implements Serializable {
@XmlAttribute(name = "guid")
private String guid;
@XmlAttribute(name = "version")
private String version;
@XmlElement(name = "Order", namespace = NameSpace.NAMESPACE_CEB_URI)
private Order order;
@XmlElement(name = "BaseTransfer", namespace = NameSpace.NAMESPACE_CEB_URI)
private BaseTransfer baseTransfer;
@XmlElement(name = "BaseSubscribe", namespace = NameSpace.NAMESPACE_CEB_URI)
private BaseSubscribe baseSubscribe;
@XmlElement(name = "ExtendMessage", namespace = NameSpace.NAMESPACE_CEB_URI)
private ExtendMessage extendMessage;
}
@@ -0,0 +1,38 @@
package o.github.weasleyj.china.eport.sign.model.cebmessage.export;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.List;
import static o.github.weasleyj.china.eport.sign.constants.NameSpace.NAMESPACE_CEB_URI;
/**
* The Order
* <p>订单表头
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Order ", namespace = NAMESPACE_CEB_URI)
public class Order implements Serializable {
/**
* 订单表头
*/
@XmlElement(name = "OrderHead", namespace = NAMESPACE_CEB_URI)
private OrderHead orderHead;
/**
* 订单商品列表
*/
@XmlElement(name = "OrderList", namespace = NAMESPACE_CEB_URI)
private List<OrderList> orderList;
}
@@ -0,0 +1,96 @@
package o.github.weasleyj.china.eport.sign.model.cebmessage.export;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import static o.github.weasleyj.china.eport.sign.constants.NameSpace.NAMESPACE_CEB_URI;
/**
* 订单表头
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "OrderHead ", namespace = NAMESPACE_CEB_URI)
public class OrderHead implements Serializable {
/**
* 1-系统唯一序号-guid-C36-是-企业系统生成36位唯一序号(英文字母大写)。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String guid;
/**
* 2-报送类型-appType-C1-是-企业报送类型。1-新增
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String appType;
/**
* 3-报送时间-appTime-C14-是-企业报送时间。格式:YYYYMMDDhhmmss。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String appTime;
/**
* 4-业务状态-appStatus-C..3-是-业务状态:1-暂存,2-申报,默认为2。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String appStatus;
/**
* 5-订单类型-orderType-C1-是-电子订单类型:I进口
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String orderType;
/**
* 6-订单编号-orderNo-C..60-是-交易平台的订单编号,同一交易平台的订单编号应唯一。订单编号长度不能超过60位。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String orderNo;
/**
* 7-电商平台代码-ebpCode-C..18-是-电商平台的海关注册登记编号;电商平台未在海关注册登记,由电商企业发送订单的,以中国电子口岸发布的电商平台标识编号为准。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String ebpCode;
/**
* 8-电商平台名称-ebpName-C..100-是-电商平台的海关注册登记名称;电商平台未在海关注册登记,由电商企业发送订单的,以中国电子口岸发布的电商平台名称为准。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String ebpName;
/**
* 9-电商企业代码-ebcCode-C..18-是-电商企业的海关注册登记编号。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String ebcCode;
/**
* 10-电商企业名称-ebcName-C..100-是-电商企业的海关注册登记名称。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String ebcName;
/**
* 11-商品价格-goodsValue-N16,2-是-商品实际成交价,含非现金抵扣金额。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String goodsValue;
/**
* 12-运杂费-freight-N16,2-是-不包含在商品价格中的运杂费,无则填写"0"。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String freight;
/**
* 币制-海关标准的参数代码 《JGS-20 海关业务代码集》- 货币代码
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String currency;
/**
* 备注-note-C..1000-否-
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String note;
}
@@ -0,0 +1,88 @@
package o.github.weasleyj.china.eport.sign.model.cebmessage.export;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import static o.github.weasleyj.china.eport.sign.constants.NameSpace.NAMESPACE_CEB_URI;
/**
* The Order List
* <p>订单商品表体
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "OrderList ", namespace = NAMESPACE_CEB_URI)
public class OrderList implements Serializable {
/**
* 1-商品序号-gnum-N2-是-从1开始的递增序号。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private Integer gnum;
/**
* 2-企业商品货号-itemNo-C..30-是-电商企业自定义的商品货号(SKU)。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String itemNo;
/**
* 3-企业商品名称-itemName-C..250-是-交易平台销售商品的中文名称。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String itemName;
/**
* 4-企业商品描述-itemDescribe-C..1000-否-交易平台销售商品的描述信息。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String itemDescribe;
/**
* 5-条形码-barCode-C..50-否-国际通用的商品条形码,一般由前缀部分、制造厂商代码、商品代码和校验码组成。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String barCode;
/**
* 6-单位-unit-C3-是-填写海关标准的参数代码,参照《JGS-20 海关业务代码集》- 计量单位代码。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String unit;
/**
* 10-币制-currency-C3-是-限定为人民币,填写“142”。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String currency;
/**
* 7-数量-qty-N16,2-是-商品实际数量。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String qty;
/**
* 8-单价-price-N16,2-是-商品单价。赠品单价填写为“0”。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String price;
/**
* 9-总价-totalPrice-N16,2-是-商品总价,等于单价乘以数量。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String totalPrice;
/**
* 12-备注-note-C..1000-否-促销活动,商品单价偏离市场价格的,可以在此说明。
*/
@XmlElement(namespace = NAMESPACE_CEB_URI)
private String note;
}
+11 -8
View File
@@ -48,19 +48,19 @@ curl -X GET -H 'x-auth-token-eport-sign:DefaultAuthToken' -i http://localhost:80
|└─signatureNode|string|XML报文的签名节点<br/><li>用来组装 ds:SignedInfo 节点</li>|-|
**Response-example:**
```json
```
{
"message": "操作成功",
"success": true,
"timestamp": "2023-07-28 21:39:15",
"timestamp": "2023-07-30 18:49:15",
"code": 200,
"data": {
"success": true,
"certNo": "03000000000cde6f",
"x509Certificate": "MIIEoDCCBESgAwIBAgIIAwAAAAAM3m8wDAYIKoEcz1UBg3UFADCBmDELMAkGA1UEBhMCQ04xDzANBgNVBAgMBuWMl+S6rDEPMA0GA1UEBwwG5YyX5LqsMRswGQYDVQQKDBLkuK3lm73nlLXlrZDlj6PlsrgxGzAZBgNVBAsMEuivgeS5pueuoeeQhuS4reW/gzEtMCsGA1UEAwwk5Lit5Zu955S15a2Q5Lia5Yqh6K+B5Lmm566h55CG5Lit5b+DMB4XDTIzMDMyOTAwMDAwMFoXDTMzMDMyOTAwMDAwMFowVjELMAkGA1UEBhMCQ04xMzAxBgNVBAsMKua1t+WNl+ecgeiNo+iqiei/m+WHuuWPo+i0uOaYk+aciemZkOWFrOWPuDESMBAGA1UEAwwJ5p2o5aaC6YeRMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE0vOQmplAr9igPZrA8F1msqnFd0U++6G6NhG5rNuIUWft0BwQn7eSJkt5/fvSSoe7pUg2/awHUWPnzkeeQc7oVqOCArUwggKxMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCBsAwCQYDVR0TBAIwADApBgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcUAgIwHwYDVR0jBBgwFoAURCQxt0wEvoAVXmuo4N1bjKXTh0UwHQYDVR0OBBYEFAytGob5L0WqhOCZ5l6Lf2jUdNrAMGgGA1UdIARhMF8wXQYEVR0gADBVMFMGCCsGAQUFBwIBFkdodHRwczovL3d3dy5jaGluYXBvcnQuZ292LmNuL3RjbXNmaWxlL3UvY21zL3d3dy8yMDIyMDQvMTIxMzI5NDh4dDZwLnBkZjB/BgNVHR8EeDB2MHSgcqBwhm5sZGFwOi8vbGRhcC5jaGluYXBvcnQuZ292LmNuOjM4OS9jbj1jcmwwMzAwMDAsb3U9Y3JsMDAsb3U9Y3JsLGM9Y24/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP2NuPWNybDAzMDAwMDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmNoaW5hcG9ydC5nb3YuY246ODgwMC8wOgYKKwYBBAGpQ2QFAQQsDCrmtbfljZfnnIHojaPoqonov5vlh7rlj6PotLjmmJPmnInpmZDlhazlj7gwEgYKKwYBBAGpQ2QFAwQEDAIwMTAiBgorBgEEAalDZAUIBBQMEjUxMjMyNDE5NjQxMDE3Mjk3WDAgBgorBgEEAalDZAUJBBIMEDAzLUpKMEc5MDAyMjA3NTIwGQYKKwYBBAGpQ2QFCwQLDAlNQTVUTkZHWTkwEgYKKwYBBAGpQ2QFDAQEDAIwMDASBgorBgEEAalDZAIBBAQMAjEyMBIGCisGAQQBqUNkAgQEBAwCMTQwDAYIKoEcz1UBg3UFAANIADBFAiBM4OVAc8aaCZU4XFfcVMkC7bWIIenRnPLxrnwVeYO3CQIhANQ767YIurkJCoLtwyqQPbUZe/+3BjGZcIWqB1mAl9T+",
"digestValue": "EW5//PlrSsuQ8pw+hRRtSsSDaN4=",
"signatureValue": "MeEiFDT6H6Sn/foR5zxKrl3g/i+fsCe2humDK6LA2E9ORvFxijpAILxXLezvUBIyqXmydu4BjFwAQk62+V1QtQ==",
"signatureNode": "<ds:SignedInfo xmlns:ceb=\"http://www.chinaport.gov.cn/ceb\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\"></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sm2-sm3\"></ds:SignatureMethod><ds:Reference URI=\"\"><ds:Transforms><ds:Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></ds:DigestMethod><ds:DigestValue>EW5//PlrSsuQ8pw+hRRtSsSDaN4=</ds:DigestValue></ds:Reference></ds:SignedInfo>"
"digestValue": "/uy5whbEnIhnrSkF7hSAJNm8ISI=",
"signatureValue": "uEG8qUT4NMS7g+QVJK6WdVQXlSK5n94PQJ+iGWec2cCyXfKh6Il2U+jmEq6nxWpoxCn3M0zNH7bICaoKrMpc6w==",
"signatureNode": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ds:SignedInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">\n <ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\"/>\n <ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sm2-sm3\"/>\n <ds:Reference URI=\"\">\n <ds:Transforms>\n <ds:Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/>\n </ds:Transforms>\n <ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/>\n <ds:DigestValue>/uy5whbEnIhnrSkF7hSAJNm8ISI=</ds:DigestValue>\n </ds:Reference>\n</ds:SignedInfo>"
}
}
```
@@ -104,7 +104,7 @@ curl -X GET -H 'x-auth-token-eport-sign:DefaultAuthToken' -i http://localhost:80
|└─signatureNode|string|XML报文的签名节点<br/><li>用来组装 ds:SignedInfo 节点</li>|-|
**Response-example:**
```json
```
{
"message": "操作成功",
"success": true,
@@ -163,6 +163,7 @@ Return void.
**Content-Type:** application/x-www-form-urlencoded;charset=UTF-8
**Description:**
<ul>
支持command类型
<li>RESTART: 重启控件(较多使用)</li>
@@ -223,6 +224,7 @@ curl -X POST -H 'x-auth-token-eport-sign:DefaultAuthToken' -i http://localhost:8
**Content-Type:** application/json
**Description:**
<ul>
<b>支持JSON报文和XML报文</b>
<li>JSON报文: 无需组装XML结构报文</li>
@@ -240,7 +242,7 @@ curl -X POST -H 'x-auth-token-eport-sign:DefaultAuthToken' -i http://localhost:8
| Parameter | Type | Required | Description | Since |
|-----------|------|----------|-------------|-------|
|messageType|enum|true|消息类型<br/>[Enum values:<br/>CEB311Message("CEB311Message")<br/>CEB621Message("CEB621Message")<br/>]|-|
|messageType|enum|true|消息类型<br/>[Enum values:<br/>CEB311Message("CEB311Message")<br/>CEB621Message("CEB621Message")<br/>CEB303Message("CEB303Message")<br/>]|-|
|dataType|enum|true|报文的数据类型<br/>[Enum values:<br/>JSON()<br/>XML()<br/>]|-|
|cebMessage|object|true|进口单、出口单的底层数据模型<br/><ul><br/>以CEB311Message数据类型为例<br/><li><br/><p>JSON示例</p><br/><pre><code><br/>{"order":{"orderHead":{"guid":"AFNC7T-WEASLEY-20230713095517-N04JEE","appType":"1","appTime":"20230704181028","appStatus":"2","orderType":"I","orderNo":"T_C5051511332138160010","ebpCode":"4601630004","ebpName":"海南省荣誉进出口贸易有限公司","ebcCode":"4601630004","ebcName":"海南省荣誉进出口贸易有限公司","goodsValue":"0.01","freight":"0","discount":"0","taxTotal":"0","acturalPaid":"0.01","currency":"142","buyerRegNo":"4","buyerName":"袁晓雨","buyerTelephone":"13701727375","buyerIdType":"1","buyerIdNumber":"130435200009241538","consignee":"袁晓雨","consigneeTelephone":"13701727375","consigneeAddress":"北京北京市东城区","note":"test"},"orderList":[{"gnum":1,"itemNo":"1","itemName":"LANNA兰纳","gmodel":"10片/包","itemDescribe":"","barCode":"1","unit":"011","qty":"1","price":"1","totalPrice":"1","currency":"142","country":"136","note":"test"}]},"guid":"AFNC7T-WEASLEY-20230713095517-N04JEE","version":"1.0","baseTransfer":{"copCode":"4601630004","copName":"海南省荣誉进出口贸易有限公司","dxpMode":"DXP","dxpId":"DXPENT0000530815","note":"test"}}<br/></code></pre><br/></li><br/><li><br/><p>XML示例: 不带ds:Signature节点的CEBXxxMessage.xml原文;<a href='http://tool.qdhuaxun.cn/ceb/CEB311Message.xml'>待加签xml报文样例</a></p><br/></li><br/></ul>|-|
@@ -316,8 +318,10 @@ curl -X POST -H 'Content-Type: application/json' -H 'x-auth-token-eport-sign:Def
**Content-Type:** application/json
**Description:**
<ul>
JSON示例:
<pre>
{
"sessionID": "032C3F56-0EE6-4558-B548-6C7A3451F07D",
@@ -564,4 +568,3 @@ curl -X POST -H 'Content-Type: application/json' -H 'x-auth-token-eport-sign:Def
}
```