工具类|快递物流的订阅与查询

快递物流

Posted by Claire on May 31, 2023

可以采用比较产品化的接口:快递100、聚合数据、51Tracking、快递鸟等专业的物流信息接口API。

也可以在阿里云云市场中寻找其他公司提供的一些简单的API或者推送服务。主要是取决于你的性能与量级的要求,再综合考虑预算与售后支撑。

这边考虑到我们是做自己小批量实物订单的追踪,每月1K的量级,所以就简单考虑在阿里云云市场上找一个合适的性价比较高的API。

在云市场的产品,也是提供了便捷明确的文档,可以购买后获取API直接粘贴DEMO直接使用,售后通过云市场产品购买的入口就可以联系到卖方工程师,基本响应都很快,专人对接,问题能够快速被解决。

一、快递物流订阅接口

场景:及时性要求高,期望尽快获取最新物流明细 使用:提交单号的订阅任务,提供回调接口,即可获取最新的物流节点信息

基础配置:

logistics.subscribeHost=https://jumexpress.market.alicloudapi.com
logistics.subscribePath=/express/logistics/subscribe
logistics.subscribeMethod=POST
logistics.subscribeAppcode=**自己的code**

配置类:

@Data
@EnableConfigurationProperties
@Component
@ConfigurationProperties(prefix = "logistics")
public class LogisticsConfig {
    private static String DEFAULT_SUBSCRIBE_HOST = "https://jumexpress.market.alicloudapi.com";
    private static String DEFAULT_SUBSCRIBE_PATH = "/express/logistics/subscribe";
    private static String DEFAULT_METHOD = "POST";

    private String subscribeHost = DEFAULT_SUBSCRIBE_HOST;
    private String subscribePath = DEFAULT_SUBSCRIBE_PATH;
    private String subscribeMethod = DEFAULT_METHOD;
    private String subscribeAppcode;
}

提交任务与回调:

@Slf4j
@RestController
@RequestMapping("/logistics/subscribe")
public class CallbackController {
    @Autowired
    private LogisticsConfig config;

    @GetMapping("submit")
    public String submitTask(@RequestParam String number) {
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Authorization", "APPCODE " + config.getSubscribeAppcode());
        //根据API的要求,定义相对应的Content-Type
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>();
        Map<String, String> bodys = new HashMap<String, String>();
        bodys.put("callBackUrl", "http://127.0.0.1:8080/logistics/callback");
//        bodys.put("expressCode", "YTO");   //可选,快递公司编号 例如圆通:YTO,详见产品说明中:快递公司编码对照表 注意:快递公司编号不传时,系统会自动识别快递公司编号,但响应时间会比传递快递编号略长
//        bodys.put("mobile", "mobile");  //看快递公司,顺丰速运/丰网速运需要传入收/寄件人手机号或后四位手机号
        bodys.put("number", number);//必选,快递运单号
        String result = "";
        try {
            HttpResponse response = HttpUtils.doPost(config.getSubscribeHost(), config.getSubscribePath(), config.getSubscribeMethod(), headers, querys, bodys);
            log.info(response.toString());
            result = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            log.info(result);
        } catch (Exception e) {
            log.error("err", e);
        }
        return result;
    }

    /**
     * {
     * "expressCode":"EMS", // 快递公司编号 详见:快递公司编码对照表
     * "number":"9796578035309",// 运单编号
     * "logisticsStatus":"SIGN", // 当前最新物流状态 详见:物流状态编码对照表
     * "logisticsStatusDesc":"已签收", // 当前最新物流状态描述
     * "details":[ // 完整的物流轨迹
     * {
     * "time":1632123146000, // 物流变更时间
     * "logisticsStatus":"ACCEPT", // 物流状态 详见:物流状态编码对照表
     * "subLogisticsStatus":"ACCEPT", // 物流子状态 详见:物流状态编码对照表
     * "desc":"【杭州电商仓配揽投部】已收寄,揽投员:刘岭,电话:13754324900", //物流路由信
     * 息描述内容
     * "areaCode":"CN330100000000", // 路由节点所在地区行政编码
     * "areaName":"浙江省,杭州市" // 路由节路由节点所在地区
     * },
     * {
     * "time":1632140994000,
     * "logisticsStatus":"TRANSPORT",
     * "subLogisticsStatus":"TRANSPORT",
     * "desc":"离开【杭州电商仓配揽投部】,下一站【杭州萧山区东片集散中心】",
     * "areaCode":"CN330100000000",
     * "areaName":"浙江省,杭州市"
     * },
     * ...
     * ]
     * }
     * <p>
     * {
     * "success":true
     * }
     * // 接收失败
     * {
     * "success":false,
     * "msg": "接收失败"  //自动失败重试,最多推送 3 次。如有疑问可工单联系工程师手动解决
     * }
     */
    @GetMapping("callback")
    public Map<String, Object> receive(@RequestBody String data, HttpServletRequest request) {
        log.info("接收到快递物流推送数据: {}", data);
        Map<String, Object> map = new HashMap<>();
        //处理业务逻辑
        Boolean result = Math.random() > 0.5;
        if (result) {
            map.put("success", true);
        } else {
            map.put("success", false);
            map.put("msg", "接收失败, 业务处理失败");
        }
        return map;
    }
}

二、快递物流查询接口

场景:及时性要求低,可主动发起查询,价格相对低,成本可控 使用:提交单号进行查询,反馈最新的物流信息

基础配置:

logistics.queryHost=https://jmexpresv2.market.alicloudapi.com
logistics.queryPath=/express/query-v2
logistics.queryMethod=POST
logistics.queryAppcode=**自己的code**

配置类:

@Data
@EnableConfigurationProperties
@Component
@ConfigurationProperties(prefix = "logistics")
public class LogisticsConfig {
    private static String DEFAULT_QUERY_HOST = "https://jmexpresv2.market.alicloudapi.com";
    private static String DEFAULT_QUERY_PATH = "/express/query-v2";
    private static String DEFAULT_METHOD = "POST";

    private String queryHost = DEFAULT_QUERY_HOST;
    private String queryPath = DEFAULT_QUERY_PATH;
    private String queryMethod = DEFAULT_METHOD;
    private String queryAppcode;
}

查询任务:

@Slf4j
@RestController
@RequestMapping("/logistics/query")
public class QueryController {
    @Autowired
    private LogisticsConfig config;


 /**
     * 响应的body:
     * {
     *   "data": {
     *     "expressCode": "YTO",
     *     "expressCompanyName": "圆通快递",
     *     "number": "YT*****535",
     *     "logisticsStatus": "SIGN",
     *     "logisticsStatusDesc": "已签收",
     *     "theLastMessage": "您******如果您对我们的服务感到满意,请在[评价快递员]处赐予我们五星好评~",
     *     "theLastTime": "2023-06-05 20:22:50",
     *     "takeTime": "21小时35分",
     *     "logisticsTraceDetails": [
     *       {
     *         "areaCode": "CN330204000000",
     *         "areaName": "浙江省,宁波市,江东区",
     *         "subLogisticsStatus": "ACCEPT",
     *         "time": 1685874576000,
     *         "logisticsStatus": "ACCEPT",
     *         "desc": "您的快****"
     *       },
     *       {
     *         "areaCode": "CN330204000000",
     *         "areaName": "浙江省,宁波市,江东区",
     *         "subLogisticsStatus": "TRANSPORT",
     *         "time": 1685881628000,
     *         "logisticsStatus": "TRANSPORT",
     *         "desc": "您的快件****心公司】"
     *       },
     *      ...
     *       {
     *         "subLogisticsStatus": "STA_INBOUND",
     *         "time": 1685952305000,
     *         "logisticsStatus": "DELIVERING",
     *         "desc": "您的快件****您服务!"
     *       },
     *       {
     *         "subLogisticsStatus": "SIGN",
     *         "time": 1685967770000,
     *         "logisticsStatus": "SIGN",
     *         "desc": "您的快****星好评~"
     *       }
     *     ]
     *   },
     *   "msg": "成功",
     *   "success": true,
     *   "code": 200,
     *   "taskNo": "9278282****72754862"
     * }
     */
    @GetMapping
    public String queryOneTime(@RequestParam String number) {
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Authorization", "APPCODE " + config.getQueryAppcode());
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>();
        Map<String, String> bodys = new HashMap<String, String>();
//        bodys.put("expressCode", "YTO"); //可选,快递公司编号 例如圆通:YTO,详见产品说明中:快递公司编码对照表 注意:快递公司编号不传时,系统会自动识别快递公司编号,但响应时间会比传递快递编号略长
        //bodys.put("mobile", "mobile"); //看快递公司,顺丰速运/丰网速运需要传入收/寄件人手机号或后四位手机号
        bodys.put("number", number); //必选,快递运单号

        try {
            HttpResponse response = HttpUtils.doPost(config.getQueryHost(), config.getQueryPath(), config.getQueryMethod(), headers, querys, bodys);
            log.info(response.toString());
            String result =EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); //这边注意指定编码,否则中文会乱码
            log.info(result);
            return result;
        } catch (Exception e) {
            log.error("err", e);
        }
        return "success";
    }
}