代码借鉴海关179对接API.(如有侵权马上删除)
步骤- 拿到ukey(运营或产品哪里应该会有)
- 获取开发文档179号开发文档
- 开发接收海关请求接口(按文档要求不能有端口号)
- 组装数据进行加签
- 拼接加签数据上报
- 完成
以上文档等不多介绍主要是开发(身为CV工程师直接上代码)
接收海关请求
接收海关请求并存储请求(因为加签需要在本地而接收请求要在开放服务器所以使用mq传输数据)
@PostMapping(value = "/platDataOpen")
@ResponseBody
public JSONObject platDataOpen(@RequestParam String openReq){
//解析获取数据
openReq = StringUtils.replace(openReq, """, """);
JSONObject jsonObject = JSONObject.parseObject(openReq);
String orderNo = jsonObject.getString("orderNo");
String sessionID = jsonObject.getString("sessionID");
Long serviceTime = jsonObject.getLong("serviceTime");
System.out.println(orderNo+sessionID+serviceTime);
//查询是否有订单
String source = customsService.insertCustoms(orderNo,sessionID,serviceTime);
JSONObject result = new JSONObject();
if (source.equals("10000")){
result.put("code", "10000");
result.put("message", "");
}else{
result.put("code", "205");
result.put("message", "没有此订单");
}
result.put("serviceTime", System.currentTimeMillis());
return result;
}
@Resource
RabbitTemplate rabbitTemplate;
@Override
public String insertCustoms(String orderNo, String sessionID, Long serviceTime) {
logger.info("海关抽查订单"+orderNo);
OmsOrderExample omsOrderExample = new OmsOrderExample();
omsOrderExample.createCriteria().andOrderSnEqualTo(orderNo);
List omsOrders = omsOrderMapper.selectByExample(omsOrderExample);
//判断是否有指定订单
if(omsOrders.size()>0){
//查询是否存在订单号
PaycheckExample example = new PaycheckExample();
example.createCriteria().andOrderNoEqualTo(orderNo);
List paychecks = paycheckMapper.selectByExample(example);
if(paychecks.size()>0){
paychecks.get(0).setSessionId(sessionID);
int num = paycheckMapper.updateByPrimaryKey(paychecks.get(0));
if(num>0){
System.out.println("修改成功");
}
}else{
Paycheck paycheck = new Paycheck();
paycheck.setOrderNo(orderNo);
paycheck.setSessionId(sessionID);
paycheck.setAddTime(new Date());
paycheck.setStatus((byte) 0);
paycheck.setBackTime(new Date());
int num = paycheckMapper.insert(paycheck);
if (num>0){
System.out.println("添加成功");
}
}
logger.info("发送消息到CUSTOMS_EXPORT_QUEUE");
rabbitTemplate.convertAndSend(DirectRabbitConfig.CUSTOMS_EXPORT_EXCHANGE,DirectRabbitConfig.CUSTOMS_EXPORT_ROUTING,orderId);
//webscoketTest(orderNo);
return "10000";
}
return "205";
}
创建实体类存放数据
import lombok.Data;
import java.util.List;
@Data
@JSONType(orders={"sessionID","payExchangeInfoHead","payExchangeInfoLists","serviceTime","certNo","signValue"})
public class HaiguanVO {
//@JSONType很重要作用就是JSON化的时候数据的排序
//@JSonType(orders={"sessionID","payExchangeInfoHead","payExchangeInfoLists","serviceTime","certNo","signValue"})
public String sessionID;
public PayExchangeInfoHead payExchangeInfoHead;
public List payExchangeInfoLists;
public String serviceTime;
public String certNo;
public String signValue;
}
package com.example.customsspotcheck.vo;
import com.alibaba.fastjson.annotation.JSONType;
import lombok.Data;
@Data
@JSONType(orders={"guid","initalRequest","initalResponse","ebpCode","payCode","payTransactionId","totalAmount","currency","verDept","tradingTime"})
public class PayExchangeInfoHead {
public String guid;
public String initalRequest;
public String initalResponse;
public String ebpCode;
public String payCode;
public String payTransactionId;
public Double totalAmount;
public String currency;
public String verDept;
//public String payType;
public String tradingTime;
//public String note;
}
package com.example.customsspotcheck.vo;
import com.alibaba.fastjson.annotation.JSONType;
import lombok.Data;
import java.util.List;
@Data
@JSONType(orders={"orderNo","goodsInfo","recpAccount","recpCode","recpName"})
public class PayExchangeInfoLists {
public String orderNo;
public List goodsInfo;
public String recpAccount;
public String recpCode;
public String recpName;
}
package com.example.customsspotcheck.vo;
import com.alibaba.fastjson.annotation.JSONType;
import lombok.Data;
@Data
@JSONType(orders={"gname","itemlink"})
public class goodsInfo {
public String gname;
public String itemlink;
}
以上是全部的实体类(通过自己的情况查询数据添加即可)
接下来是加签
加签是获取signValue海关会验签
加签有js加签 websocket加签 (本人纯后端前端不太会所以使用websocket加签)
websocket加签要有一个操作员的卡(一个U盘)
插入后启动
就会在本地开放两个个websocket服务
请求地址:
ws://127.0.0.1:61232
wss://wss.singlewindow.cn:61231
编写websocket加签代码
首先组装数据
package com.example.customsspotcheck.service.impl;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import com.alibaba.fastjson.JSONObject;
import com.example.customsspotcheck.mapper.PaycheckDao;
import com.example.customsspotcheck.service.HaiguanService;
import com.example.customsspotcheck.util.HaiguanSign;
import com.example.customsspotcheck.vo.HgCheckVO;
import org.apache.http.Consts;
import org.apache.http.HttpStatus;
import org.apache.http.NamevaluePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNamevaluePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
@Service
public class HaiguanServiceImpl implements HaiguanService {
@Resource
HaiguanSign haiguanSign;
@Value(value = "${spring.customs.haiguan.certNo}")
private String certNo;
@Value(value = "${spring.customs.haiguan.password}")
private String password;
@Value(value = "${spring.customs.haiguan.uploadUrl}")
private String uploadUrl;
@Resource
PaycheckDao paycheckDao;
@Override
public void repDataApply(HgCheckVO entity) {
StringBuffer sb = new StringBuffer();
sb.append(""sessionID":"").append(entity.getSessionID()).append(""").append("||");
String headerString = JSON.toJSONString(entity.getPayExchangeInfoHead(), SerializerFeature.SortField);
sb.append(""payExchangeInfoHead":"").append(headerString).append(""").append("||");
String listString = JSON.toJSONString(entity.getPayExchangeInfoLists(), SerializerFeature.SortField);
sb.append(""payExchangeInfoLists":"").append(listString).append(""").append("||");
sb.append(""serviceTime":"").append(entity.getServiceTime()).append(""");
String signValue = sb.toString();
//组装加签数据
Map args = new java.util.HashMap<>();
args.put("inData", signValue);
args.put("passwd", password);
JSONObject epdata = new JSONObject(true);
epdata.put("_method", "cus-sec_SpcSignDataAsPEM");
epdata.put("_id", 1);
epdata.put("args", args);
//加签(使用websocket加签)
haiguanSign.sign(epdata,entity);
}
@Override
public void shangbao(HgCheckVO entity) {
//吧获取到的全部数据转JSON然后上报给海关
System.out.println("---海关179数据上报数据:payExInfoStr=" + JSON.toJSONString(entity));
try {
List param = new ArrayList();
//组装数据
param.add(new BasicNamevaluePair("payExInfoStr", JSON.toJSONString(entity)));
CloseableHttpClient client = getHttpsClient();
HttpPost post = new HttpPost(uploadUrl);
post.setEntity(new UrlEncodedFormEntity(param,Consts.UTF_8));
try {
CloseableHttpResponse xx = client.execute(post);
if(HttpStatus.SC_OK == xx.getStatusLine().getStatusCode()) {
String result = EntityUtils.toString(xx.getEntity(), Consts.UTF_8);
System.out.println("---海关179数据上报结果:" + result);
//解析返回数据表
Map mapType = JSON.parseObject(result,Map.class);
//获取订单id
String OederSn = entity.getPayExchangeInfoLists().get(0).getOrderNo();
System.out.println(mapType.get("code"));
if(mapType.get("code").equals("10000")){
System.out.println("上传成功:"+OederSn);
//修改上报状态
paycheckDao.updatePaycheck(OederSn,1);
}else{
System.out.println("上传失败:"+OederSn);
//修改上报状态
paycheckDao.updatePaycheck(OederSn,2);
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}catch (Exception e){
}
}
private static CloseableHttpClient getHttpsClient(){
SSLConnectionSocketFactory sslsf = null;
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
@Override
public void verify(String host, SSLSocket ssl) throws IOException {
}
@Override
public void verify(String host, X509Certificate cert) throws SSLException {
}
@Override
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
}
});
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
}
}
package com.example.customsspotcheck.util;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.example.customsspotcheck.service.HaiguanService;
import com.example.customsspotcheck.vo.HgCheckVO;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import javax.annotation.Resource;
@Service
public class HaiguanSign {
private static final Logger LOGGER = (Logger) LoggerFactory.getLogger(HaiguanSign.class);
public static final Integer TIME_OUT = 3 * 60 * 1000;
public static final Integer TIME_STEP = 10;
@Value(value = "${spring.customs.haiguan.sign.wsUrl}")
private String wsUrl;
@Value(value = "${spring.customs.haiguan.certNo}")
private String certNo;
@Resource
HaiguanService haiguanService;
private Map clientPool = new HashMap<>();
public String sign(JSONObject value, HgCheckVO entity) {
System.out.println("请求加签报文->" + value);
WebSocketClient client = clientPool.get(wsUrl);
if (client != null && client.isConnecting() && client.isOpen()) {
client.send(String.valueOf(value));
} else {
try {
client = new WebSocketClient(new URI(wsUrl)) {
@Override
public void onOpen(ServerHandshake shake) {
// TODO Auto-generated method stub
System.out.println("握手...");
for (Iterator it = shake.iterateHttpFields(); it.hasNext();) {
String key = it.next();
System.out.println(key + "->" + shake.getFieldValue(key));
}
}
@Override
public void onMessage(String message) {
// TODO Auto-generated method stub
if (!StringUtils.isEmpty(message)) {
System.out.println("接收到消息:" + message);
JSONObject jsonObject = JSON.parseObject(String.valueOf(message));
Integer id = jsonObject.getInteger("_id");
if (id != null && id == 0) {
System.out.println("根据海关ws报文,第一次回复为握手通知,并非'加签'信息!");//第一次(id=0)
} else if (id != null && id == 1) {
JSONArray data = jsonObject.getJSONObject("_args").getJSONArray("Data");
String signValue = data.getString(0);
entity.setCertNo(certNo);
entity.setSignValue(signValue);
//上报数据
haiguanService.shangbao(entity);
}
}
}
@Override
public void onClose(int code, String reason, boolean remote) {
// TODO Auto-generated method stub
System.out.println("-----------close()");
}
@Override
public void onError(Exception ex) {
// TODO Auto-generated method stub
System.out.println("-----------onError:"+ex.getMessage());
}
};
} catch (URISyntaxException e) {
e.printStackTrace();
System.out.println("--------->websocket client exception.");
}
client.connect();
Integer count = 0;
// 阻塞等待OPEN
while (!client.getReadyState().equals(WebSocket.READYSTATE.OPEN)) {
try {
count += TIME_STEP;
Thread.sleep(TIME_STEP);
if (count >= TIME_OUT) {
LOGGER.info("error-{}", new Exception("WS服务器连接超时!或服务器已经关闭"));
break;
}
} catch (InterruptedException e) {
LOGGER.error("发送信息异常-{}", e);
}
}
client.send(String.valueOf(value));
// 放入缓存
clientPool.put(wsUrl, client);
}
return "";
}
}
以上就是海关179对接如有疑问可以留言(海关179对接过最坑的没有之一)



