mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 10:18:42 +08:00 
			
		
		
		
	快递100 快递查询实现
This commit is contained in:
		| @@ -4,6 +4,7 @@ import cn.hutool.core.util.ArrayUtil; | |||||||
| import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||||
| import cn.hutool.json.JSONUtil; | import cn.hutool.json.JSONUtil; | ||||||
| import com.fasterxml.jackson.core.type.TypeReference; | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
|  | import com.fasterxml.jackson.databind.DeserializationFeature; | ||||||
| import com.fasterxml.jackson.databind.JsonNode; | import com.fasterxml.jackson.databind.JsonNode; | ||||||
| import com.fasterxml.jackson.databind.ObjectMapper; | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
| import com.fasterxml.jackson.databind.SerializationFeature; | import com.fasterxml.jackson.databind.SerializationFeature; | ||||||
| @@ -29,6 +30,7 @@ public class JsonUtils { | |||||||
|  |  | ||||||
|     static { |     static { | ||||||
|         objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); |         objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); | ||||||
|  |         objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); | ||||||
|         objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化 |         objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -53,8 +53,9 @@ public interface ErrorCodeConstants { | |||||||
|     ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011003003, "已经存在该运费模板名"); |     ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011003003, "已经存在该运费模板名"); | ||||||
|     ErrorCode DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY = new ErrorCode(1011003004, "计算快递运费时,收件人地址编号为空"); |     ErrorCode DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY = new ErrorCode(1011003004, "计算快递运费时,收件人地址编号为空"); | ||||||
|     ErrorCode PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND = new ErrorCode(1011003005, "找不到到商品对应的运费模板"); |     ErrorCode PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND = new ErrorCode(1011003005, "找不到到商品对应的运费模板"); | ||||||
|     ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1011003006, "快递接口查询失败"); |     ErrorCode EXPRESS_API_QUERY_ERROR = new ErrorCode(1011003006, "快递查询接口异常"); | ||||||
|     ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011003007, "自提门店不存在"); |     ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1011003007, "快递查询返回失败, 原因:{}"); | ||||||
|  |     ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011003008, "自提门店不存在"); | ||||||
|  |  | ||||||
|     // ========== Price 相关 1011004000 ============ |     // ========== Price 相关 1011004000 ============ | ||||||
|     ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011004000, "支付价格计算异常,原因:价格小于等于 0"); |     ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011004000, "支付价格计算异常,原因:价格小于等于 0"); | ||||||
|   | |||||||
| @@ -55,10 +55,20 @@ public class TradeExpressQueryProperties { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 快递100 配置项 TODO |      * 快递100 配置项 | ||||||
|      */ |      */ | ||||||
|  |     @Data | ||||||
|     public static class Kd100Config { |     public static class Kd100Config { | ||||||
|  |         /** | ||||||
|  |          * 快递 100 授权码 | ||||||
|  |          */ | ||||||
|  |         @NotEmpty(message = "快递 100 授权码配置项不能为空") | ||||||
|  |         private String customer; | ||||||
|  |         /** | ||||||
|  |          * 快递 100 授权 key | ||||||
|  |          */ | ||||||
|  |         @NotEmpty(message = "快递 100 授权 Key 配置项不能为空") | ||||||
|  |         private String key; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.trade.framework.delivery.core.convert; | |||||||
|  |  | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryRespDTO; | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryRespDTO; | ||||||
|  | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kd100.Kd100ExpressQueryReqDTO; | ||||||
|  | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kd100.Kd100ExpressQueryRespDTO; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryReqDTO; | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryReqDTO; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryRespDTO; | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryRespDTO; | ||||||
| import org.mapstruct.Mapper; | import org.mapstruct.Mapper; | ||||||
| @@ -16,5 +18,9 @@ public interface ExpressQueryConvert { | |||||||
|  |  | ||||||
|     List<ExpressQueryRespDTO> convertList(List<KdNiaoExpressQueryRespDTO.ExpressTrack> expressTrackList); |     List<ExpressQueryRespDTO> convertList(List<KdNiaoExpressQueryRespDTO.ExpressTrack> expressTrackList); | ||||||
|  |  | ||||||
|  |     List<ExpressQueryRespDTO> convertList2(List<Kd100ExpressQueryRespDTO.ExpressTrack> expressTrackList); | ||||||
|  |  | ||||||
|     KdNiaoExpressQueryReqDTO convert(ExpressQueryReqDTO dto); |     KdNiaoExpressQueryReqDTO convert(ExpressQueryReqDTO dto); | ||||||
|  |  | ||||||
|  |     Kd100ExpressQueryReqDTO convert2(ExpressQueryReqDTO dto); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,47 @@ | |||||||
|  | package cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kd100; | ||||||
|  |  | ||||||
|  | import com.fasterxml.jackson.annotation.JsonInclude; | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 快递 100 快递查询 Req DTO | ||||||
|  |  * | ||||||
|  |  * @author jason | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | @JsonInclude(JsonInclude.Include.NON_NULL) | ||||||
|  | public class Kd100ExpressQueryReqDTO { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 快递公司编码 | ||||||
|  |      */ | ||||||
|  |     @JsonProperty("com") | ||||||
|  |     private String expressCompanyCode; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 快递单号 | ||||||
|  |      */ | ||||||
|  |     @JsonProperty("num") | ||||||
|  |     private String logisticsNo; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 收、寄件人的电话号码 | ||||||
|  |      */ | ||||||
|  |     private String phone; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 出发地城市 | ||||||
|  |      */ | ||||||
|  |     private String from; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 目的地城市,到达目的地后会加大监控频率 | ||||||
|  |      */ | ||||||
|  |     private String to; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 返回结果排序:desc降序(默认),asc 升序 | ||||||
|  |      */ | ||||||
|  |     private String order; | ||||||
|  | } | ||||||
| @@ -0,0 +1,59 @@ | |||||||
|  | package cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kd100; | ||||||
|  |  | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 快递 100 实时快递查询 Resp DTO 参见  <a href="https://api.kuaidi100.com/document/5f0ffb5ebc8da837cbd8aefc">快递 100 文档</a> | ||||||
|  |  * | ||||||
|  |  * @author jason | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class Kd100ExpressQueryRespDTO { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 快递公司编码 | ||||||
|  |      */ | ||||||
|  |     @JsonProperty("com") | ||||||
|  |     private String expressCompanyCode; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 快递单号 | ||||||
|  |      */ | ||||||
|  |     @JsonProperty("nu") | ||||||
|  |     private String logisticsNo; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 快递单当前状态 | ||||||
|  |      */ | ||||||
|  |     private String state; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 查询结果, 失败返回 "false" | ||||||
|  |      */ | ||||||
|  |     private String result; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 查询结果失败时的错误信息 | ||||||
|  |      */ | ||||||
|  |     private String message; | ||||||
|  |  | ||||||
|  |     @JsonProperty("data") | ||||||
|  |     private List<ExpressTrack> tracks; | ||||||
|  |  | ||||||
|  |     @Data | ||||||
|  |     public static class ExpressTrack { | ||||||
|  |         /** | ||||||
|  |          * 轨迹发生时间 | ||||||
|  |          */ | ||||||
|  |         @JsonProperty("time") | ||||||
|  |         private String time; | ||||||
|  |         /** | ||||||
|  |          * 轨迹描述 | ||||||
|  |          */ | ||||||
|  |         @JsonProperty("context") | ||||||
|  |         private String state; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,19 +1,39 @@ | |||||||
| package cn.iocoder.yudao.module.trade.framework.delivery.core.impl; | package cn.iocoder.yudao.module.trade.framework.delivery.core.impl; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.collection.CollUtil; | ||||||
|  | import cn.hutool.core.util.HexUtil; | ||||||
|  | import cn.hutool.crypto.digest.DigestUtil; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressQueryProperties; | import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressQueryProperties; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProvider; | import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProvider; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryRespDTO; | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryRespDTO; | ||||||
|  | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kd100.Kd100ExpressQueryReqDTO; | ||||||
|  | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kd100.Kd100ExpressQueryRespDTO; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.springframework.http.*; | ||||||
|  | import org.springframework.util.LinkedMultiValueMap; | ||||||
|  | import org.springframework.util.MultiValueMap; | ||||||
| import org.springframework.web.client.RestTemplate; | import org.springframework.web.client.RestTemplate; | ||||||
|  |  | ||||||
|  | import java.util.Collections; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Objects; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
|  | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_API_QUERY_FAILED; | ||||||
|  | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_API_QUERY_ERROR; | ||||||
|  | import static cn.iocoder.yudao.module.trade.framework.delivery.core.convert.ExpressQueryConvert.INSTANCE; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 快递 100 服务商 TODO |  * 快递 100 服务商 | ||||||
|  |  * | ||||||
|  * @author jason |  * @author jason | ||||||
|  */ |  */ | ||||||
|  | @Slf4j | ||||||
| public class Kd100ExpressQueryProvider implements ExpressQueryProvider { | public class Kd100ExpressQueryProvider implements ExpressQueryProvider { | ||||||
|  |  | ||||||
|  |     private static final String REAL_TIME_QUERY_URL = "https://poll.kuaidi100.com/poll/query.do"; | ||||||
|     private final RestTemplate restTemplate; |     private final RestTemplate restTemplate; | ||||||
|  |  | ||||||
|     private final TradeExpressQueryProperties.Kd100Config config; |     private final TradeExpressQueryProperties.Kd100Config config; | ||||||
| @@ -25,6 +45,63 @@ public class Kd100ExpressQueryProvider implements ExpressQueryProvider { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<ExpressQueryRespDTO> realTimeQueryExpress(ExpressQueryReqDTO reqDTO) { |     public List<ExpressQueryRespDTO> realTimeQueryExpress(ExpressQueryReqDTO reqDTO) { | ||||||
|         return null; |         Kd100ExpressQueryReqDTO kd100ReqParam = INSTANCE.convert2(reqDTO); | ||||||
|  |         // 快递公司编码需要转成小写 | ||||||
|  |         kd100ReqParam.setExpressCompanyCode(kd100ReqParam.getExpressCompanyCode().toLowerCase()); | ||||||
|  |         Kd100ExpressQueryRespDTO respDTO = sendExpressQueryReq(REAL_TIME_QUERY_URL, kd100ReqParam, | ||||||
|  |                 Kd100ExpressQueryRespDTO.class); | ||||||
|  |         log.debug("快递 100 接口 查询接口返回 {}", respDTO); | ||||||
|  |         if (Objects.equals("false", respDTO.getResult())) { | ||||||
|  |             log.error("快递 100 接口 返回失败 {} ", respDTO.getMessage()); | ||||||
|  |             throw exception(EXPRESS_API_QUERY_FAILED, respDTO.getMessage()); | ||||||
|  |         } else { | ||||||
|  |             if (CollUtil.isNotEmpty(respDTO.getTracks())) { | ||||||
|  |                 return INSTANCE.convertList2(respDTO.getTracks()); | ||||||
|  |             } else { | ||||||
|  |                 return Collections.emptyList(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 发送快递 100 实时快递查询请求,可以作为通用快递 100 通用请求接口。 目前没有其它场景需要使用。暂时放这里 | ||||||
|  |      * @param url 请求 url | ||||||
|  |      * @param req 对应请求的请求参数 | ||||||
|  |      * @param respClass 对应请求的响应 class | ||||||
|  |      * @param <Req> 每个请求的请求结构 Req DTO | ||||||
|  |      * @param <Resp> 每个请求的响应结构 Resp DTO | ||||||
|  |      */ | ||||||
|  |     private <Req, Resp> Resp sendExpressQueryReq(String url, Req req, Class<Resp> respClass) { | ||||||
|  |         // 请求头 | ||||||
|  |         HttpHeaders headers = new HttpHeaders(); | ||||||
|  |         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); | ||||||
|  |         // 生成签名 | ||||||
|  |         String param = JsonUtils.toJsonString(req); | ||||||
|  |         String sign = generateReqSign(param, config.getKey(), config.getCustomer()); | ||||||
|  |         log.debug("快递 100 快递 接口生成签名的: {}", sign); | ||||||
|  |         // 请求体 | ||||||
|  |         MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>(); | ||||||
|  |         requestBody.add("customer", config.getCustomer()); | ||||||
|  |         requestBody.add("sign", sign); | ||||||
|  |         requestBody.add("param", param); | ||||||
|  |         log.debug("快递 100 接口的请求参数: {}", requestBody); | ||||||
|  |  | ||||||
|  |         HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(requestBody, headers); | ||||||
|  |         // 发送请求 | ||||||
|  |         ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); | ||||||
|  |         log.debug("快递 100 接口响应结果 {}", responseEntity); | ||||||
|  |         // 处理响应 | ||||||
|  |         if (responseEntity.getStatusCode().is2xxSuccessful()) { | ||||||
|  |             String response = responseEntity.getBody(); | ||||||
|  |             return JsonUtils.parseObject(response, respClass); | ||||||
|  |         } else { | ||||||
|  |             throw exception(EXPRESS_API_QUERY_ERROR); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private String generateReqSign(String param, String key, String customer) { | ||||||
|  |         String plainText = String.format("%s%s%s", param, key, customer); | ||||||
|  |         log.debug("快递 100 接口待签名的数据 {}", plainText); | ||||||
|  |         return HexUtil.encodeHexStr(DigestUtil.md5(plainText), false); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReq | |||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryRespDTO; | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryRespDTO; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryReqDTO; | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryReqDTO; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryRespDTO; | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryRespDTO; | ||||||
| import com.fasterxml.jackson.core.type.TypeReference; |  | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.springframework.http.*; | import org.springframework.http.*; | ||||||
| import org.springframework.util.LinkedMultiValueMap; | import org.springframework.util.LinkedMultiValueMap; | ||||||
| @@ -23,6 +22,7 @@ import java.util.List; | |||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
| import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_API_QUERY_FAILED; | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_API_QUERY_FAILED; | ||||||
|  | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_API_QUERY_ERROR; | ||||||
| import static cn.iocoder.yudao.module.trade.framework.delivery.core.convert.ExpressQueryConvert.INSTANCE; | import static cn.iocoder.yudao.module.trade.framework.delivery.core.convert.ExpressQueryConvert.INSTANCE; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -57,34 +57,28 @@ public class KdNiaoExpressQueryProvider implements ExpressQueryProvider { | |||||||
|         KdNiaoExpressQueryRespDTO respDTO = sendKdNiaoApiRequest(REAL_TIME_QUERY_URL, REAL_TIME_FREE_REQ_TYPE, |         KdNiaoExpressQueryRespDTO respDTO = sendKdNiaoApiRequest(REAL_TIME_QUERY_URL, REAL_TIME_FREE_REQ_TYPE, | ||||||
|                 kdNiaoReqData, KdNiaoExpressQueryRespDTO.class); |                 kdNiaoReqData, KdNiaoExpressQueryRespDTO.class); | ||||||
|         log.debug("快递鸟即时查询接口返回 {}", respDTO); |         log.debug("快递鸟即时查询接口返回 {}", respDTO); | ||||||
|         if (respDTO.getSuccess() && CollUtil.isNotEmpty(respDTO.getTracks())) { |         if(!respDTO.getSuccess()){ | ||||||
|             return INSTANCE.convertList(respDTO.getTracks()); |             throw exception(EXPRESS_API_QUERY_FAILED, respDTO.getReason()); | ||||||
|         }else{ |         }else{ | ||||||
|             return Collections.emptyList(); |             if (CollUtil.isNotEmpty(respDTO.getTracks())) { | ||||||
|  |                 return INSTANCE.convertList(respDTO.getTracks()); | ||||||
|  |             }else{ | ||||||
|  |                 return Collections.emptyList(); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private  <Req, Resp> Resp sendKdNiaoApiRequest(String url, String requestType, Req req, |  | ||||||
|                                                    Class<Resp> respClass){ |  | ||||||
|         return sendKdNiaoApiRequest(url, requestType, req, respClass, null); |  | ||||||
|     } |  | ||||||
|     private  <Req, Resp> Resp sendKdNiaoApiRequest(String url, String requestType, Req req, |  | ||||||
|                                                    TypeReference<Resp> typeRefResp){ |  | ||||||
|         return sendKdNiaoApiRequest(url, requestType, req, null, typeRefResp); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 快递鸟 通用的 API 请求 |      * 快递鸟 通用的 API 请求, 暂时没有其他应用场景, 暂时放这里 | ||||||
|      * @param url 请求 url |      * @param url 请求 url | ||||||
|      * @param requestType 对应的请求指令 (快递鸟的RequestType) |      * @param requestType 对应的请求指令 (快递鸟的RequestType) | ||||||
|      * @param req  对应请求的请求参数 |      * @param req  对应请求的请求参数 | ||||||
|      * @param respClass 对应请求的响应 class |      * @param respClass 对应请求的响应 class | ||||||
|      * @param typeRefResp 对应请求的响应  TypeReference |  | ||||||
|      * @param <Req> 每个请求的请求结构 Req DTO |      * @param <Req> 每个请求的请求结构 Req DTO | ||||||
|      * @param <Resp> 每个请求的响应结构 Resp DTO |      * @param <Resp> 每个请求的响应结构 Resp DTO | ||||||
|      */ |      */ | ||||||
|     private  <Req, Resp> Resp sendKdNiaoApiRequest(String url, String requestType, Req req, |     private  <Req, Resp> Resp sendKdNiaoApiRequest(String url, String requestType, Req req, | ||||||
|                                                    Class<Resp> respClass, TypeReference<Resp> typeRefResp){ |                                                    Class<Resp> respClass){ | ||||||
|         // 请求头 |         // 请求头 | ||||||
|         HttpHeaders headers = new HttpHeaders(); |         HttpHeaders headers = new HttpHeaders(); | ||||||
|         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); |         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); | ||||||
| @@ -106,13 +100,9 @@ public class KdNiaoExpressQueryProvider implements ExpressQueryProvider { | |||||||
|         // 处理响应 |         // 处理响应 | ||||||
|         if (responseEntity.getStatusCode().is2xxSuccessful()) { |         if (responseEntity.getStatusCode().is2xxSuccessful()) { | ||||||
|             String response = responseEntity.getBody(); |             String response = responseEntity.getBody(); | ||||||
|             if (respClass != null && typeRefResp == null) { |             return JsonUtils.parseObject(response, respClass); | ||||||
|                 return JsonUtils.parseObject(response, respClass); |  | ||||||
|             } else { |  | ||||||
|                 return JsonUtils.parseObject(response, typeRefResp); |  | ||||||
|             } |  | ||||||
|         } else { |         } else { | ||||||
|             throw exception(EXPRESS_API_QUERY_FAILED); |             throw exception(EXPRESS_API_QUERY_ERROR); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,56 @@ | |||||||
|  | package cn.iocoder.yudao.module.trade.framework.delivery.core.impl; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.exception.ServiceException; | ||||||
|  | import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressQueryProperties; | ||||||
|  | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | ||||||
|  | import org.junit.jupiter.api.BeforeEach; | ||||||
|  | import org.junit.jupiter.api.Disabled; | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  | import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; | ||||||
|  | import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||||
|  | import org.springframework.boot.test.context.SpringBootTest; | ||||||
|  | import org.springframework.boot.web.client.RestTemplateBuilder; | ||||||
|  | import org.springframework.context.annotation.Import; | ||||||
|  | import org.springframework.test.context.ActiveProfiles; | ||||||
|  |  | ||||||
|  | import javax.annotation.Resource; | ||||||
|  |  | ||||||
|  | import static org.junit.jupiter.api.Assertions.assertEquals; | ||||||
|  | import static org.junit.jupiter.api.Assertions.assertThrows; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @author jason | ||||||
|  |  */ | ||||||
|  | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = Kd100ExpressQueryProviderTest.Application.class) | ||||||
|  | @ActiveProfiles("trade-delivery-query") // 设置使用 trade-delivery-query 配置文件 | ||||||
|  | public class Kd100ExpressQueryProviderTest { | ||||||
|  |     @Resource | ||||||
|  |     private RestTemplateBuilder builder; | ||||||
|  |     @Resource | ||||||
|  |     private TradeExpressQueryProperties expressQueryProperties; | ||||||
|  |  | ||||||
|  |     private Kd100ExpressQueryProvider kd100ExpressQueryProvider; | ||||||
|  |  | ||||||
|  |     @BeforeEach | ||||||
|  |     public void init(){ | ||||||
|  |         kd100ExpressQueryProvider = new Kd100ExpressQueryProvider(builder.build(),expressQueryProperties.getKd100()); | ||||||
|  |     } | ||||||
|  |     @Test | ||||||
|  |     @Disabled("需要 授权 key. 暂时忽略") | ||||||
|  |     void testRealTimeQueryExpressFailed() { | ||||||
|  |         ServiceException t =  assertThrows(ServiceException.class, () -> { | ||||||
|  |             ExpressQueryReqDTO reqDTO = new ExpressQueryReqDTO(); | ||||||
|  |             reqDTO.setExpressCompanyCode("yto"); | ||||||
|  |             reqDTO.setLogisticsNo("YT9383342193097"); | ||||||
|  |             kd100ExpressQueryProvider.realTimeQueryExpress(reqDTO); | ||||||
|  |         }); | ||||||
|  |         assertEquals(1011003007, t.getCode()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Import({ | ||||||
|  |             RestTemplateAutoConfiguration.class | ||||||
|  |     }) | ||||||
|  |     @EnableConfigurationProperties(TradeExpressQueryProperties.class) | ||||||
|  |     public static class Application { | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,9 +1,10 @@ | |||||||
| package cn.iocoder.yudao.module.trade.framework.delivery.core.impl; | package cn.iocoder.yudao.module.trade.framework.delivery.core.impl; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.exception.ServiceException; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressQueryProperties; | import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressQueryProperties; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | ||||||
| import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryRespDTO; |  | ||||||
| import org.junit.jupiter.api.BeforeEach; | import org.junit.jupiter.api.BeforeEach; | ||||||
|  | import org.junit.jupiter.api.Disabled; | ||||||
| import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||||
| import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; | import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; | ||||||
| import org.springframework.boot.context.properties.EnableConfigurationProperties; | import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||||
| @@ -13,9 +14,8 @@ import org.springframework.context.annotation.Import; | |||||||
| import org.springframework.test.context.ActiveProfiles; | import org.springframework.test.context.ActiveProfiles; | ||||||
|  |  | ||||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
| import static org.junit.jupiter.api.Assertions.*; | import static org.junit.jupiter.api.Assertions.assertThrows; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @author jason |  * @author jason | ||||||
| @@ -35,12 +35,14 @@ public class KdNiaoExpressQueryProviderTest { | |||||||
|         kdNiaoExpressQueryProvider = new KdNiaoExpressQueryProvider(builder.build(),expressQueryProperties.getKdNiao()); |         kdNiaoExpressQueryProvider = new KdNiaoExpressQueryProvider(builder.build(),expressQueryProperties.getKdNiao()); | ||||||
|     } |     } | ||||||
|     @Test |     @Test | ||||||
|     void queryExpress() { |     @Disabled("需要 授权 key. 暂时忽略") | ||||||
|         ExpressQueryReqDTO reqDTO = new ExpressQueryReqDTO(); |     void testRealTimeQueryExpressFailed() { | ||||||
|         reqDTO.setExpressCompanyCode("yto"); |         assertThrows(ServiceException.class,() ->{ | ||||||
|         reqDTO.setLogisticsNo("YT1764381060802"); |             ExpressQueryReqDTO reqDTO = new ExpressQueryReqDTO(); | ||||||
|         List<ExpressQueryRespDTO> expressQueryRespDTOS = kdNiaoExpressQueryProvider.realTimeQueryExpress(reqDTO); |             reqDTO.setExpressCompanyCode("yy"); | ||||||
|         assertNotNull(expressQueryRespDTOS); |             reqDTO.setLogisticsNo("YT9383342193097"); | ||||||
|  |             kdNiaoExpressQueryProvider.realTimeQueryExpress(reqDTO); | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Import({ |     @Import({ | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ spring: | |||||||
|     lazy-initialization: true # 开启懒加载,加快速度 |     lazy-initialization: true # 开启懒加载,加快速度 | ||||||
|     banner-mode: off # 单元测试,禁用 Banner |     banner-mode: off # 单元测试,禁用 Banner | ||||||
|  |  | ||||||
| --- #################### 数据库相关配置 #################### | --- #################### 交易快递查询相关配置 #################### | ||||||
|  |  | ||||||
| yudao: | yudao: | ||||||
|   trade: |   trade: | ||||||
| @@ -11,5 +11,8 @@ yudao: | |||||||
|       query: |       query: | ||||||
|         express-query-provider: kd_niao |         express-query-provider: kd_niao | ||||||
|         kd-niao: |         kd-niao: | ||||||
|           api-key: 8e22d97d-6a3d-442e-b243-2190c9f0cfdd |           api-key: xxx | ||||||
|           business-id: 1801700 |           business-id: xxxxxxxx | ||||||
|  |         kd100: | ||||||
|  |           customer: xxxx | ||||||
|  |           key: xxxxx | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 jason
					jason