SpringBoot實(shí)現(xiàn)快遞物流查詢功能(快遞鳥(niǎo))
一、前言
本文將基于springboot2.4.0實(shí)現(xiàn)快遞物流查詢,物流信息的獲取通過(guò)快遞鳥(niǎo)第三方實(shí)現(xiàn)
http://www.kdniao.com
二、快遞物流查詢
1、快遞鳥(niǎo)工具類
@Slf4j public class KdniaoUtil { /** * 快遞查詢接口 * * @param queryDTO 請(qǐng)求參數(shù) * @return 物流信息 * @author zhengqingya * @date 2021/10/25 17:39 */ public static KdniaoApiVO getLogisticInfo(KdniaoApiDTO queryDTO) { KdniaoApiVO kdniaoApiVO = new KdniaoUtil().getLogisticBase(queryDTO); Assert.isTrue("true".equals(kdniaoApiVO.getSuccess()), kdniaoApiVO.getReason()); kdniaoApiVO.handleData(); return kdniaoApiVO; } /** * 快遞查詢接口 * * @param queryDTO 請(qǐng)求參數(shù) * @return 物流信息 * @author zhengqingya * @date 2021/10/25 17:39 */ @SneakyThrows(Exception.class) private KdniaoApiVO getLogisticBase(KdniaoApiDTO queryDTO) { String EBusinessID = queryDTO.getEBusinessID(); String ApiKey = queryDTO.getApiKey(); String ReqURL = queryDTO.getReqURL(); String shipperCode = queryDTO.getShipperCode(); String logisticCode = queryDTO.getLogisticCode(); // 組裝應(yīng)用級(jí)參數(shù) Map<String, String> requestParamMap = Maps.newHashMap(); requestParamMap.put("shipperCode", shipperCode); requestParamMap.put("LogisticCode", logisticCode); String RequestData = JSON.toJSONString(requestParamMap); // 組裝系統(tǒng)級(jí)參數(shù) Map<String, String> params = Maps.newHashMap(); params.put("RequestData", this.urlEncoder(RequestData, "UTF-8")); params.put("EBusinessID", EBusinessID); params.put("RequestType", "8001"); String dataSign = this.encrypt(RequestData, ApiKey, "UTF-8"); params.put("DataSign", this.urlEncoder(dataSign, "UTF-8")); params.put("DataType", "2"); // 以form表單形式提交post請(qǐng)求,post請(qǐng)求體中包含了應(yīng)用級(jí)參數(shù)和系統(tǒng)級(jí)參數(shù) String resultJson = this.sendPost(ReqURL, params); return JSON.parseObject(resultJson, KdniaoApiVO.class); } /** * MD5加密 * str 內(nèi)容 * charset 編碼方式 * * @throws Exception */ @SuppressWarnings("unused") private String MD5(String str, String charset) throws Exception { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str.getBytes(charset)); byte[] result = md.digest(); StringBuffer sb = new StringBuffer(32); for (int i = 0; i < result.length; i++) { int val = result[i] & 0xff; if (val <= 0xf) { sb.append("0"); } sb.append(Integer.toHexString(val)); } return sb.toString().toLowerCase(); } /** * base64編碼 * str 內(nèi)容 * charset 編碼方式 * * @throws UnsupportedEncodingException */ private String base64(String str, String charset) throws UnsupportedEncodingException { String encoded = Base64.encode(str.getBytes(charset)); return encoded; } @SuppressWarnings("unused") private String urlEncoder(String str, String charset) throws UnsupportedEncodingException { String result = URLEncoder.encode(str, charset); return result; } /** * 電商Sign簽名生成 * content 內(nèi)容 * keyValue ApiKey * charset 編碼方式 * * @return DataSign簽名 * @throws UnsupportedEncodingException ,Exception */ @SuppressWarnings("unused") private String encrypt(String content, String keyValue, String charset) throws UnsupportedEncodingException, Exception { if (keyValue != null) { return base64(MD5(content + keyValue, charset), charset); } return base64(MD5(content, charset), charset); } /** * 向指定 URL 發(fā)送POST方法的請(qǐng)求 * url 發(fā)送請(qǐng)求的 URL * params 請(qǐng)求的參數(shù)集合 * * @return 遠(yuǎn)程資源的響應(yīng)結(jié)果 */ @SuppressWarnings("unused") private String sendPost(String url, Map<String, String> params) { OutputStreamWriter out = null; BufferedReader in = null; StringBuilder result = new StringBuilder(); try { URL realUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); // 發(fā)送POST請(qǐng)求必須設(shè)置如下兩行 conn.setDoOutput(true); conn.setDoInput(true); // POST方法 conn.setRequestMethod("POST"); // 設(shè)置通用的請(qǐng)求屬性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); conn.connect(); // 獲取URLConnection對(duì)象對(duì)應(yīng)的輸出流 out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8"); // 發(fā)送請(qǐng)求參數(shù) if (params != null) { StringBuilder param = new StringBuilder(); for (Map.Entry<String, String> entry : params.entrySet()) { if (param.length() > 0) { param.append("&"); } param.append(entry.getKey()); param.append("="); param.append(entry.getValue()); } log.info("[快遞鳥(niǎo)] 請(qǐng)求參數(shù): [{}]", param); out.write(param.toString()); } // flush輸出流的緩沖 out.flush(); // 定義BufferedReader輸入流來(lái)讀取URL的響應(yīng) in = new BufferedReader( new InputStreamReader(conn.getInputStream(), "UTF-8")); String line; while ((line = in.readLine()) != null) { result.append(line); } } catch (Exception e) { e.printStackTrace(); } //使用finally塊來(lái)關(guān)閉輸出流、輸入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result.toString(); } }
2、請(qǐng)求類
@Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @ApiModel("快遞鳥(niǎo)-物流-查詢base參數(shù)") public class KdniaoApiBaseDTO { @ApiModelProperty(value = "用戶ID", required = true, example = "xx") private String eBusinessID; @ApiModelProperty(value = "API key", required = true, example = "xx") private String apiKey; @ApiModelProperty(value = "請(qǐng)求url", required = true, example = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx") private String reqURL; }
@Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @ApiModel("快遞鳥(niǎo)-物流-查詢參數(shù)") public class KdniaoApiDTO extends KdniaoApiBaseDTO { @ApiModelProperty(value = "快遞公司編碼", required = true, example = "ZTO") private String shipperCode; @ApiModelProperty(value = "快遞單號(hào)", required = true, example = "xxx") private String logisticCode; }
3、響應(yīng)結(jié)果類
@Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @ApiModel("快遞鳥(niǎo)-物流-響應(yīng)參數(shù)") public class KdniaoApiVO { /** * {@link KdniaoLogisticsStatusEnum } * 增值物流狀態(tài): * 0-暫無(wú)軌跡信息 * 1-已攬收 * 2-在途中 * 201-到達(dá)派件城市, 202-派件中, 211-已放入快遞柜或驛站, * 3-已簽收 * 301-正常簽收, 302-派件異常后最終簽收, 304-代收簽收, 311-快遞柜或驛站簽收, * 4-問(wèn)題件 * 401-發(fā)貨無(wú)信息, 402-超時(shí)未簽收, 403-超時(shí)未更新, 404-拒收(退件), 405-派件異常, 406-退貨簽收, 407-退貨未簽收, 412-快遞柜或驛站超時(shí)未取 */ @ApiModelProperty("增值物流狀態(tài)") private Integer StateEx; @ApiModelProperty("增值物流狀態(tài)名稱") private String statusExName; @ApiModelProperty("快遞單號(hào)") private String LogisticCode; @ApiModelProperty("快遞公司編碼") private String ShipperCode; @ApiModelProperty("失敗原因") private String Reason; @ApiModelProperty("事件軌跡集") private List<TraceItem> Traces; /** * {@link KdniaoLogisticsStatusEnum } */ @ApiModelProperty("物流狀態(tài):0-暫無(wú)軌跡信息,1-已攬收,2-在途中,3-簽收,4-問(wèn)題件") private Integer State; @ApiModelProperty("狀態(tài)名稱") private String statusName; @ApiModelProperty("用戶ID") private String EBusinessID; @ApiModelProperty("送貨人") private String DeliveryMan; @ApiModelProperty("送貨人電話號(hào)碼") private String DeliveryManTel; @ApiModelProperty("成功與否 true/false") private String Success; @ApiModelProperty("所在城市") private String Location; @Data @Builder @NoArgsConstructor @AllArgsConstructor @ApiModel("事件軌跡集") public static class TraceItem { /** * {@link KdniaoLogisticsStatusEnum } */ @ApiModelProperty("當(dāng)前狀態(tài)(同StateEx)") private Integer Action; @ApiModelProperty("狀態(tài)名稱") private String actionName; @ApiModelProperty("描述") private String AcceptStation; @ApiModelProperty("時(shí)間") private String AcceptTime; @ApiModelProperty("所在城市") private String Location; } public void handleData() { this.statusName = KdniaoLogisticsStatusEnum.getEnum(this.State).getDesc(); this.statusExName = KdniaoLogisticsStatusEnum.getEnum(this.StateEx).getDesc(); if (CollectionUtils.isEmpty(this.Traces)) { this.Traces = Lists.newArrayList(); } this.Traces.forEach(item -> item.actionName = KdniaoLogisticsStatusEnum.getEnum(item.Action).getDesc()); } }
4、物流編碼、狀態(tài)枚舉類
溫馨小提示:更多物流編碼值可參考官網(wǎng)快遞鳥(niǎo)接口支持的快遞公司編碼。
@Getter @AllArgsConstructor public enum KdniaoLogisticsCodeEnum { /** * 申通 */ STO("STO", "申通"), /** * 中通 */ ZTO("ZTO", "中通"), /** * 圓通 */ YTO("YTO", "圓通"), /** * 韻達(dá) */ YD("YD", "韻達(dá)"), /** * 順豐 */ SF("SF", "順豐"); /** * 物流編碼 */ private final String code; /** * 物流名 */ private final String name; private static final List<KdniaoLogisticsCodeEnum> LIST = Lists.newArrayList(); static { LIST.addAll(Arrays.asList(KdniaoLogisticsCodeEnum.values())); } /** * 根據(jù)值查找相應(yīng)枚舉 */ @SneakyThrows(Exception.class) public static KdniaoLogisticsCodeEnum getEnumByName(String name) { for (KdniaoLogisticsCodeEnum itemEnum : LIST) { if (itemEnum.getName().equals(name)) { return itemEnum; } } throw new Exception("暫無(wú)此物流編碼信息,請(qǐng)聯(lián)系系統(tǒng)管理員!"); } }
@Getter @AllArgsConstructor public enum KdniaoLogisticsStatusEnum { /** * 暫無(wú)軌跡信息 */ NO_TRACE(0, "暫無(wú)軌跡信息"), /** * 已攬收 */ HAVE_PAID(1, "已攬收"), /** * 已攬收 ----------------------------------------------------------------------------- */ ON_THE_WAY(2, "在途中"), /** * 到達(dá)派件城市 */ ARRIVE_AT_THE_DISPATCH_CITY(201, "到達(dá)派件城市"), /** * 派件中 */ IN_THE_DELIVERY(202, "派件中"), /** * 已放入快遞柜或驛站 */ HAS_STORED(211, "已放入快遞柜或驛站"), /** * 簽收 ----------------------------------------------------------------------------- */ SIGN(3, "簽收"), /** * 正常簽收 */ SIGN_NORMAL(301, "正常簽收"), /** * 派件異常后最終簽收 */ SIGN_ABNORMAL(302, "派件異常后最終簽收"), /** * 代收簽收 */ SIGN_COLLECTION(304, "代收簽收"), /** * 快遞柜或驛站簽收 */ SIGN_STORED(311, "快遞柜或驛站簽收"), /** * 問(wèn)題件 ----------------------------------------------------------------------------- */ PROBLEM_SHIPMENT(4, "問(wèn)題件"), /** * 發(fā)貨無(wú)信息 */ DELIVERY_NO_INFO(401, "發(fā)貨無(wú)信息"), /** * 超時(shí)未簽收 */ NO_SIGN_OVER_TIME(402, "超時(shí)未簽收"), /** * 超時(shí)未更新 */ NOT_UPDATED_DUE_TO_TIMEOUT(403, "超時(shí)未更新"), /** * 拒收(退件) */ REJECTION(404, "拒收(退件)"), /** * 派件異常 */ SEND_A_ABNORMAL(405, "派件異常"), /** * 退貨簽收 */ RETURN_TO_SIGN_FOR(406, "退貨簽收"), /** * 退貨未簽收 */ RETURN_NOT_SIGNED_FOR(407, "退貨未簽收"), /** * 快遞柜或驛站超時(shí)未取 */ STORED_OVER_TIME(412, "快遞柜或驛站超時(shí)未取"), /** * - */ DEFAULT(0, "-"); /** * 狀態(tài) */ private final Integer status; /** * 描述 */ private final String desc; private static final List<KdniaoLogisticsStatusEnum> LIST = Lists.newArrayList(); static { LIST.addAll(Arrays.asList(KdniaoLogisticsStatusEnum.values())); } /** * 根據(jù)物流狀態(tài)查找相應(yīng)枚舉 */ public static KdniaoLogisticsStatusEnum getEnum(Integer status) { for (KdniaoLogisticsStatusEnum itemEnum : LIST) { if (itemEnum.getStatus().equals(status)) { return itemEnum; } } return KdniaoLogisticsStatusEnum.DEFAULT; } }
5、測(cè)試api
@Slf4j @RestController @RequestMapping("/test") @Api(tags = "測(cè)試api") public class TestController { @ApiOperation("查詢物流信息-快遞鳥(niǎo)") @GetMapping("getLogisticByKdniao") public KdniaoApiVO getLogisticByKdniao(@ModelAttribute KdniaoApiDTO params) { return KdniaoUtil.getLogisticInfo(params); } }
接口文檔 http://127.0.0.1/doc.html
三、本文demo源碼
https://gitee.com/zhengqingya/java-workspace
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)快遞物流查詢功能(快遞鳥(niǎo))的文章就介紹到這了,更多相關(guān)SpringBoot快遞物流查詢內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot前后端分離開(kāi)發(fā)模式中的跨域問(wèn)題及解決方法
本文介紹了解決Spring Boot前端Vue跨域問(wèn)題的實(shí)戰(zhàn)經(jīng)驗(yàn),并提供了后端和前端的配置示例,通過(guò)配置后端和前端,我們可以輕松解決跨域問(wèn)題,實(shí)現(xiàn)正常的前后端交互,需要的朋友可以參考下2023-09-09淺談Java異常的Exception e中的egetMessage()和toString()方法的區(qū)別
下面小編就為大家?guī)?lái)一篇淺談Java異常的Exception e中的egetMessage()和toString()方法的區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07java語(yǔ)言自行實(shí)現(xiàn)ULID過(guò)程底層原理詳解
這篇文章主要為大家介紹了java語(yǔ)言自行實(shí)現(xiàn)ULID過(guò)程底層原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Spring事務(wù)失效之常見(jiàn)場(chǎng)景分析
這篇文章主要介紹了Spring事務(wù)失效之常見(jiàn)場(chǎng)景,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04