日常工作中如果有三方给客户发福利类实物的无法追踪物流明细的场景,就需要通过物流单号来定位客户福利的发货进度。
可以采用比较产品化的接口:快递100、聚合数据、51Tracking、快递鸟等专业的物流信息接口API,也可以在阿里云云市场中寻找其他公司提供的一些简单的API或者推送服务。主要是取决于你的性能与量级的要求,再综合考虑预算与售后支撑。
这边考虑到我们是做自己小批量实物订单的追踪,每月1K的量级,所以就简单考虑在阿里云云市场上找一个合适的性价比较高的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 {@Autowiredprivate 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-Typeheaders.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");//本地测试的话需要穿透一个公网Host,供公网回调
// 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 {@Autowiredprivate 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"* }*/@GetMappingpublic 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";}
}