【SpringBoot + Vue 尚庭公寓实战】标签管理接口优化(四)
1.标签管理
标签管理共有三个接口,分别是[根据类型]查询标签列表、保存或更新标签信息和根据ID删除标签,下面逐一实现。
首先在LabelController
中注入LabelInfoService
依赖,如下
@Tag(name = "标签管理")
@RestController
@RequestMapping("/admin/label")
public class LabelController {@Autowiredprivate LabelInfoService service;
}
1.1@RestController
(1) @RestController组合注解,等同于 @Controller
和 @ResponseBody
的结合使用,常用于编写 RESTful 风格的 Web 服务;
(2) @Controller:用于标记控制层(Controller),表示这是 MVC 架构中的控制器组件。Spring 会自动扫描使用了 @Controller 注解的类,并将其注册为控制器 Bean,在处理请求时自动将请求映射到相应的 @RequestMapping 注解标注的方法中进行处理。
1.2@RequestMapping
@RequestMapping注解是一个用来处理请求地址映射的注解,可用于映射一个请求或一个方法,可以用在类或方法上。
2. [根据类型]查询标签列表
在LabelController
中增加如下内容
@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);List<LabelInfo> list = service.list(queryWrapper);return Result.ok(list);
}
2.1@Operation
@Operation(v3)接口注释
@Operation(summary = " ", description = " ")
2.2@GetMapping
@GetMapping注解可以用于类和方法上,用于定义HTTP GET请求的URL路径。当客户端发送HTTP GET请求时,Spring Boot会自动将请求映射到具有相应URL路径的控制器方法上。
2.3WebDataBinder枚举类型转换
WebDataBinder
依赖于Converter实现类型转换,若Controller方法声明的@RequestParam
参数的类型不是String
,WebDataBinder
就会自动进行数据类型转换。SpringMVC提供了常用类型的转换器,例如String
到Integer
、String
到Date
,String
到Boolean
等等,其中也包括String
到枚举类型,但是String
到枚举类型的默认转换规则是根据实例名称("APARTMENT")转换为枚举对象实例(ItemType.APARTMENT)。若想实现code
属性到枚举对象实例的转换,需要自定义Converter
,代码如下,具体内容可参考官方文档。
(1)在web-admin模块自定义com.atguigu.lease.web.admin.custom.converter.StringToItemTypeConverter
@Component
public class StringToItemTypeConverter implements Converter<String, ItemType> {@Overridepublic ItemType convert(String code) {for (ItemType value : ItemType.values()) {if (value.getCode().equals(Integer.valueOf(code))) {return value;}}throw new IllegalArgumentException("code非法");}
}
(2) 注册上述的StringToItemTypeConverter
,在web-admin模块创建com.atguigu.lease.web.admin.custom.config.WebMvcConfiguration
,内容如下:
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {@Autowiredprivate StringToItemTypeConverter stringToItemTypeConverter;@Overridepublic void addFormatters(FormatterRegistry registry) {registry.addConverter(this.stringToItemTypeConverter);}
}
2.4优化
但是我们有很多的枚举类型都需要考虑类型转换这个问题,按照上述思路,我们需要为每个枚举类型都定义一个Converter,并且每个Converter的转换逻辑都完全相同,针对这种情况,我们使用ConverterFactory接口更为合适,这个接口可以将同一个转换逻辑应用到一个接口的所有实现类,因此我们可以定义一个BaseEnum
接口,然后另所有的枚举类都实现该接口,然后就可以自定义ConverterFactory
,集中编写各枚举类的转换逻辑了。具体实现如下:
(1)在model模块定义com.atguigu.lease.model.enums.BaseEnum
接口
public interface BaseEnum {Integer getCode();String getName();
}
(2)令所有com.atguigu.lease.model.enums
包下的枚举类都实现BaseEnun
接口
在web-admin模块自定义com.atguigu.lease.web.admin.custom.converter.StringToBaseEnumConverterFactory
@Component
public class StringToBaseEnumConverterFactory implements ConverterFactory<String, BaseEnum> {@Overridepublic <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {return new Converter<String, T>() {@Overridepublic T convert(String source) {for (T enumConstant : targetType.getEnumConstants()) {if (enumConstant.getCode().equals(Integer.valueOf(source))) {return enumConstant;}}throw new IllegalArgumentException("非法的枚举值:" + source);}};}
}
(3) 注册上述的ConverterFactory
,在web-admin模块创建com.atguigu.lease.web.admin.custom.config.WebMvcConfiguration
,内容如下:
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {@Autowiredprivate StringToBaseEnumConverterFactory stringToBaseEnumConverterFactory;@Overridepublic void addFormatters(FormatterRegistry registry) {registry.addConverterFactory(this.stringToBaseEnumConverterFactory);}
}
注意:
最终采用的是ConverterFactory
方案,因此StringToItemTypeConverter
相关代码可以直接删除。
3.保存或更新标签信息
在LabelController
中增加如下内容
@Operation(summary = "保存或更新标签信息")
@PostMapping("saveOrUpdate")
public Result saveOrUpdateFacility(@RequestBody LabelInfo labelInfo) {service.saveOrUpdate(labelInfo);return Result.ok();
}
4. 根据ID删除标签
在LabelController
中增加如下内容
@Operation(summary = "根据id删除标签信息")
@DeleteMapping("deleteById")
public Result deleteLabelById(@RequestParam Long id) {service.removeById(id);return Result.ok();
}
4.1@DeleteMapping
有些时候,有的数据可能不再需要了,客户端可以通过HTTP DELETE请求来要移除某个资源。
而 @DeleteMapping 注解就能够非常便捷的声明能够处理DELETE请求的方法。举个栗子:
我们想要有一个能够删除订单资源的API,下面的方法就能实现这一点:
@DeleteMapping("/{orderId}")
@ResponseStatus(code=HttpStatus.NO_CONTENT)
public void deleteOrder(@PathVariable("orderId") Long orderId){try{repo.deleteById(orderId);}catch(EmptyResultDataAccessException e){}
}
在这个方法中,真正负责删除订单的是里面的代码,@DeleteMapping指定deleteOrder()方法处理针对“/orders/{orderId}的DELETE请求。
在该方法中,需要注意的是,@ResponseStatus注解确保的是HTTP状态码为204。对于已经不存在的资源,我们没有必要返回任何的资源数据给客户端,因此DELETE请求中通常没有响应体,我们要以HTTP状态码的形式让客户端知道不要期望得到任何的内容。