可以采用比较产品化的接口:快递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";
}
}