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