赞
踩
目前公司上线了快递100的推送接口,现在需要做一个快递预计到达时间接口。
该接口主要是为了对签收和仓库人员进行月末考核,比如某个快递15号就签收,但是20号才入库,这属于失职,应当被处罚。
但是公司的快递单均由采购部门维护,他们觉得维护快递单号和快递所属公司已经很麻烦了,不愿意再去维护出发城市(formCity)和目的城市(toCity)(快递时效明细查询时需要用到这两个字段)
这就给后台开发增加了难度。
原本设想的是,再sys_express中录入维护出发城市(formCity)和目的城市(toCity),这样每次检测到这些快递单,就会自动去快递100查询预计到达时间。
后来发现这个方案不可行。
因为这个快递时效明细接口还需要快递的下单时间,假如一个快递时早上8:00下单的,但是采购部一直到下午17:00快下班的时候,才想起来录入该快递单。
此时就需要采购部人员记住每个快递单的下单时间,而且最好是下单后就立即录入,但这是不现实的,采购部的工作比较忙,很容易忘记,更何况快递单量太多,很容易疏忽。
后来我想到了一个解决办法。
我们之前上线的推送接口,它推送的快递物流轨迹信息,可以获取到快递的揽收时间,这个时间才是正确的下单时间。
我问过快递100的客服,一个快递8:00下单,16:00才正式揽收,哪个算下单时间(快递员8:00收单,但是又去别的地方收单,一直到下午4点才回到快递站点,由快递车运走。)
从接口层面,揽收时间才是快递真正上路的时间。
(在双11大促时间,11月11日下单,很可能11月14号才开始揽收,如果预计两天内到达,很可能都已经预计到达了,结果快递还没发货)
这就解决了下单时间的问题(orderTime由推送接口提供,在推送接口第一次推送时获取,同时出发快递100时效明细接口查询)
可是,出发城市(formCity)和目的城市(toCity)还是无法获取,怎么办呢?
想了半天,发现我们的供应商信息和客户信息,都是是维护在系统中的,我们知道供应商和客户的信息,自然就知道了他们的地址,也就变相知道了出发城市或者目的城市。
至于出发城市(formCity)和目的城市(toCity),只需要一个简单的判断就搞定了。
业务场景已经理清,接下来就是写代码了。
官方文档: https://cloud.kuaidi100.com/platform/productdetail/32164353135.shtml
V1接口是查询单个快递公司,V2是查询快递公司列表。
V2精确到小时级别,但是它有个BUG,请求参数中的com,应该是companyList(说多了都是累)。
不知道快递100的维护人员为什么没有更改这个错误,可能是因为这个接口用的人比较少吧。
tips:请求参数中的授权key,接口编号,加密签名都可以在后台获取到。
SysExpressServiceImpl.java
/**
* 业务处理
* @param param 返回的参数
* @param backResp
*/
@Transactional
public void handleResponse(String param,SubscribePushParamResp backResp) throws Exception {
// 每次推送的报文,都要入库,方便出问题后排查
String expressNum = backResp.getLastResult().getNu();
SysExpressData expressData = new SysExpressData();
expressData.setExpressNum(expressNum);
expressData.setReceiveText(param);
expressData.setType("1");
expressData.setStatus("0");
expressDataMapper.insertSysExpressData(expressData);
// 业务处理
SysExpress express = expressMapper.selectSysExpressByNum(expressNum);
// 更新主表状态
if("abort".equals(backResp.getStatus().trim())){
//当message为“3天查询无记录”或“60天无变化时”status= abort,处理逻辑是重新订阅推送服务
express.setRemark("status= abort,重新订阅推送服务");
List<SysExpress> expressList = new ArrayList<>();
expressList.add(express);
subscribe(expressList);
}
// shutdown说明快递被签收,推送服务中止
if("shutdown".equals(backResp.getStatus().trim())){
express.setStatus(3L);
expressMapper.updateSysExpress(express);
}
// 获取data数据集,解析后存入数据库
List<SubscribePushData> dataList = backResp.getLastResult().getData();
if(dataList != null && dataList.size() >0){
if (StringUtils.isEmpty(express.getArriveTime())) {
//arriveTime为null,说明还没有调用接口获取预计到达时间
if(StringUtils.isNotEmpty(express.getFromCity()) && StringUtils.isNotEmpty(express.getToCity())){
// fromCity和toCity不为空,说明是后录入的快递单
Map<String, String> paramMap = new HashMap<>();
paramMap.put("secret_key", secretKey);
paramMap.put("secret_code", secretCode);
// secretSign = SignUtils.sign(key+secretSecret)
paramMap.put("secret_sign", secretSign);
paramMap.put("from", express.getFromCity());
paramMap.put("to", express.getToCity());
paramMap.put("companyList", express.getCompanyCode());
paramMap.put("orderTime", dataList.get(dataList.size()-1).getFtime());
String sendText = new Gson().toJson(paramMap);
String response = getExpressVo(paramMap);
handleResponseAndSaveArriveTime(sendText, response, express);
}
}
List<SysExpressInfo> infoList = new ArrayList<>();
for (SubscribePushData data : dataList) {
SysExpressInfo info = new SysExpressInfo();
info.setCompanyCode(backResp.getLastResult().getCom());
info.setContext(data.getContext());
info.setExpressNum(expressNum);
info.setStatus(data.getStatus());
info.setTime(DateUtils.getUTCTime(data.getFtime()));
infoList.add(info);
}
if(infoList.size() > 0){
// 入库操作前,先删除sys_express_info表中的数据,只保留最新数据。
expressInfoMapper.deleteSysExpressInfoByNum(expressNum);
expressInfoMapper.insertSysExpressBatch(infoList);
}
}
}
/**
* 获取快递时效接口
* @param params
* @return
*/
public String getExpressVo(Map<String, String> params) throws IOException {
StringBuilder response = new StringBuilder("");
BufferedReader reader = null;
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, String> param : params.entrySet()) {
if (builder.length() > 0) {
builder.append('&');
}
builder.append(URLEncoder.encode(param.getKey(), "UTF-8"));
builder.append('=');
builder.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
byte[] bytes = builder.toString().getBytes("UTF-8");
URL url = new URL(arriveUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(3000);
conn.setReadTimeout(3000);
conn.setRequestMethod("POST");
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", String.valueOf(bytes.length));
conn.setDoOutput(true);
conn.getOutputStream().write(bytes);
reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String line = "";
while((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
}
/**
* @param sendText 快递明细接口发送报文
* @param response 快递明细接口返回报文
* @param express 快递实体类
*/
private void handleResponseAndSaveArriveTime(String sendText,String response,SysExpress express) {
// 快递时效明细的返回报文,入库操作
SysExpressData expressData = new SysExpressData();
expressData.setExpressNum(express.getExpressNum());
expressData.setSendText(sendText);
expressData.setReceiveText(response);
expressData.setType("2");
expressData.setStatus("0");
expressDataMapper.insertSysExpressData(expressData);
ExpressVo expressVo = new Gson().fromJson(response, ExpressVo.class);
if ("200".equals(expressVo.getReturnCode())) {
express.setArriveTime("预计到达时间缺失");
// 200说明数据返回成功
List<ExpressSupportResult> data = expressVo.getData();
if(data != null && data.size() > 0){
// 说明支持该快递
String arriveTime = data.get(0).getArrivalTime();
express.setArriveTime(arriveTime);
}else{
// TODO 不支持的快递公司可以入库,下次不再调用该接口
}
expressMapper.updateSysExpress(express);
}
}
快递时效明细实体类:ExpressVo
@Data
public class ExpressVo {
/**出发地*/
private String fromName;
/**出发地编码*/
private String fromNum;
/**目的地*/
private String toName;
/**目的地编码*/
private String toNum;
/**下单时间*/
private String orderTime;
/**返回状态码 200代表成功*/
private String returnCode;
private boolean result;
/**返回信息(成功,失败,签名验证失败等)*/
private String message;
/**各快递公司统计时间信息*/
private List<ExpressSupportResult> data;
}
快递预计到达时间结果集:ExpressSupportResult
@Data
public class ExpressSupportResult {
/**快递公司编码*/
private String com;
/**平均耗时*/
private String totalAvg;
/**业务类型10:普通,20:快,30:特快*/
private String type;
/**预测到达时间*/
private String arrivalTime;
/**预测出发时间*/
private String startTime;
/**预计花费时间*/
private String mayExpendTime;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。