【快递100】快递时效接口获取快递预计到达时间

本文讲述了在面临公司需要实现快递预计到达时间接口,但采购部门不愿维护出发城市和目的城市信息的情况下,如何通过已有推送接口获取揽收时间,并结合供应商和客户地址信息推断出发城市和目的城市,从而实现接口功能。文章详细描述了解决方案的实施过程,包括接口调用和数据处理逻辑。
摘要由CSDN通过智能技术生成

需求分析

目前公司上线了快递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,接口编号,加密签名都可以在后台获取到。

在这里插入图片描述

service代码

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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值