【项目实践】公寓租赁项目(二):基于SpringBoot标签管理接口开发

接口说明

@Tag(name = "标签管理")
@RestController
@RequestMapping("/admin/label")
public class LabelController {

    @Autowired
    private LabelInfoService service;
}

一、根据类型查询标签全部列表接口

接口名称:labelList

请求方式:Get

请求路径:/admin/label/list

请求参数:type

根据type类型使用条件查询:

@Operation(summary = "(根据类型)查询标签列表")
    @GetMapping("list")
    public Result<List<LabelInfo>> labelList(@RequestParam(required = false) ItemType type) {
        LambdaQueryWrapper<LabelInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(type!=null,LabelInfo::getType,type);  //当type不等于null时进行条件查询
        List<LabelInfo> list = service.list(queryWrapper);
        return Result.ok(list);
    }
错误反思❌:根据业务流程来说,上述代码是没有问题的,但是经过测试之后,发现当传入type之后,无法传回来数据。日志显示报类型转换异常。

原因

首先我们要搞清楚具体的转换流程:

  • 请求流程:前端传入type参数经过SpringMVC的WebDataBinder组件负责将HTTP的请求参数绑定到Controller方法的参数,并实现参数类型的转换 ,此时参数经历第一次类型转换;接着经过MybatisPlus的TypeHandler,用于处理Java中的实体对象与数据库之间的数据类型转换 ,此时经过第二次类型转换。

  • 响应流程:SpringMVC中的HTTPMessageConverter组件负责Controller方法的返回值Java对象转换为HTTP响应体中的JSON字符串,或者将请求体中的JSON字符串转换为Controller方法中的参数(Java对象)。

WebDataBinder默认进行自动类型转换,例如StringIntegerStringDateStringBoolean等等,而且其中也包括了String到枚举类型(Enum)。

但是!String到枚举类型的默认规则只是根据实例名称转换为枚举对象实例,比如“APARTMENT”只能转换成“ItemType.APARTMENT”,并不能映射到该属性code,相反亦是一样。

👍解决方法:

由于WebDataBinder依赖于Converter实现类型转换,我们便可以根据实际情况自定义Converter去实现类型转换。

/**
 * 解决枚举类型不匹配的问题,自定义Converter
 */
@Component
public class StringToItemTypeConverter implements Converter<String, ItemType> {
    @Override
    public ItemType convert(String code) {
//        ItemType.class.getEnumConstants();  //方法一:利用反射获取枚举类型对象
        ItemType[] itemTypes = ItemType.values();  //方法二:使用values方法获取枚举类型对象
        for (ItemType itemType : itemTypes) {
            if (itemType.getCode().equals(Integer.valueOf(code))){  //使用getCode()方法判断与传入的code是否相等
                return itemType;
            }
        }
        throw new IllegalArgumentException("code"+code+"非法");
    }
}

接着要去配置类添加自定义的Converter。

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {    //实现WebMvcConfigurer,并实现addFormatters方法。

    @Autowired
    private StringToItemTypeConverter stringToItemTypeConverter;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(this.stringToItemTypeConverter);  //添加自定义的Converter  
    }


}

接着启动项目测试:

优化方法👍:因为我们有着很多的枚举类,因此如果像上述那样每个都需要写一个自定义的Converter,而且每个Converter实现的代码都大同小异,工作量会变得很大。所以我们使用ConverterFactory更加合适,这个接口可以将同一个转换逻辑应用到一个接口的所有实现类。因此只需要定义一个Converter就可以应用于该接口的使用实现类。
@Component
public class StringToBaseEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
    @Override
    public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
        return new Converter<String, T>() {
            @Override
            public T convert(String code) {
                T[] typeEnumConstants = targetType.getEnumConstants();
                for (T typeEnumConstant : typeEnumConstants) {
                    if (typeEnumConstant.equals(Integer.valueOf(code))){
                        return typeEnumConstant;
                    }
                }
                throw new IllegalArgumentException("code"+code+"错误");
            }
        };
    }
}

接着也需要到配置类里添加ConverterFactory。

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    
    @Autowired
    private StringToBaseEnumConverterFactory stringToBaseEnumConverterFactory;

    /**
     * 增加一个自定义的Converter去解决枚举类型参数类型不匹配的问题
     * @param registry
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(stringToBaseEnumConverterFactory);
    }


}

二、保存或修改标签信息接口

接口名称:saveOrUpdate

请求方式:Post

请求路径:/admin/label/saveOrUpdate

请求参数:{
  "id": 0,
  "type": "",
  "name": ""
}

@Operation(summary = "新增或修改标签信息")
    @PostMapping("saveOrUpdate")
    public Result saveOrUpdateLabel(@RequestBody LabelInfo labelInfo) {
        service.saveOrUpdate(labelInfo);
        return Result.ok();
    }

三、根据ID删除标签接口

接口名称:deleteById

请求方式:Delete

请求路径:/admin/label/deleteById

请求参数:id

@Operation(summary = "根据id删除标签信息")
    @DeleteMapping("deleteById")
    public Result deleteLabelById(@RequestParam Long id) {
        service.removeById(id);
        return Result.ok();
    }

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值