当前位置:   article > 正文

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

快递100博客

需求分析

目前公司上线了快递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);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142

快递时效明细实体类: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;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

快递预计到达时间结果集: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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/549015
推荐阅读
相关标签
  

闽ICP备14008679号