SpringBoot實現(xiàn)快遞物流查詢功能(快遞鳥)
一、前言
本文將基于springboot2.4.0實現(xiàn)快遞物流查詢,物流信息的獲取通過快遞鳥第三方實現(xiàn)
http://www.kdniao.com
二、快遞物流查詢
1、快遞鳥工具類
@Slf4j public class KdniaoUtil { /** * 快遞查詢接口 * * @param queryDTO 請求參數(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 請求參數(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)用級參數(shù) Map<String, String> requestParamMap = Maps.newHashMap(); requestParamMap.put("shipperCode", shipperCode); requestParamMap.put("LogisticCode", logisticCode); String RequestData = JSON.toJSONString(requestParamMap); // 組裝系統(tǒng)級參數(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請求,post請求體中包含了應(yīng)用級參數(shù)和系統(tǒng)級參數(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方法的請求 * url 發(fā)送請求的 URL * params 請求的參數(shù)集合 * * @return 遠程資源的響應(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請求必須設(shè)置如下兩行 conn.setDoOutput(true); conn.setDoInput(true); // POST方法 conn.setRequestMethod("POST"); // 設(shè)置通用的請求屬性 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對象對應(yīng)的輸出流 out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8"); // 發(fā)送請求參數(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("[快遞鳥] 請求參數(shù): [{}]", param); out.write(param.toString()); } // flush輸出流的緩沖 out.flush(); // 定義BufferedReader輸入流來讀取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塊來關(guān)閉輸出流、輸入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result.toString(); } }
2、請求類
@Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @ApiModel("快遞鳥-物流-查詢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 = "請求url", required = true, example = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx") private String reqURL; }
@Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @ApiModel("快遞鳥-物流-查詢參數(shù)") public class KdniaoApiDTO extends KdniaoApiBaseDTO { @ApiModelProperty(value = "快遞公司編碼", required = true, example = "ZTO") private String shipperCode; @ApiModelProperty(value = "快遞單號", required = true, example = "xxx") private String logisticCode; }
3、響應(yīng)結(jié)果類
@Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @ApiModel("快遞鳥-物流-響應(yīng)參數(shù)") public class KdniaoApiVO { /** * {@link KdniaoLogisticsStatusEnum } * 增值物流狀態(tài): * 0-暫無軌跡信息 * 1-已攬收 * 2-在途中 * 201-到達派件城市, 202-派件中, 211-已放入快遞柜或驛站, * 3-已簽收 * 301-正常簽收, 302-派件異常后最終簽收, 304-代收簽收, 311-快遞柜或驛站簽收, * 4-問題件 * 401-發(fā)貨無信息, 402-超時未簽收, 403-超時未更新, 404-拒收(退件), 405-派件異常, 406-退貨簽收, 407-退貨未簽收, 412-快遞柜或驛站超時未取 */ @ApiModelProperty("增值物流狀態(tài)") private Integer StateEx; @ApiModelProperty("增值物流狀態(tài)名稱") private String statusExName; @ApiModelProperty("快遞單號") private String LogisticCode; @ApiModelProperty("快遞公司編碼") private String ShipperCode; @ApiModelProperty("失敗原因") private String Reason; @ApiModelProperty("事件軌跡集") private List<TraceItem> Traces; /** * {@link KdniaoLogisticsStatusEnum } */ @ApiModelProperty("物流狀態(tài):0-暫無軌跡信息,1-已攬收,2-在途中,3-簽收,4-問題件") private Integer State; @ApiModelProperty("狀態(tài)名稱") private String statusName; @ApiModelProperty("用戶ID") private String EBusinessID; @ApiModelProperty("送貨人") private String DeliveryMan; @ApiModelProperty("送貨人電話號碼") 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("時間") 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)快遞鳥接口支持的快遞公司編碼。
@Getter @AllArgsConstructor public enum KdniaoLogisticsCodeEnum { /** * 申通 */ STO("STO", "申通"), /** * 中通 */ ZTO("ZTO", "中通"), /** * 圓通 */ YTO("YTO", "圓通"), /** * 韻達 */ YD("YD", "韻達"), /** * 順豐 */ 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("暫無此物流編碼信息,請聯(lián)系系統(tǒng)管理員!"); } }
@Getter @AllArgsConstructor public enum KdniaoLogisticsStatusEnum { /** * 暫無軌跡信息 */ NO_TRACE(0, "暫無軌跡信息"), /** * 已攬收 */ HAVE_PAID(1, "已攬收"), /** * 已攬收 ----------------------------------------------------------------------------- */ ON_THE_WAY(2, "在途中"), /** * 到達派件城市 */ ARRIVE_AT_THE_DISPATCH_CITY(201, "到達派件城市"), /** * 派件中 */ IN_THE_DELIVERY(202, "派件中"), /** * 已放入快遞柜或驛站 */ HAS_STORED(211, "已放入快遞柜或驛站"), /** * 簽收 ----------------------------------------------------------------------------- */ SIGN(3, "簽收"), /** * 正常簽收 */ SIGN_NORMAL(301, "正常簽收"), /** * 派件異常后最終簽收 */ SIGN_ABNORMAL(302, "派件異常后最終簽收"), /** * 代收簽收 */ SIGN_COLLECTION(304, "代收簽收"), /** * 快遞柜或驛站簽收 */ SIGN_STORED(311, "快遞柜或驛站簽收"), /** * 問題件 ----------------------------------------------------------------------------- */ PROBLEM_SHIPMENT(4, "問題件"), /** * 發(fā)貨無信息 */ DELIVERY_NO_INFO(401, "發(fā)貨無信息"), /** * 超時未簽收 */ NO_SIGN_OVER_TIME(402, "超時未簽收"), /** * 超時未更新 */ NOT_UPDATED_DUE_TO_TIMEOUT(403, "超時未更新"), /** * 拒收(退件) */ REJECTION(404, "拒收(退件)"), /** * 派件異常 */ SEND_A_ABNORMAL(405, "派件異常"), /** * 退貨簽收 */ RETURN_TO_SIGN_FOR(406, "退貨簽收"), /** * 退貨未簽收 */ RETURN_NOT_SIGNED_FOR(407, "退貨未簽收"), /** * 快遞柜或驛站超時未取 */ STORED_OVER_TIME(412, "快遞柜或驛站超時未取"), /** * - */ 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、測試api
@Slf4j @RestController @RequestMapping("/test") @Api(tags = "測試api") public class TestController { @ApiOperation("查詢物流信息-快遞鳥") @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實現(xiàn)快遞物流查詢功能(快遞鳥)的文章就介紹到這了,更多相關(guān)SpringBoot快遞物流查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot前后端分離開發(fā)模式中的跨域問題及解決方法
本文介紹了解決Spring Boot前端Vue跨域問題的實戰(zhàn)經(jīng)驗,并提供了后端和前端的配置示例,通過配置后端和前端,我們可以輕松解決跨域問題,實現(xiàn)正常的前后端交互,需要的朋友可以參考下2023-09-09淺談Java異常的Exception e中的egetMessage()和toString()方法的區(qū)別
下面小編就為大家?guī)硪黄獪\談Java異常的Exception e中的egetMessage()和toString()方法的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07