海关跨境电商进口统一版信息化系统平台数据实时获取接口(试行) java版

海关总署公告:
http://www.customs.gov.cn/customs/302249/302266/302267/2134975/index.html 165号

http://www.customs.gov.cn/customs/302249/302266/302267/2155884/index.html 179号

这个接口对接已经懒得吐槽了,搞不懂一个技术文档怎么就写的这么官方!!!连个具体的sdk都没有!!!好了 我承认我有吐槽了。
现有的对接方法基本可看下网上的信息,可以了解80%
https://blog.csdn.net/u010955036/article/details/88712577
https://www.cnblogs.com/whtydn/p/10220209.html
尤其是第二个可以仔细看下 干货很多,流程也很细,唯一的缺点就是是用C#实现的报文,java的报文虽然有提及,但没有具体的实现方式,所以本文打算作一个补充说明。

  1. 加签验签会包含两个工具,一个html+js加签工具 主要是加密报文和获取序列号,由于给到海关需要数字证书,所以这个工具没啥用,可以略过。第二个,debug工具,非常有用,怎么用看上面第二链接文章,注意的一点,一定好在插IC卡的电脑启动工具,其次获取数字证书的时候依次打卡卡-》验证口令-》读取证书-》证书序列号就行了,***注意不需要浏览添加报文,和签名***我第一次在这个地方费了好久搞报文!!!
  2. 如果是C#写的可以按照第二篇文章第5步拼接报文,如果是java的就需要按照其他语言给的格式用webSocket发送报文,这也是我后面要实现的。
  3. 如果是java语言写的需要用到张弓写的webSocket实现类,具体可以下载:
    Java 张工版下载地址: https://pan.baidu.com/s/1beifsbtA7fXmi4vJ3c2Kjw 提取码: jdev
package omni.purcotton.omni.customs.api;import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.purcotton.omni.common.exception.CommonException;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
import omni.purcotton.omni.customs.config.CustomsConfig;
import omni.purcotton.omni.customs.feign.OrderService;
import omni.purcotton.omni.customs.feign.PayService;
import omni.purcotton.omni.customs.pojo.data.OrderItemVo;
import omni.purcotton.omni.customs.pojo.data.OrderMainVo;
import omni.purcotton.omni.customs.pojo.data.PayInfoVo;
import omni.purcotton.omni.customs.pojo.data.SignReqDTO;
import omni.purcotton.omni.customs.pojo.request.GoodsInfo;
import omni.purcotton.omni.customs.pojo.request.PayExInfoStr;
import omni.purcotton.omni.customs.pojo.request.PayExchangeInfoHead;
import omni.purcotton.omni.customs.pojo.request.PayExchangeInfoList;
import omni.purcotton.omni.customs.pojo.response.RealTimeDataUploadResponse;
import omni.purcotton.omni.customs.socket.WebCallback;
import omni.purcotton.omni.customs.socket.WebSocketClientHandle;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;/*** [简要描述]:<br/>* [详细描述]:<br/>*/
@Slf4j
@RestController
@RequestMapping("/api/customs/realtime")
@Log
public class RealTimeDataUploadApi
{@Autowiredprivate WebSocketClientHandle webSocketClientHandle;@Autowiredprivate OrderService orderService;@Autowiredprivate PayService payService;private static final Logger LOGGER = LoggerFactory.getLogger(RealTimeDataUploadApi.class);@Autowiredprivate CustomsConfig customsConfig;static Gson gson = new GsonBuilder().disableHtmlEscaping().create();@PostMapping(value = "/platDataOpen", headers = "content-type=application/x-www-form-urlencoded")public JSONObject platDataOpen(@RequestParam String openReq){openReq = StringUtils.replace(openReq, "&quot;", "\"");JSONObject jsonObject = JSONObject.parseObject(openReq);String orderNo = jsonObject.getString("orderNo");String sessionID = jsonObject.getString("sessionID");Long serviceTime = jsonObject.getLong("serviceTime");PayExInfoStr payExInfoStr = getPayExInfoStr(orderNo, sessionID, customsConfig);SignReqDTO signReqDTO = new SignReqDTO();signReqDTO.setKey(payExInfoStr.getSessionID());signReqDTO.setMessage(getSendData(payExInfoStr, customsConfig));LOGGER.info("入参-{}", signReqDTO);webSocketClientHandle.send(signReqDTO.getKey(), signReqDTO.getMessage(), new ImplWebCallback(payExInfoStr));JSONObject result = new JSONObject();result.put("code", "10000");result.put("message", "");result.put("serviceTime", System.currentTimeMillis());return result;}private void setPostData(PayExInfoStr payExInfoStr){CloseableHttpClient client = HttpClients.createDefault();URIBuilder uriBuilder = null;CloseableHttpResponse response = null;List<NameValuePair> nameValuePairList = new ArrayList<>();String json = gson.toJson(payExInfoStr);LOGGER.info("上传给海关的json:" + json);nameValuePairList.add(new BasicNameValuePair("payExInfoStr", json));try{uriBuilder = new URIBuilder(customsConfig.getRealTimeUrl());uriBuilder.addParameters(nameValuePairList);HttpPost httpPost = new HttpPost(uriBuilder.build());httpPost.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));try{response = client.execute(httpPost);int statusCode = response.getStatusLine().getStatusCode();if (statusCode == 200){HttpEntity entity = response.getEntity();String result = EntityUtils.toString(entity, "UTF-8");RealTimeDataUploadResponse responseData = gson.fromJson(result, RealTimeDataUploadResponse.class);LOGGER.info(gson.toJson(responseData));}}catch (IOException e){e.printStackTrace();}}catch (URISyntaxException e){e.printStackTrace();}}public static String getSignJson(PayExInfoStr payExInfoStr){StringBuilder buff = new StringBuilder();buff.append("\"sessionID\"").append(":").append("\"" + payExInfoStr.getSessionID() + "\"").append("||");buff.append("\"payExchangeInfoHead\"").append(":").append("\"" + gson.toJson(payExInfoStr.getPayExchangeInfoHead()) + "\"").append("||");buff.append("\"payExchangeInfoLists\"").append(":").append("\"" + gson.toJson(payExInfoStr.getPayExchangeInfoLists()) + "\"").append("||");buff.append("\"serviceTime\"").append(":").append("\"" + payExInfoStr.getServiceTime() + "\"");LOGGER.info("加签准备报文:-------" + buff.toString());return buff.toString();}public static String getSendData(PayExInfoStr payExInfoStr, CustomsConfig customsConfig){LinkedHashMap<String, Object> map = new LinkedHashMap<>();Map<String, String> data = new HashMap<>(16);map.put("_method", "cus-sec_SpcSignDataAsPEM");map.put("_id", 1);data.put("inData", getSignJson(payExInfoStr));data.put("passwd", customsConfig.getPassword());map.put("args", data);return gson.toJson(map);}private PayExInfoStr getPayExInfoStr(String orderNo, String sessionID, CustomsConfig customsConfig){OrderMainVo orderMainVo = orderService.find(orderNo);if (orderMainVo == null){LOGGER.info("订单:" + orderNo + "查询不到订单信息");throw new CommonException(201, "订单:" + orderNo + "查询不到订单信息");}PayInfoVo payInfoVo = payService.getPayInfo(orderNo);if (payInfoVo == null){LOGGER.info("订单:" + orderNo + "查询不到支付信息");throw new CommonException(201, "订单:" + orderNo + "查询不到支付信息");}//todo 拼接报文信息PayExInfoStr payExInfoStr = new PayExInfoStr();payExInfoStr.setSessionID(sessionID);PayExchangeInfoHead payExchangeInfoHead = new PayExchangeInfoHead();payExchangeInfoHead.setGuid(UUID.randomUUID().toString());payExchangeInfoHead.setInitalRequest(payInfoVo.getInitalRequest());payExchangeInfoHead.setInitalResponse(payInfoVo.getInitalResponse());payExchangeInfoHead.setEbpCode(customsConfig.getEbpEntNo());payExchangeInfoHead.setPayCode(customsConfig.getPayCode());payExchangeInfoHead.setPayTransactionId(payInfoVo.getPayTransactionId());payExchangeInfoHead.setTotalAmount(payInfoVo.getTotalAmount().doubleValue());payExchangeInfoHead.setCurrency("142");payExchangeInfoHead.setVerDept("3");payExchangeInfoHead.setPayType("3");payExchangeInfoHead.setTradingTime(DateUtil.format(payInfoVo.getTradingTime(), DatePattern.PURE_DATETIME_PATTERN));payExchangeInfoHead.setNote("");payExInfoStr.setPayExchangeInfoHead(payExchangeInfoHead);PayExchangeInfoList payExchangeInfoList = new PayExchangeInfoList();payExchangeInfoList.setOrderNo(orderNo);List<OrderItemVo> orderItemVos = orderMainVo.getOrderItemVos();List<GoodsInfo> goodsInfos = new ArrayList<>();for (OrderItemVo orderItemVo : orderItemVos){GoodsInfo goodsInfo = new GoodsInfo();goodsInfo.setGname(orderItemVo.getProductName());goodsInfo.setItemLink(orderItemVo.getImagePath());goodsInfos.add(goodsInfo);}payExchangeInfoList.setGoodsInfo(goodsInfos);payExchangeInfoList.setRecpAccount(customsConfig.getRecpAccount());payExchangeInfoList.setRecpCode(customsConfig.getRecpCode());payExchangeInfoList.setRecpName(customsConfig.getRecpName());List<PayExchangeInfoList> payExchangeInfoLists = new ArrayList<>();payExchangeInfoLists.add(payExchangeInfoList);payExInfoStr.setPayExchangeInfoLists(payExchangeInfoLists);payExInfoStr.setServiceTime(System.currentTimeMillis());payExInfoStr.setCertNo(customsConfig.getCertNo());return payExInfoStr;}class ImplWebCallback implements WebCallback{PayExInfoStr payExInfoStr;public ImplWebCallback(PayExInfoStr payExInfoStr){this.payExInfoStr = payExInfoStr;}@Overridepublic void message(String key, Object param){LOGGER.info("key-{}, message-{}", key, param);String signValue = null;if (!StringUtils.isEmpty(param)){JSONObject jsonObject = JSON.parseObject(String.valueOf(param));Integer id = jsonObject.getInteger("_id");if (id != null && id == 1){JSONObject args = jsonObject.getJSONObject("_args");JSONArray data = args.getJSONArray("Data");signValue = data.getString(0);LOGGER.info("key-{}, signValue-{}", key, signValue);payExInfoStr.setSignValue(signValue);setPostData(payExInfoStr);}}// todo 放入处理队列}@Overridepublic void error(Object param){LOGGER.info("error-{}", param);}}
}

上面接口是经过修改联调后的最终版,最关键的报文拼接和websocket发送机制,大家可以参考一下,避免躺坑。

补充说明:
上面的代码经过测试有两个问题,现在修复如下:
1、CustomsConfig 是一个自定义配置信息,相关的海关参数配置都包含在里面,涉及系统敏感信息就不贴了
2、海关给出的报文属性是payExchangeInfoList!!!注意是错的 应该是payExchangeInfoLists,需要加s.

海关跨境电商进口统一版信息化系统平台数据实时获取接口(试行) java版相关推荐

  1. 东南亚跨境电商为什么推荐ERP仓储系统?

    东南亚跨境电商为什么推荐ERP仓储系统? 跨境电商ERP软件是一款智能采集系统,全网采集可以为商家提供高效的网络服务,能帮商家节省大量的时间和减少繁琐的工作,上传亚马逊是需要翻译成不同国家的语言的,如 ...

  2. 星卓越货代系统,东南亚跨境电商必备的物流服务系统

    之前的文章中有讲到,如今东南亚市场发展迅速,商家投身这片蓝海市场在Shopee和Lazada平台开店运营,但其中有一个难题,就是物流问题,长此以往会对商家店铺发展造成巨大的影响,而市场上许多物流公司或 ...

  3. 跨境电商自建站后台系统原型rp_Shoptago---跨境电商平台又一个新选择

    在去年邀请2000卖家参与内测的跨境电商自建站平台Shoptago,现在用户数已经达到了3850+,成绩可谓,我们也能在各大媒体看到Shoptago相关的新功能上线公告,那么在这段时间里,Shopta ...

  4. 跨境电商为什么要用ERP系统?

    1.为什么要用ERP 对于跨境电商而言,多平台.多账号运作是比较常见的方式.但这种操作模式会给卖家们带来很多难题: 大量的SKU需要快速地刊登到不同平台.不同账号,不同站点,人工上传不仅速度慢,人工成 ...

  5. 跨境电商ERP中的自动化 1.平台订单自动同步至本地

    比较主流的跨境电商平台,包括速卖通.Shopee.Wish.亚马逊等.如果你的订单量不多,完全可以在店铺后台操作,但如果订单达到几百上千的时候,就要借助平台提供的API,把订单下载到第三方的ERP里, ...

  6. 跨境电商自建站后台系统原型rp_外贸业务员和跨境电商运营哪个好,跨境电商可以去哪个网站学...

    我做跨境电商也有六年的时间了,在电商这个行业也有自己的一些经验.经验也许没有其他大卖家丰富,但会将我知道的都进行分享.如果有不懂得亚马逊问题可以+我(V:543482465).我这里给大家安排一堂直播 ...

  7. 跨境电商自建站后台系统原型rp_没学历做跨境电商好做吗?虾皮shopee开店没有流水怎么办...

    (shopee)虾皮刚诞生的时候我就做了,在电商这个行业也有自己的一些经验.经验也许没有其他大卖家丰富,但会将我知道的都进行分享.如果有不懂(shopee)虾皮问题可以+我(V:2787823020) ...

  8. 跨境电商,独立站和第三方平台孰更具优势?

    随着云计算.大数据.人工智能等互联网技术的发展,全球贸易环境变化,正在进入数字化.信息化.互联网化的 "新贸易"时代.全球贸易呈现更扁平.更便捷.更智能的趋势.同时,全球消费水平的 ...

  9. 适合跨境电商亚马逊专业货源平台有哪些?

    亚马逊电商平台是面向全球的电商市场,也是全球最大的电商平,但对于做跨境电商刚入门的小伙伴来说,前期单量不多自备货不现实,如果一开始就自备货会面临囤货及消耗时间的问题. 初期运营亚马逊建议用学习的心态对 ...

最新文章

  1. android崩溃日志收集
  2. 学生档案管理系统(续)
  3. HDU3662(求三维凸包表面的多边形个数,表面三角形个数,体积,表面积,凸包重心,凸包中点到面的距离)
  4. Expression Blend实例中文教程(3) - 布局控件快速入门Grid
  5. Kotlin 接口(三)
  6. markdown 文档转 word
  7. 数据库系统概论第五版_第九章:关系查询处理和查询优化
  8. Pycharm 搭建 Django 项目 (非常详细)
  9. opencore 0.6.3 华硕_钜惠嗨翻双11,颜值优选华硕GT501白色狙击手机箱
  10. Lucene+Pangu分词
  11. 树莓派用root登陆_树莓派开启root用户权限
  12. 性别 图标 css,CSS实现小图标
  13. 什么是基本的逻辑运算?
  14. 信号调理方法总结笔记
  15. 自定义类型:结构体,枚举,联合
  16. 连续数值变量的离散化、哑变量
  17. scriptx.cab下载
  18. “新闻拉盘币”Enjin背后到底有没有干货
  19. Android 领券联盟:记录RecyclerView的使用
  20. LocalDateTime获取当前时间戳

热门文章

  1. Office 2021 简体中文 正式版 零售版 32位和64位 官方镜像下载合集
  2. 如何搜索百度云盘里的文件
  3. 使用MNM(Microsoft Network Monitor)抓包
  4. PhotoShop彩色图片打印机只有四中颜色操作步骤:
  5. 在线创建LaTeX表格的方法
  6. 银行招聘考试计算机题,银行招聘考试:计算机模拟试题(七)答案
  7. vue+echarts GL3d中国地图
  8. python 实现三维向量之间的夹角
  9. 查看进程及结束进程命令
  10. 药店管理系统源码 药店管理信息系统源码带文档