运费微服务和redis存热门数据

诗林  金牌会员 | 2024-12-8 18:53:38 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 724|帖子 724|积分 2172

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
目次

运费模板微服务
接收前端发送的模板实体类
插入数据时使用的entity类对象
 BaseEntity类
查询运费模板服务
新增和修改运费模块
整体流程
代码实现
运费计算 
整体流程
总的代码 
 查找运费模板方法
计算重量方法
Redis存入热门数据
1.从nacos导入共享redis配置
2.自定义RedisTemplate,自定义序列化和反序列化方式
 3.修改代码
4.存入数据时报错


运费模板微服务

接收前端发送的模板实体类

   这里对实体类的每一个成员类变量使用了javax.validation.constraints注解来限制成员变量的值
  1. package com.sl.ms.carriage.domain.dto;
  2. import io.swagger.annotations.ApiModelProperty;
  3. import lombok.Data;
  4. import javax.validation.constraints.DecimalMin;
  5. import javax.validation.constraints.Max;
  6. import javax.validation.constraints.Min;
  7. import javax.validation.constraints.NotNull;
  8. import java.time.LocalDateTime;
  9. import java.util.List;
  10. /**
  11. * 运费模板对象
  12. */
  13. @Data
  14. public class CarriageDTO {
  15.     /**
  16.      * 运费模板id
  17.      */
  18.     @ApiModelProperty(value = "运费模板id")
  19.     private Long id;
  20.     /**
  21.      * 模板类型:1-同城寄,2-省内寄,3-经济区互寄,4-跨省
  22.      */
  23.     @ApiModelProperty(value = "模板类型:1-同城寄,2-省内寄,3-经济区互寄,4-跨省", required = true)
  24.     @Max(value = 4, message = "类型值必须是1、2、3、4")
  25.     @Min(value = 1, message = "类型值必须是1、2、3、4")
  26.     @NotNull(message = "模板类型不能为空")
  27.     private Integer templateType;
  28.     /**
  29.      * 运送类型:1-普快,2-特快
  30.      */
  31.     @ApiModelProperty(value = "运送类型:1-普快,2-特快", required = true)
  32.     @Max(value = 2, message = "类型值必须是1、2")
  33.     @Min(value = 1, message = "类型值必须是1、2")
  34.     @NotNull(message = "运送类型不能为空")
  35.     private Integer transportType;
  36.     /**
  37.      * 关联城市:1-全国,2-京津冀,3-江浙沪,4-川渝,5-黑吉辽
  38.      */
  39.     @ApiModelProperty(value = "关联城市:1-全国,2-京津冀,3-江浙沪,4-川渝,5-黑吉辽", required = true)
  40.     @NotNull(message = "关联城市不能为空")
  41.     private List<String> associatedCityList;
  42.     /**
  43.      * 首重价格
  44.      */
  45.     @ApiModelProperty(value = "首重价格", required = true)
  46.     @DecimalMin(value = "0.1", message = "首重价格必须大于0")
  47.     @NotNull(message = "首重价格不能为空")
  48.     private Double firstWeight;
  49.     /**
  50.      * 续重价格
  51.      */
  52.     @ApiModelProperty(value = "续重价格", required = true)
  53.     @DecimalMin(value = "0.1", message = "续重价格必须大于0")
  54.     @NotNull(message = "续重价格不能为空")
  55.     private Double continuousWeight;
  56.     /**
  57.      * 轻抛系数
  58.      */
  59.     @ApiModelProperty(value = "轻抛系数", required = true)
  60.     @Min(value = 1, message = "轻抛系数必须大于0")
  61.     @NotNull(message = "轻抛系数不能为空")
  62.     private Integer lightThrowingCoefficient;
  63.     /**
  64.      * 创建时间
  65.      */
  66.     @ApiModelProperty(value = "创建时间")
  67.     private LocalDateTime created;
  68.     /**
  69.      * 更新时间
  70.      */
  71.     @ApiModelProperty(value = "更新时间")
  72.     private LocalDateTime updated;
  73.     @ApiModelProperty(value = "运费")
  74.     private Double expense;
  75.     @ApiModelProperty(value = "计费重量,单位:kg")
  76.     private Double computeWeight;
  77. }
复制代码
插入数据时使用的entity类对象

  1. @Data
  2. @EqualsAndHashCode(callSuper = false)
  3. @AllArgsConstructor
  4. @NoArgsConstructor
  5. @TableName("sl_carriage")
  6. public class CarriageEntity extends BaseEntity {
  7.     private static final long serialVersionUID = -5358753714676282742L;
  8.     /**
  9.      * 模板类型:1-同城寄,2-省内寄,3-经济区互寄,4-跨省
  10.      */
  11.     private Integer templateType;
  12.     /**
  13.      * 运送类型:1-普快,2-特快
  14.      */
  15.     private Integer transportType;
  16.     /**
  17.      * 关联城市:1-全国,2-京津冀,3-江浙沪,4-川渝,5-黑吉辽
  18.      */
  19.     private String associatedCity;
  20.     /**
  21.      * 首重价格
  22.      */
  23.     private Double firstWeight;
  24.     /**
  25.      * 续重价格
  26.      */
  27.     private Double continuousWeight;
  28.     /**
  29.      * 轻抛系数
  30.      */
  31.     private Integer lightThrowingCoefficient;
  32. }
复制代码
 BaseEntity类

  1. @Data
  2. public abstract class BaseEntity implements Serializable {
  3.     @TableId
  4.     private Long id; //主键id
  5.     @TableField(fill = FieldFill.INSERT) //MP自动填充
  6.    
  7.     private LocalDateTime created;
  8.     @TableField(fill = FieldFill.INSERT_UPDATE)
  9.    
  10.     private LocalDateTime updated;
  11. }
复制代码
查询运费模板服务

  
  1. /**
  2. * 获取全部运费模板,按照创建时间倒序排序
  3. *
  4. * @return 运费模板对象列表
  5. */
复制代码
这里是通过工具类批量把entity类对象转换成dto对象,然后返回给前端
  1.     @Override
  2.     public List<CarriageDTO> findAll() {
  3.         // 构造查询条件,按创建时间倒序
  4.         LambdaQueryWrapper<CarriageEntity> wrapper = Wrappers.<CarriageEntity>lambdaQuery().orderByDesc(CarriageEntity::getCreated);
  5.         // 查询数据库
  6.         List<CarriageEntity> carriageEntities = baseMapper.selectList(wrapper);
  7.         // 将结果转换为DTO类型  使用CarriageUtils工具类
  8.         return carriageEntities.stream().map(CarriageUtils::toDTO).collect(Collectors.toList());
  9.     }
复制代码
新增和修改运费模块

整体流程



流程阐明:


  • 根据传入的CarriageDTO对象参数进行查询模板,判断模板是否存在,如果不存在直接落库
  • 如果存在,需要进一步的判断是否为经济区互寄,如果不是,阐明模板重复,不能落库
  • 如果是经济区互寄,再进一步的判断是否有重复的城市,如果是,模板重复,不能落库
  • 如果不重复,落库,响应返回
模板为什么不能重复?
因为运费的计算是通过模板进行的,如果存在多个模板,该基于哪个模板计算呢?所以模板是不能重复的。
代码实现

           // 校验运费模板是否存在,如果不存在直接插入 (查询条件: 模板类型  运输类型   如果是修改排除当前id)
        LambdaQueryWrapper<CarriageEntity> wrapper = Wrappers.<CarriageEntity>lambdaQuery()
                .eq(CarriageEntity::getTemplateType, carriageDto.getTemplateType())
                .eq(CarriageEntity::getTransportType, carriageDto.getTransportType())
                //如果有id字段值,就阐明是更新操纵,那么就需要把与自己id值一样的模板排撤除,不然会与自己模板类型一致冲突
                .ne(ObjectUtil.isNotEmpty(carriageDto.getId()), CarriageEntity::getId, carriageDto.getId());
  这段代码构建的条件查询对象,特别留意ne()方法,如果dto对象的id成员变量不为null,阐明就是更新操纵,就阐明在数据库中,有与这个对象千篇一律的模板,所以需要排撤除这个存在与数据库中的模板(根据id主键值)
     // 如果是经济区互寄类型,需进一步判断关联城市是否重复,通过集合取交集判断是否重复
        List<String> assCities = carriageEntityList.stream().map(CarriageEntity::getAssociatedCity)//得到每一个数据关联的城市字符串
                .map(s -> {
                    return s.split(",");//将每一个字符串酿成一个字符串数组
                })
                .flatMap(Arrays::stream)//将每一个字符串数组重新酿成流对象
                //TODO:不然直接网络的是List<String[]>类型
                .collect(Collectors.toList());
        Collection<String> intersection = CollUtil.intersection(assCities, carriageDto.getAssociatedCityList());
  在数据库中,关联城市字段是 2,3,4 使用,间隔的字符串类型,2是城市id。
  所以需要把这个字符串分割成字符数组。 
  .flatMap(Arrays::stream)
  将每一个字符串数组重新酿成流对象,不然直接网络的是List<String[]>类型,
  assCities是数据表中全部的关联城市集合,最后判断与dto传入的关联城市集合是否有重复
  

  1.     /**
  2.      * 流程说明:
  3.      * ● 根据传入的CarriageDTO对象参数进行查询模板,判断模板是否存在,如果不存在直接落库
  4.      * ● 如果存在,需要进一步的判断是否为经济区互寄,如果不是,说明模板重复,不能落库
  5.      * ● 如果是经济区互寄,再进一步的判断是否有重复的城市,如果是,模板重复,不能落库
  6.      * ● 如果不重复,落库,响应返回
  7.      * 模板为什么不能重复?
  8.      * 因为运费的计算是通过模板进行的,如果存在多个模板,该基于哪个模板计算呢?所以模板是不能重复的。
  9.      * @param carriageDto 新增/修改运费对象
  10.      * @return
  11.      *
  12.      * 模板类型常量 {@link com.sl.ms.carriage.domain.constant.CarriageConstant}
  13.      *
  14.      */
  15.     @Override
  16.     public CarriageDTO saveOrUpdate(CarriageDTO carriageDto) {
  17.         // 校验运费模板是否存在,如果不存在直接插入 (查询条件: 模板类型  运输类型   如果是修改排除当前id)
  18.         LambdaQueryWrapper<CarriageEntity> wrapper = Wrappers.<CarriageEntity>lambdaQuery()
  19.                 .eq(CarriageEntity::getTemplateType, carriageDto.getTemplateType())
  20.                 .eq(CarriageEntity::getTransportType, carriageDto.getTransportType())
  21.                 //如果有id字段值,就说明是更新操作,那么就需要把与自己id值一样的模板排除掉,不然会与自己模板类型一致冲突
  22.                 .ne(ObjectUtil.isNotEmpty(carriageDto.getId()), CarriageEntity::getId, carriageDto.getId());
  23.         List<CarriageEntity> carriageEntityList = super.list(wrapper);
  24.         // 如果没有重复的模板,可以直接插入或更新操作 (DTO 转 entity 保存成功 entity 转 DTO)
  25.         if (CollUtil.isEmpty(carriageEntityList)){
  26.             return saveOrUpdateCarriage(carriageDto);
  27.         }
  28.         // 如果存在重复模板,需要判断此次插入的是否为经济区互寄,非经济区互寄是不可以重复的
  29.         if(ObjectUtil.notEqual(carriageDto.getTemplateType(),CarriageConstant.ECONOMIC_ZONE)){
  30.             throw new SLException(CarriageExceptionEnum.NOT_ECONOMIC_ZONE_REPEAT);
  31.         }
  32.         // 如果是经济区互寄类型,需进一步判断关联城市是否重复,通过集合取交集判断是否重复
  33.         List<String> assCities = carriageEntityList.stream().map(CarriageEntity::getAssociatedCity)//获得每一个数据关联的城市字符串
  34.                 .map(s -> {
  35.                     return s.split(",");//将每一个字符串变成一个字符串数组
  36.                 })
  37.                 .flatMap(Arrays::stream)//将每一个字符串数组重新变成流对象
  38.                 //TODO:不然直接收集的是List<String[]>类型
  39.                 .collect(Collectors.toList());
  40.         Collection<String> intersection = CollUtil.intersection(assCities, carriageDto.getAssociatedCityList());
  41.         // 如果没有重复,可以新增或更新 (DTO 转 entity 保存成功 entity 转 DTO)
  42.         if(CollUtil.isEmpty(intersection)){
  43.             return saveOrUpdateCarriage(carriageDto);
  44.         }else{
  45.             throw new SLException(CarriageExceptionEnum.ECONOMIC_ZONE_CITY_REPEAT);
  46.         }
  47.     }
  48.     public CarriageDTO saveOrUpdateCarriage(CarriageDTO carriageDTO){
  49.         CarriageEntity entity = CarriageUtils.toEntity(carriageDTO);
  50.         super.saveOrUpdate(entity);
  51.         return CarriageUtils.toDTO(entity);
  52.     }
复制代码
运费计算 

整体流程



阐明:


  • 运费模板优先级:同城>省内>经济区互寄>跨省
  • 将体积转化成重量,与重量比力,取大值
总的代码 

  1. /**
  2.      * ● 运费模板优先级:同城>省内>经济区互寄>跨省
  3.      * ● 将体积转化成重量,与重量比较,取大值
  4.      * @param waybillDTO 运费计算对象
  5.      * @return
  6.      *
  7.      *  
  8.      */
  9.   
  10.     @Override
  11.     public CarriageDTO compute(WaybillDTO waybillDTO) {
  12.         // 根据参数查找运费模板 调用findCarriage方法
  13.         CarriageEntity carriage = findCarriage(waybillDTO);
  14.         // 计算重量,最小重量为1kg 调用getComputeWeight方法
  15.         double weight = getComputeWeight(waybillDTO, carriage);
  16.         // 计算运费  运费 = 首重价格 + (实际重量 - 1) * 续重架构
  17.         double money=carriage.getFirstWeight()+(weight-1)*carriage.getContinuousWeight();
  18.         // 结果四舍五入保留一位小数
  19.         money=NumberUtil.round(money,1).doubleValue();
  20.         // 封装运费和计算重量到 CarriageDTO,并返回
  21.         CarriageDTO carriageDTO = CarriageUtils.toDTO(carriage);
  22.         carriageDTO.setComputeWeight(weight);
  23.         carriageDTO.setExpense(money);
  24.         return carriageDTO;
  25.     }
复制代码
 查找运费模板方法

  1. /**
  2.      * 根据参数查找运费模板
  3.      * 运费模板优先级:同城>省内>经济区互寄>跨省
  4.      * @param waybillDTO 参数
  5.      * @return 运费模板
  6.      */
  7.     @Resource
  8.     private AreaFeign areaFeign;
  9.     private CarriageEntity findCarriage(WaybillDTO waybillDTO) {
  10.         // 如果 发件的城市id 和 收件的城市id相同, 查询同城模板 调用findByTemplateType方法
  11.         if(ObjectUtil.equal(waybillDTO.getSenderCityId(),waybillDTO.getReceiverCityId())){
  12.             CarriageEntity carriageEntity = findByTemplateType(CarriageConstant.SAME_CITY);
  13.             if(ObjectUtil.isNotEmpty(carriageEntity)){
  14.                 return carriageEntity;
  15.             }
  16.         }
  17.         // 如果没查到或不是同城,则获取收寄件地址省份id  使用AreaFeign结构查询
  18.         //根据areaFeign接口获取这个市所属的省id
  19.         Long receiveProvinceId = areaFeign.get(waybillDTO.getReceiverCityId()).getParentId();
  20.         Long senderProvinceId = areaFeign.get(waybillDTO.getSenderCityId()).getParentId();
  21.         // 如果 收发件的省份id相同,查询同省的模板  调用findByTemplateType方法
  22.         if(ObjectUtil.equal(receiveProvinceId,senderProvinceId)){
  23.             CarriageEntity carriageEntity = findByTemplateType(CarriageConstant.SAME_PROVINCE);
  24.             if(ObjectUtil.isNotEmpty(carriageEntity)){
  25.                 return carriageEntity;
  26.             }
  27.         }
  28.         // 如果没查到或不是同省,则查询是否为经济区互寄  调用findEconomicCarriage方法查询
  29.         CarriageEntity carriageEntity = findEconomicCarriage(receiveProvinceId,senderProvinceId);
  30.         if(ObjectUtil.isNotEmpty(carriageEntity)){
  31.             return carriageEntity;
  32.         }
  33.         // 如果没查到或不是经济区互寄,直接查跨省运费模板
  34.         carriageEntity = findByTemplateType(CarriageConstant.TRANS_PROVINCE);
  35.         if(ObjectUtil.isNotEmpty(carriageEntity)){
  36.             return carriageEntity;
  37.         }
  38.         // 如果最后没查到,直接抛自定义异常,提示模板未找到
  39.         if(ObjectUtil.isEmpty(carriageEntity)){
  40.             throw new SLException(CarriageExceptionEnum.NOT_FOUND);
  41.         }
  42.         return null;
  43.     }
  44. /**
  45.      * @param receiverProvinceId 收件省份id
  46.      * @param senderProvinceId 发件省份id
  47.      * @return
  48.      */
  49.     private CarriageEntity findEconomicCarriage(Long receiverProvinceId, Long senderProvinceId) {
  50.         //通过工具类EnumUtil 获取经济区城市配置枚举
  51.         LinkedHashMap<String, EconomicRegionEnum> enumMap = EnumUtil.getEnumMap(EconomicRegionEnum.class);
  52.         // 遍历所有经济区枚举值
  53.         EconomicRegionEnum targetEconomicEnum=null;
  54.         for (EconomicRegionEnum regionEnum : enumMap.values()) {
  55.             //     通过ArrayUtil工具类 判断发件网点 和 收件网点是否在同一经济区
  56.             if(ArrayUtil.containsAll(regionEnum.getValue(),receiverProvinceId,senderProvinceId)){
  57.                 //     如果在得到对应经济区枚举
  58.                 targetEconomicEnum=regionEnum;
  59.                 break;
  60.             }
  61.         }
  62.         // 循环遍历未发现所属经济区,方法直接返回null
  63.         if(ObjectUtil.isEmpty(targetEconomicEnum)){
  64.             return null;
  65.         }
  66.         // 如果有经济区 根据 模板类型=经济区, 运输类型=普快  关联城市=枚举的code值 查询
  67.         LambdaQueryWrapper<CarriageEntity> wrapper = Wrappers.<CarriageEntity>lambdaQuery()
  68.                 .eq(CarriageEntity::getTemplateType, CarriageConstant.ECONOMIC_ZONE)
  69.                 .eq(CarriageEntity::getTransportType, CarriageConstant.REGULAR_FAST)
  70.                 .like(CarriageEntity::getAssociatedCity, targetEconomicEnum.getCode());
  71.         return super.getOne(wrapper);
  72.     }
  73.     /**
  74.      * 根据模板类型查询模板
  75.      * @param templateType 模板类型:1-同城寄,2-省内寄,3-经济区互寄,4-跨省
  76.      * @return 运费模板
  77.      */
  78.     private CarriageEntity findByTemplateType(Integer templateType) {
  79.         // 根据模板类型,及运输类型 = CarriageConstant.REGULAR_FAST 查询模板
  80.         LambdaQueryWrapper<CarriageEntity> wrapper = Wrappers.<CarriageEntity>lambdaQuery()
  81.                 .eq(CarriageEntity::getTemplateType, templateType)
  82.                 .eq(CarriageEntity::getTransportType,CarriageConstant.REGULAR_FAST);
  83.         return super.getOne(wrapper);
  84.     }
复制代码
经济特区罗列类

  1. package com.sl.ms.carriage.domain.enums;
  2. /**
  3. * 经济区枚举
  4. */
  5. public enum EconomicRegionEnum {
  6.     BTH("2", new Long[] {1L, 7362L, 13267L}),
  7.     JZS("3", new Long[] {167904L, 191019L, 161792L}),
  8.     SC("4", new Long[] {545532L, 533328L}),
  9.     HJL("5", new Long[] {145665L, 133208L, 115224L});
  10.     /**
  11.      * 类型编码
  12.      */
  13.     private final String code;
  14.     /**
  15.      * 类型值
  16.      */
  17.     private final Long[] value;
  18.     EconomicRegionEnum(String code, Long[] value) {
  19.         this.code = code;
  20.         this.value = value;
  21.     }
  22.     public String getCode() {
  23.         return code;
  24.     }
  25.     public Long[] getValue() {
  26.         return value;
  27.     }
  28.     public static EconomicRegionEnum codeOf(String code) {
  29.         switch (code) {
  30.             case "2": {
  31.                 return BTH;
  32.             }
  33.             case "3": {
  34.                 return JZS;
  35.             }
  36.             case "4": {
  37.                 return SC;
  38.             }
  39.             case "5": {
  40.                 return HJL;
  41.             }
  42.             default: {
  43.                 return null;
  44.             }
  45.         }
  46.     }
  47. }
复制代码
计算重量方法

  1. /**
  2.      * 根据体积参数与实际重量计算计费重量
  3.      *
  4.      * @param waybillDTO 运费计算对象
  5.      * @param carriage   运费模板
  6.      * @return 计费重量
  7.      */
  8.     private double getComputeWeight(WaybillDTO waybillDTO, CarriageEntity carriage) {
  9.         // 计算体积,如果传入体积则不需要计算
  10.         Integer volume = waybillDTO.getVolume();
  11.         if(ObjectUtil.isEmpty(volume)){
  12.             try {
  13.                 volume=waybillDTO.getMeasureHigh()*waybillDTO.getMeasureLong()*waybillDTO.getMeasureWidth();
  14.             } catch (Exception e) {//防止有null值
  15.                 throw new RuntimeException(e);
  16.             }
  17.         }
  18.         // 计算体积重量  = 体积 / 轻抛系数  tips: 使用NumberUtil工具类计算 保留一位小数
  19.         BigDecimal weightByV = NumberUtil.div(volume, carriage.getLightThrowingCoefficient(), 1);
  20.         // 重量取大值 = 体积重量 和 实际重量 tips: 使用NumberUtil工具类计算   保留一位小数
  21.         double weight = NumberUtil.max(weightByV.doubleValue(), NumberUtil.round(waybillDTO.getWeight(), 1).doubleValue());
  22.         // 计算续重,规则:不满1kg,按1kg计费;
  23.         if(weight<=1){
  24.             return 1;
  25.         }
  26.         // 10kg以下续重以0.1kg计量保留1位小数;
  27.         if(weight<=10){
  28.             return weight;
  29.         }
  30.         // 100kg以上四舍五入取整  举例:108.4kg按照108kg收费 108.5kg按照109kg收费
  31.         // tips: 使用NumberUtil工具类计算
  32.         if(weight>=100){
  33.             return NumberUtil.round(weight,0).doubleValue();
  34.         }
  35.         // 10-100kg续重以0.5kg计量保留1位小数;
  36.         // 0.5为一个计算单位,举例:18.8kg按照19收费, 18.4kg按照18.5kg收费 18.1kg按照18.5kg收费
  37.         int i=NumberUtil.round(weight, 0, RoundingMode.DOWN).intValue();//向下取整
  38.         if(NumberUtil.sub(weight,i)==0){
  39.             return weight;
  40.         }else if(NumberUtil.sub(weight,i)<=0.5){
  41.             return NumberUtil.add(i,0.5);
  42.         }else{
  43.             return NumberUtil.add(i,1);
  44.         }
  45.     }
复制代码
Redis存入热门数据

思索:根据模板类型查询模板时需要频繁的查询数据库,性能较低,而且模板数据不会频繁变化,查询次数多,属于热门数据
所以可以使用redis存储模板entity类数据,
使用hash结构。大key->template 小key->发件城市id_收件城市
1.从nacos导入共享redis配置

  1. spring:
  2.   cloud:
  3.     nacos:
  4.       username: nacos
  5.       password: nacos
  6.       server-addr: 192.168.150.101:8848
  7.       discovery:
  8.         namespace: ecae68ba-7b43-4473-a980-4ddeb6157bdc
  9.         ip: 192.168.150.1
  10.       config:
  11.         namespace: ecae68ba-7b43-4473-a980-4ddeb6157bdc
  12.         shared-configs: #共享配置
  13.           - data-id: shared-spring-seata.yml
  14.             group: SHARED_GROUP
  15.             refresh: false
  16.           - data-id: shared-spring-mysql.yml
  17.             group: SHARED_GROUP
  18.             refresh: false
  19.           - data-id: shared-spring-mybatis-plus.yml
  20.             group: SHARED_GROUP
  21.             refresh: false
  22. #            导入redis共享配置
  23.           - data-id: shared-spring-redis.yml
  24.             group: SHARED_GROUP
  25.             refresh: false
复制代码
这是共享redis配置文件的内容,可以发现内里的值并没有进行定义,那在哪定义了呢
实在共享配置文件是定义了文件的结构,详细的内容由微服务的配置文件自己配置 

详细的配置在sl-express-ms-carriage.properties运费微服务自己的配置文件当中定义
 

2.自定义RedisTemplate,自定义序列化和反序列化方式

存入value值时使用json序列
  1. @Configuration//告诉Spring这是一个配置类,并让Spring加载这个类
  2. public class RedisConfig extends CachingConfigurerSupport {
  3.     @Bean
  4.     public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory factory){
  5.         RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<>();
  6.         //默认的key序列化器为:JdkSerializationRedisSerializer
  7.         //我们改成StringRedisSerializer
  8.         //键序列化
  9.         redisTemplate.setKeySerializer(new StringRedisSerializer());
  10.         //值序列化
  11.         // 创建一个json的序列化方式
  12.         GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
  13.         // 设置value用jackjson进行处理
  14.         redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
  15.         //key hashMap序列化
  16.         redisTemplate.setHashKeySerializer(new StringRedisSerializer());
  17.         //value hashMap序列化
  18.         redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
  19.         //连接工厂
  20.         redisTemplate.setConnectionFactory(factory);
  21.         return redisTemplate;
  22.     }
  23. }
复制代码
 3.修改代码

  1.     @Resource
  2.     private RedisTemplate redisTemplate;
  3.     @Override
  4.     public CarriageDTO compute(WaybillDTO waybillDTO) {
  5.         //TODO day02 计算运费
  6.         HashOperations operations = redisTemplate.opsForHash();
  7.         // 根据参数查找运费模板 调用findCarriage方法
  8.         //CarriageEntity carriage = findCarriage(waybillDTO);
  9.         /*
  10.          * 根据模板类型查询模板时需要频繁的查询数据库,性能较低,而且模板数据不会频繁变化,查询次数多,属于热点数据
  11.          * 可以存于redis中,使用hash结构。大key->template 小key->发件城市id_收件城市
  12.          */
  13.         //组装小key
  14.         String sKey = String.join("_", waybillDTO.getSenderCityId() + "", waybillDTO.getReceiverCityId() + "");
  15.         //先从redis中查数据
  16.         CarriageEntity carriage= (CarriageEntity) operations.get(RedisConstant.templateCode, sKey);
  17.         if(ObjectUtil.isEmpty(carriage)){
  18.             //redis没有改数据,就从数据库中查询
  19.             carriage=findCarriage(waybillDTO);
  20.             if(ObjectUtil.isEmpty(carriage)){
  21.                 return null;
  22.             }
  23.             //将数据存入redis
  24.             operations.put(RedisConstant.templateCode,sKey,carriage);
  25.         }
  26.         // 计算重量,最小重量为1kg 调用getComputeWeight方法
  27.         double weight = getComputeWeight(waybillDTO, carriage);
  28.         // 计算运费  运费 = 首重价格 + (实际重量 - 1) * 续重架构
  29.         double money=carriage.getFirstWeight()+(weight-1)*carriage.getContinuousWeight();
  30.         // 结果四舍五入保留一位小数
  31.         money=NumberUtil.round(money,1).doubleValue();
  32.         // 封装运费和计算重量到 CarriageDTO,并返回
  33.         CarriageDTO carriageDTO = CarriageUtils.toDTO(carriage);
  34.         carriageDTO.setComputeWeight(weight);
  35.         carriageDTO.setExpense(money);
  36.         return carriageDTO;
  37.     }
复制代码
4.存入数据时报错

   com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module 
"com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through 
reference chain: java.util.ArrayList[0]->com.zym.entity.Banner["gmtCreate"])
  解决:
导入依赖
  1. <dependency>
  2.             <groupId>com.fasterxml.jackson.datatype</groupId>
  3.             <artifactId>jackson-datatype-jsr310</artifactId>
  4.             <version>2.12.3</version>
  5.         </dependency>
复制代码
给LocalTime数据类型的成员变量规定序列化方式和反序列化方式
  1. @Data
  2. public abstract class BaseEntity implements Serializable {
  3.     @TableId
  4.     private Long id; //主键id
  5.     @TableField(fill = FieldFill.INSERT) //MP自动填充
  6.     @JsonDeserialize(using = LocalDateTimeDeserializer.class)                // 反序列化
  7.     @JsonSerialize(using = LocalDateTimeSerializer.class)                // 序列化
  8.     private LocalDateTime created;
  9.     @TableField(fill = FieldFill.INSERT_UPDATE)
  10.     @JsonDeserialize(using = LocalDateTimeDeserializer.class)                // 反序列化
  11.     @JsonSerialize(using = LocalDateTimeSerializer.class)                // 序列化
  12.     private LocalDateTime updated;
  13. }
复制代码

第二种代码方式

1.直接注入StringRedisTemplate模板类
这样一来就不用写配置类,重新定义RedisTemplate,它会把value序列化成String类型存入redis中
  1.   @Resource
  2.     private StringRedisTemplate stringRedisTemplate;
复制代码
 2.存取数据
  1. //获取hashKey
  2.         String sKey = StrUtil.format("{}_{}", waybillDTO.getSenderCityId(), waybillDTO.getReceiverCityId());
  3.         Object cacheData = stringRedisTemplate.opsForHash().get(RedisConstant.templateCode, sKey);
  4.         CarriageEntity carriage=null;
  5.         if(ObjectUtil.isNotEmpty(cacheData)){
  6. //将json数据反序列化成实体类对象,先将cacheData变成String类型,再反序列化
  7.             carriage= JSONUtil.toBean(StrUtil.toString(cacheData),CarriageEntity.class);
  8.         }else{
  9.             //从数据库中查
  10.             carriage = this.findCarriage(waybillDTO);
  11.             //将实体类转成json字符串存入redis中
  12.             stringRedisTemplate.opsForHash().put(RedisConstant.templateCode,sKey,JSONUtil.toJsonStr(carriage));
  13.         }
复制代码
效果


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

诗林

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表