Commit 0c283ded5dd67e656e6abe2c112ac7bc2a81b5ff
Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product
Showing
22 changed files
with
918 additions
and
1 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 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.hutool.json.JSONUtil; |
| 6 | 6 | import com.fasterxml.jackson.core.type.TypeReference; |
| 7 | +import com.fasterxml.jackson.databind.DeserializationFeature; | |
| 7 | 8 | import com.fasterxml.jackson.databind.JsonNode; |
| 8 | 9 | import com.fasterxml.jackson.databind.ObjectMapper; |
| 9 | 10 | import com.fasterxml.jackson.databind.SerializationFeature; |
| ... | ... | @@ -29,6 +30,7 @@ public class JsonUtils { |
| 29 | 30 | |
| 30 | 31 | static { |
| 31 | 32 | objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); |
| 33 | + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); | |
| 32 | 34 | objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化 |
| 33 | 35 | } |
| 34 | 36 | ... | ... |
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
| ... | ... | @@ -10,11 +10,14 @@ import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; |
| 10 | 10 | import org.springframework.beans.factory.annotation.Value; |
| 11 | 11 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 12 | 12 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| 13 | +import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; | |
| 13 | 14 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| 15 | +import org.springframework.boot.web.client.RestTemplateBuilder; | |
| 14 | 16 | import org.springframework.boot.web.servlet.FilterRegistrationBean; |
| 15 | 17 | import org.springframework.context.annotation.Bean; |
| 16 | 18 | import org.springframework.util.AntPathMatcher; |
| 17 | 19 | import org.springframework.web.bind.annotation.RestController; |
| 20 | +import org.springframework.web.client.RestTemplate; | |
| 18 | 21 | import org.springframework.web.cors.CorsConfiguration; |
| 19 | 22 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
| 20 | 23 | import org.springframework.web.filter.CorsFilter; |
| ... | ... | @@ -107,6 +110,15 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { |
| 107 | 110 | return createFilterBean(new DemoFilter(), WebFilterOrderEnum.DEMO_FILTER); |
| 108 | 111 | } |
| 109 | 112 | |
| 113 | + /** | |
| 114 | + * 创建 RestTemplate 实例 | |
| 115 | + * @param restTemplateBuilder {@link RestTemplateAutoConfiguration#restTemplateBuilder} | |
| 116 | + */ | |
| 117 | + @Bean | |
| 118 | + public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){ | |
| 119 | + return restTemplateBuilder.build(); | |
| 120 | + } | |
| 121 | + | |
| 110 | 122 | public static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) { |
| 111 | 123 | FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter); |
| 112 | 124 | bean.setOrder(order); | ... | ... |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
| ... | ... | @@ -53,7 +53,9 @@ public interface ErrorCodeConstants { |
| 53 | 53 | ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011003003, "已经存在该运费模板名"); |
| 54 | 54 | ErrorCode DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY = new ErrorCode(1011003004, "计算快递运费时,收件人地址编号为空"); |
| 55 | 55 | ErrorCode PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND = new ErrorCode(1011003005, "找不到到商品对应的运费模板"); |
| 56 | - ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011003006, "自提门店不存在"); | |
| 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, "自提门店不存在"); | |
| 57 | 59 | |
| 58 | 60 | // ========== Price 相关 1011004000 ============ |
| 59 | 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
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.config; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProviderEnum; | |
| 4 | +import lombok.Data; | |
| 5 | +import org.springframework.boot.context.properties.ConfigurationProperties; | |
| 6 | +import org.springframework.stereotype.Component; | |
| 7 | +import org.springframework.validation.annotation.Validated; | |
| 8 | + | |
| 9 | +import javax.validation.Valid; | |
| 10 | +import javax.validation.constraints.NotEmpty; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 交易快递查询的配置项 | |
| 14 | + * | |
| 15 | + * @author jason | |
| 16 | + */ | |
| 17 | +@Component | |
| 18 | +@ConfigurationProperties(prefix = "yudao.trade.express.query") | |
| 19 | +@Data | |
| 20 | +@Validated | |
| 21 | +public class TradeExpressQueryProperties { | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 快递查询服务商, 如果未配置,默认使用快递鸟 | |
| 25 | + */ | |
| 26 | + private ExpressQueryProviderEnum expressQueryProvider; | |
| 27 | + /** | |
| 28 | + * 快递鸟配置 | |
| 29 | + */ | |
| 30 | + @Valid | |
| 31 | + private KdNiaoConfig kdNiao; | |
| 32 | + /** | |
| 33 | + * 快递 100 配置 | |
| 34 | + */ | |
| 35 | + @Valid | |
| 36 | + private Kd100Config kd100; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 快递鸟配置项目 | |
| 40 | + */ | |
| 41 | + @Data | |
| 42 | + public static class KdNiaoConfig { | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * 快递鸟用户 ID | |
| 46 | + */ | |
| 47 | + @NotEmpty(message = "快递鸟用户 ID 配置项不能为空") | |
| 48 | + private String businessId; | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * 快递鸟 API Key | |
| 52 | + */ | |
| 53 | + @NotEmpty(message = "快递鸟 Api Key 配置项不能为空") | |
| 54 | + private String apiKey; | |
| 55 | + } | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * 快递100 配置项 | |
| 59 | + */ | |
| 60 | + @Data | |
| 61 | + public static class Kd100Config { | |
| 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; | |
| 72 | + } | |
| 73 | + | |
| 74 | + | |
| 75 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/ExpressQueryClient.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | |
| 4 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryRespDTO; | |
| 5 | + | |
| 6 | +import java.util.List; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 快递查询客户端 | |
| 10 | + * | |
| 11 | + * @author jason | |
| 12 | + */ | |
| 13 | +public interface ExpressQueryClient { | |
| 14 | + | |
| 15 | + /** | |
| 16 | + * 快递实时查询 | |
| 17 | + * | |
| 18 | + * @param reqDTO 查询请求参数 | |
| 19 | + */ | |
| 20 | + List<ExpressQueryRespDTO> realTimeQuery(ExpressQueryReqDTO reqDTO); | |
| 21 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/ExpressQueryProvider.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | |
| 4 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryRespDTO; | |
| 5 | + | |
| 6 | +import java.util.List; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 快递查询服务商 | |
| 10 | + * | |
| 11 | + * @author jason | |
| 12 | + */ | |
| 13 | +public interface ExpressQueryProvider { | |
| 14 | + /** | |
| 15 | + * 快递实时查询 | |
| 16 | + * | |
| 17 | + * @param reqDTO 查询请求参数 | |
| 18 | + */ | |
| 19 | + List<ExpressQueryRespDTO> realTimeQueryExpress(ExpressQueryReqDTO reqDTO); | |
| 20 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/ExpressQueryProviderEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core; | |
| 2 | + | |
| 3 | +import lombok.Getter; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 快递查询服务商枚举 | |
| 7 | + * | |
| 8 | + * @author jason | |
| 9 | + */ | |
| 10 | +@Getter | |
| 11 | +public enum ExpressQueryProviderEnum { | |
| 12 | + KD_NIAO("kd-niao", "快递鸟"), | |
| 13 | + KD_100("kd-100", "快递100"); | |
| 14 | + /** | |
| 15 | + * 快递服务商唯一编码 | |
| 16 | + */ | |
| 17 | + private final String code; | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 快递服务商名称 | |
| 21 | + */ | |
| 22 | + private final String name; | |
| 23 | + | |
| 24 | + ExpressQueryProviderEnum(String code, String name) { | |
| 25 | + this.code = code; | |
| 26 | + this.name = name; | |
| 27 | + } | |
| 28 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/ExpressQueryProviderFactory.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * 快递服务商工厂, 用于创建和缓存快递服务商服务 | |
| 5 | + * @author jason | |
| 6 | + */ | |
| 7 | +public interface ExpressQueryProviderFactory { | |
| 8 | + | |
| 9 | + /** | |
| 10 | + * 通过枚举获取快递查询服务商, 如果不存在。就创建一个对应的快递查询服务商 | |
| 11 | + * @param queryProviderEnum 快递服务商枚举 | |
| 12 | + */ | |
| 13 | + ExpressQueryProvider getOrCreateExpressQueryProvider(ExpressQueryProviderEnum queryProviderEnum); | |
| 14 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/convert/ExpressQueryConvert.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core.convert; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | |
| 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; | |
| 7 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryReqDTO; | |
| 8 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryRespDTO; | |
| 9 | +import org.mapstruct.Mapper; | |
| 10 | +import org.mapstruct.factory.Mappers; | |
| 11 | + | |
| 12 | +import java.util.List; | |
| 13 | + | |
| 14 | +@Mapper | |
| 15 | +public interface ExpressQueryConvert { | |
| 16 | + | |
| 17 | + ExpressQueryConvert INSTANCE = Mappers.getMapper(ExpressQueryConvert.class); | |
| 18 | + | |
| 19 | + List<ExpressQueryRespDTO> convertList(List<KdNiaoExpressQueryRespDTO.ExpressTrack> expressTrackList); | |
| 20 | + | |
| 21 | + List<ExpressQueryRespDTO> convertList2(List<Kd100ExpressQueryRespDTO.ExpressTrack> expressTrackList); | |
| 22 | + | |
| 23 | + KdNiaoExpressQueryReqDTO convert(ExpressQueryReqDTO dto); | |
| 24 | + | |
| 25 | + Kd100ExpressQueryReqDTO convert2(ExpressQueryReqDTO dto); | |
| 26 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/dto/ExpressQueryReqDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core.dto; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 快递查询 Req DTO | |
| 8 | + * | |
| 9 | + * @author jason | |
| 10 | + */ | |
| 11 | +@Data | |
| 12 | +public class ExpressQueryReqDTO { | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 快递公司编码 | |
| 16 | + * | |
| 17 | + * 对应 {@link DeliveryExpressDO#getCode()} } | |
| 18 | + */ | |
| 19 | + private String expressCompanyCode; | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 发货快递单号 | |
| 23 | + */ | |
| 24 | + private String logisticsNo; | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * 收、寄件人的电话号码 | |
| 28 | + */ | |
| 29 | + private String phone; | |
| 30 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/dto/ExpressQueryRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core.dto; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 快递查询 Resp DTO | |
| 7 | + * | |
| 8 | + * @author jason | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +public class ExpressQueryRespDTO { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * 发生时间 | |
| 15 | + */ | |
| 16 | + private String time; | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 快递状态 | |
| 20 | + */ | |
| 21 | + private String state; | |
| 22 | +} | ... | ... |
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/dto/provider/kdniao/KdNiaoExpressQueryReqDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao; | |
| 2 | + | |
| 3 | +import com.fasterxml.jackson.annotation.JsonInclude; | |
| 4 | +import com.fasterxml.jackson.annotation.JsonProperty; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 快递鸟快递查询 Req DTO | |
| 9 | + * | |
| 10 | + * @author jason | |
| 11 | + */ | |
| 12 | +@Data | |
| 13 | +@JsonInclude(JsonInclude.Include.NON_NULL) | |
| 14 | +public class KdNiaoExpressQueryReqDTO { | |
| 15 | + /** | |
| 16 | + * 快递公司编码 | |
| 17 | + */ | |
| 18 | + @JsonProperty("ShipperCode") | |
| 19 | + private String expressCompanyCode; | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 快递单号 | |
| 23 | + */ | |
| 24 | + @JsonProperty("LogisticCode") | |
| 25 | + private String logisticsNo; | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 订单编号 | |
| 29 | + */ | |
| 30 | + @JsonProperty("OrderCode") | |
| 31 | + private String orderNo; | |
| 32 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/dto/provider/kdniao/KdNiaoExpressQueryRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao; | |
| 2 | + | |
| 3 | +import com.fasterxml.jackson.annotation.JsonProperty; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.util.List; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 快递鸟快递查询 Resp DTO 参见 <a href="https://www.yuque.com/kdnjishuzhichi/dfcrg1/wugo6k">快递鸟接口文档</a> | |
| 10 | + * | |
| 11 | + * @author jason | |
| 12 | + */ | |
| 13 | +@Data | |
| 14 | +public class KdNiaoExpressQueryRespDTO { | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 快递公司编码 | |
| 18 | + */ | |
| 19 | + @JsonProperty("ShipperCode") | |
| 20 | + private String expressCompanyCode; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 快递单号 | |
| 24 | + */ | |
| 25 | + @JsonProperty("LogisticCode") | |
| 26 | + private String logisticsNo; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 订单编号 | |
| 30 | + */ | |
| 31 | + @JsonProperty("OrderCode") | |
| 32 | + private String orderNo; | |
| 33 | + | |
| 34 | + @JsonProperty("EBusinessID") | |
| 35 | + private String businessId; | |
| 36 | + @JsonProperty("State") | |
| 37 | + private String state; | |
| 38 | + /** | |
| 39 | + * 成功与否 | |
| 40 | + */ | |
| 41 | + @JsonProperty("Success") | |
| 42 | + private Boolean success; | |
| 43 | + /** | |
| 44 | + * 失败原因 | |
| 45 | + */ | |
| 46 | + @JsonProperty("Reason") | |
| 47 | + private String reason; | |
| 48 | + | |
| 49 | + @JsonProperty("Traces") | |
| 50 | + private List<ExpressTrack> tracks; | |
| 51 | + | |
| 52 | + @Data | |
| 53 | + public static class ExpressTrack { | |
| 54 | + /** | |
| 55 | + * 轨迹发生时间 | |
| 56 | + */ | |
| 57 | + @JsonProperty("AcceptTime") | |
| 58 | + private String time; | |
| 59 | + /** | |
| 60 | + * 轨迹描述 | |
| 61 | + */ | |
| 62 | + @JsonProperty("AcceptStation") | |
| 63 | + private String state; | |
| 64 | + } | |
| 65 | + | |
| 66 | +// { | |
| 67 | +// "EBusinessID": "1237100", | |
| 68 | +// "Traces": [], | |
| 69 | +// "State": "0", | |
| 70 | +// "ShipperCode": "STO", | |
| 71 | +// "LogisticCode": "638650888018", | |
| 72 | +// "Success": true, | |
| 73 | +// "Reason": "暂无轨迹信息" | |
| 74 | +// } | |
| 75 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/impl/ExpressQueryClientImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core.impl; | |
| 2 | + | |
| 3 | +import cn.hutool.core.lang.Assert; | |
| 4 | +import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressQueryProperties; | |
| 5 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryClient; | |
| 6 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProvider; | |
| 7 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProviderEnum; | |
| 8 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProviderFactory; | |
| 9 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | |
| 10 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryRespDTO; | |
| 11 | +import lombok.extern.slf4j.Slf4j; | |
| 12 | +import org.springframework.stereotype.Component; | |
| 13 | + | |
| 14 | +import javax.annotation.PostConstruct; | |
| 15 | +import javax.annotation.Resource; | |
| 16 | +import java.util.List; | |
| 17 | + | |
| 18 | +import static cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProviderEnum.KD_NIAO; | |
| 19 | + | |
| 20 | +/** | |
| 21 | + * 快递查询客户端实现 | |
| 22 | + * | |
| 23 | + * @author jason | |
| 24 | + */ | |
| 25 | +@Component | |
| 26 | +@Slf4j | |
| 27 | +public class ExpressQueryClientImpl implements ExpressQueryClient { | |
| 28 | + @Resource | |
| 29 | + private ExpressQueryProviderFactory expressQueryProviderFactory; | |
| 30 | + @Resource | |
| 31 | + private TradeExpressQueryProperties tradeExpressQueryProperties; | |
| 32 | + | |
| 33 | + private ExpressQueryProvider expressQueryProvider; | |
| 34 | + @PostConstruct | |
| 35 | + private void init(){ | |
| 36 | + ExpressQueryProviderEnum queryProvider = tradeExpressQueryProperties.getExpressQueryProvider(); | |
| 37 | + if (queryProvider == null) { | |
| 38 | + // 如果未设置,默认使用快递鸟 | |
| 39 | + queryProvider = KD_NIAO; | |
| 40 | + } | |
| 41 | + expressQueryProvider = expressQueryProviderFactory.getOrCreateExpressQueryProvider(queryProvider); | |
| 42 | + if (expressQueryProvider == null) { | |
| 43 | + // 记录错误日志 | |
| 44 | + log.error("获取创建快递查询服务商{}失败,请检查相关配置", queryProvider); | |
| 45 | + } | |
| 46 | + Assert.notNull(expressQueryProvider, "快递查询服务商不能为空"); | |
| 47 | + | |
| 48 | + } | |
| 49 | + @Override | |
| 50 | + public List<ExpressQueryRespDTO> realTimeQuery(ExpressQueryReqDTO reqDTO) { | |
| 51 | + return expressQueryProvider.realTimeQueryExpress(reqDTO); | |
| 52 | + } | |
| 53 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/impl/ExpressQueryProviderFactoryImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core.impl; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressQueryProperties; | |
| 4 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProvider; | |
| 5 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProviderEnum; | |
| 6 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProviderFactory; | |
| 7 | +import org.springframework.stereotype.Component; | |
| 8 | +import org.springframework.web.client.RestTemplate; | |
| 9 | + | |
| 10 | +import javax.annotation.Resource; | |
| 11 | +import java.util.Map; | |
| 12 | +import java.util.concurrent.ConcurrentHashMap; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * @author jason | |
| 16 | + */ | |
| 17 | +@Component | |
| 18 | +public class ExpressQueryProviderFactoryImpl implements ExpressQueryProviderFactory { | |
| 19 | + | |
| 20 | + private final Map<ExpressQueryProviderEnum, ExpressQueryProvider> providerMap = new ConcurrentHashMap<>(8); | |
| 21 | + @Resource | |
| 22 | + private TradeExpressQueryProperties tradeExpressQueryProperties; | |
| 23 | + @Resource | |
| 24 | + private RestTemplate restTemplate; | |
| 25 | + | |
| 26 | + @Override | |
| 27 | + public ExpressQueryProvider getOrCreateExpressQueryProvider(ExpressQueryProviderEnum queryProviderEnum) { | |
| 28 | + return providerMap.computeIfAbsent(queryProviderEnum, | |
| 29 | + provider -> createExpressQueryProvider(provider, tradeExpressQueryProperties)); | |
| 30 | + } | |
| 31 | + | |
| 32 | + private ExpressQueryProvider createExpressQueryProvider(ExpressQueryProviderEnum queryProviderEnum, | |
| 33 | + TradeExpressQueryProperties tradeExpressQueryProperties) { | |
| 34 | + ExpressQueryProvider result = null; | |
| 35 | + switch (queryProviderEnum) { | |
| 36 | + case KD_NIAO: | |
| 37 | + result = new KdNiaoExpressQueryProvider(restTemplate, tradeExpressQueryProperties.getKdNiao()); | |
| 38 | + break; | |
| 39 | + case KD_100: | |
| 40 | + result = new Kd100ExpressQueryProvider(restTemplate, tradeExpressQueryProperties.getKd100()); | |
| 41 | + break; | |
| 42 | + } | |
| 43 | + return result; | |
| 44 | + } | |
| 45 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/impl/Kd100ExpressQueryProvider.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core.impl; | |
| 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; | |
| 7 | +import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressQueryProperties; | |
| 8 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProvider; | |
| 9 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | |
| 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; | |
| 17 | +import org.springframework.web.client.RestTemplate; | |
| 18 | + | |
| 19 | +import java.util.Collections; | |
| 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; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * 快递 100 服务商 | |
| 30 | + * | |
| 31 | + * @author jason | |
| 32 | + */ | |
| 33 | +@Slf4j | |
| 34 | +public class Kd100ExpressQueryProvider implements ExpressQueryProvider { | |
| 35 | + | |
| 36 | + private static final String REAL_TIME_QUERY_URL = "https://poll.kuaidi100.com/poll/query.do"; | |
| 37 | + private final RestTemplate restTemplate; | |
| 38 | + | |
| 39 | + private final TradeExpressQueryProperties.Kd100Config config; | |
| 40 | + | |
| 41 | + public Kd100ExpressQueryProvider(RestTemplate restTemplate, TradeExpressQueryProperties.Kd100Config config) { | |
| 42 | + this.restTemplate = restTemplate; | |
| 43 | + this.config = config; | |
| 44 | + } | |
| 45 | + | |
| 46 | + @Override | |
| 47 | + public List<ExpressQueryRespDTO> realTimeQueryExpress(ExpressQueryReqDTO reqDTO) { | |
| 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); | |
| 106 | + } | |
| 107 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/impl/KdNiaoExpressQueryProvider.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.framework.delivery.core.impl; | |
| 2 | + | |
| 3 | +import cn.hutool.core.codec.Base64; | |
| 4 | +import cn.hutool.core.collection.CollUtil; | |
| 5 | +import cn.hutool.core.net.URLEncodeUtil; | |
| 6 | +import cn.hutool.crypto.digest.DigestUtil; | |
| 7 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 8 | +import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressQueryProperties; | |
| 9 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.ExpressQueryProvider; | |
| 10 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.ExpressQueryReqDTO; | |
| 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; | |
| 13 | +import cn.iocoder.yudao.module.trade.framework.delivery.core.dto.provider.kdniao.KdNiaoExpressQueryRespDTO; | |
| 14 | +import lombok.extern.slf4j.Slf4j; | |
| 15 | +import org.springframework.http.*; | |
| 16 | +import org.springframework.util.LinkedMultiValueMap; | |
| 17 | +import org.springframework.util.MultiValueMap; | |
| 18 | +import org.springframework.web.client.RestTemplate; | |
| 19 | + | |
| 20 | +import java.util.Collections; | |
| 21 | +import java.util.List; | |
| 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; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * 快递鸟服务商 | |
| 30 | + * | |
| 31 | + * @author jason | |
| 32 | + */ | |
| 33 | +@Slf4j | |
| 34 | +public class KdNiaoExpressQueryProvider implements ExpressQueryProvider { | |
| 35 | + private static final String REAL_TIME_QUERY_URL = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx"; | |
| 36 | + /** | |
| 37 | + * 快递鸟即时查询免费版 RequestType | |
| 38 | + */ | |
| 39 | + private static final String REAL_TIME_FREE_REQ_TYPE = "1002"; | |
| 40 | + private final RestTemplate restTemplate; | |
| 41 | + private final TradeExpressQueryProperties.KdNiaoConfig config; | |
| 42 | + | |
| 43 | + public KdNiaoExpressQueryProvider(RestTemplate restTemplate, TradeExpressQueryProperties.KdNiaoConfig config) { | |
| 44 | + this.restTemplate = restTemplate; | |
| 45 | + this.config = config; | |
| 46 | + } | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 快递鸟即时查询免费版本 参见 <a href="https://www.yuque.com/kdnjishuzhichi/dfcrg1/wugo6k">快递鸟接口文档</a> | |
| 50 | + * @param reqDTO 查询请求参数 | |
| 51 | + */ | |
| 52 | + @Override | |
| 53 | + public List<ExpressQueryRespDTO> realTimeQueryExpress(ExpressQueryReqDTO reqDTO) { | |
| 54 | + KdNiaoExpressQueryReqDTO kdNiaoReqData = INSTANCE.convert(reqDTO); | |
| 55 | + // 快递公司编码需要转成大写 | |
| 56 | + kdNiaoReqData.setExpressCompanyCode(reqDTO.getExpressCompanyCode().toUpperCase()); | |
| 57 | + KdNiaoExpressQueryRespDTO respDTO = sendKdNiaoApiRequest(REAL_TIME_QUERY_URL, REAL_TIME_FREE_REQ_TYPE, | |
| 58 | + kdNiaoReqData, KdNiaoExpressQueryRespDTO.class); | |
| 59 | + log.debug("快递鸟即时查询接口返回 {}", respDTO); | |
| 60 | + if(!respDTO.getSuccess()){ | |
| 61 | + throw exception(EXPRESS_API_QUERY_FAILED, respDTO.getReason()); | |
| 62 | + }else{ | |
| 63 | + if (CollUtil.isNotEmpty(respDTO.getTracks())) { | |
| 64 | + return INSTANCE.convertList(respDTO.getTracks()); | |
| 65 | + }else{ | |
| 66 | + return Collections.emptyList(); | |
| 67 | + } | |
| 68 | + } | |
| 69 | + } | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * 快递鸟 通用的 API 请求, 暂时没有其他应用场景, 暂时放这里 | |
| 73 | + * @param url 请求 url | |
| 74 | + * @param requestType 对应的请求指令 (快递鸟的RequestType) | |
| 75 | + * @param req 对应请求的请求参数 | |
| 76 | + * @param respClass 对应请求的响应 class | |
| 77 | + * @param <Req> 每个请求的请求结构 Req DTO | |
| 78 | + * @param <Resp> 每个请求的响应结构 Resp DTO | |
| 79 | + */ | |
| 80 | + private <Req, Resp> Resp sendKdNiaoApiRequest(String url, String requestType, Req req, | |
| 81 | + Class<Resp> respClass){ | |
| 82 | + // 请求头 | |
| 83 | + HttpHeaders headers = new HttpHeaders(); | |
| 84 | + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); | |
| 85 | + // 请求体 | |
| 86 | + String reqData = JsonUtils.toJsonString(req); | |
| 87 | + String dataSign = generateDataSign(reqData, config.getApiKey()); | |
| 88 | + log.trace("得到快递鸟接口 RequestType : {} 的 签名: {}", requestType, dataSign); | |
| 89 | + MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>(); | |
| 90 | + requestBody.add("RequestData", reqData); | |
| 91 | + requestBody.add("DataType", "2"); | |
| 92 | + requestBody.add("EBusinessID", config.getBusinessId()); | |
| 93 | + requestBody.add("DataSign", dataSign); | |
| 94 | + requestBody.add("RequestType", requestType); | |
| 95 | + log.debug("快递鸟接口 RequestType : {}, 的请求参数 {}", requestType, requestBody); | |
| 96 | + HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(requestBody, headers); | |
| 97 | + // 发送请求 | |
| 98 | + ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); | |
| 99 | + log.debug("快递鸟接口 RequestType : {}, 的响应结果 {}", requestType, responseEntity); | |
| 100 | + // 处理响应 | |
| 101 | + if (responseEntity.getStatusCode().is2xxSuccessful()) { | |
| 102 | + String response = responseEntity.getBody(); | |
| 103 | + return JsonUtils.parseObject(response, respClass); | |
| 104 | + } else { | |
| 105 | + throw exception(EXPRESS_API_QUERY_ERROR); | |
| 106 | + } | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * 快递鸟生成请求签名 参见 <a href="https://www.yuque.com/kdnjishuzhichi/dfcrg1/zes04h">签名说明</a> | |
| 111 | + * @param reqData 请求实体 | |
| 112 | + * @param apiKey api Key | |
| 113 | + */ | |
| 114 | + private String generateDataSign(String reqData, String apiKey) { | |
| 115 | + String plainText = String.format("%s%s", reqData, apiKey); | |
| 116 | + log.trace("签名前的数据 {}", plainText); | |
| 117 | + return URLEncodeUtil.encode(Base64.encode(DigestUtil.md5Hex(plainText))); | |
| 118 | + } | |
| 119 | +} | ... | ... |
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 | 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
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.assertThrows; | |
| 19 | + | |
| 20 | +/** | |
| 21 | + * @author jason | |
| 22 | + */ | |
| 23 | +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = KdNiaoExpressQueryProviderTest.Application.class) | |
| 24 | +@ActiveProfiles("trade-delivery-query") // 设置使用 trade-delivery-query 配置文件 | |
| 25 | +public class KdNiaoExpressQueryProviderTest { | |
| 26 | + @Resource | |
| 27 | + private RestTemplateBuilder builder; | |
| 28 | + @Resource | |
| 29 | + private TradeExpressQueryProperties expressQueryProperties; | |
| 30 | + | |
| 31 | + private KdNiaoExpressQueryProvider kdNiaoExpressQueryProvider; | |
| 32 | + | |
| 33 | + @BeforeEach | |
| 34 | + public void init(){ | |
| 35 | + kdNiaoExpressQueryProvider = new KdNiaoExpressQueryProvider(builder.build(),expressQueryProperties.getKdNiao()); | |
| 36 | + } | |
| 37 | + @Test | |
| 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 | + }); | |
| 46 | + } | |
| 47 | + | |
| 48 | + @Import({ | |
| 49 | + RestTemplateAutoConfiguration.class | |
| 50 | + }) | |
| 51 | + @EnableConfigurationProperties(TradeExpressQueryProperties.class) | |
| 52 | + public static class Application { | |
| 53 | + } | |
| 54 | +} | |
| 0 | 55 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-trade-delivery-query.yaml
0 → 100644
| 1 | +spring: | |
| 2 | + main: | |
| 3 | + lazy-initialization: true # 开启懒加载,加快速度 | |
| 4 | + banner-mode: off # 单元测试,禁用 Banner | |
| 5 | + | |
| 6 | +--- #################### 交易快递查询相关配置 #################### | |
| 7 | + | |
| 8 | +yudao: | |
| 9 | + trade: | |
| 10 | + express: | |
| 11 | + query: | |
| 12 | + express-query-provider: kd_niao | |
| 13 | + kd-niao: | |
| 14 | + api-key: xxx | |
| 15 | + business-id: xxxxxxxx | |
| 16 | + kd100: | |
| 17 | + customer: xxxx | |
| 18 | + key: xxxxx | ... | ... |