版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第SpringBoot之使用枚举参数案例详解接口开发过程中不免有表示类型的参数,比如0表示未知,1表示男,2表示女。通常有两种做法,一种是用数字表示,另一种是使用枚举实现。
使用数字表示就是通过契约形式,约定每个数字表示的含义,接口接收到参数,就按照约定对类型进行判断,接口维护成本比较大。
在Spring体系中,使用枚举表示,是借助Spring的Converter机制,可以将数字或字符串对应到枚举的序号或者name,然后将前端的输入转换为枚举类型。
在场景不复杂的场景中,枚举可以轻松胜任。
于是,迅速实现逻辑,准备提测。这个时候需求变了,不允许选择未知性别,只能选男或女,就没有0值。这样,因为取值是从1开始,而枚举的序号是从0开始,就会产生冲突。
还有一些不太多的场景,就是前端不期望类型都是用数字,可能期望用一些有意义的字符串表示。但是按照前端规范,需要用小写或者驼峰命名。但是后端的规范中,枚举必须是大写,又是冲突。
需求合不合理暂且不论,我们要保存对技术的探索精神。
首先确认需求。我们期望定义一个枚举类作为参数,接口访问的时候,可以是int类型的id,id取值不限于枚举的序号;也可以是String类型的code,code取值不限于枚举的name。换句话说,这个枚举有个id和code,随意定义,只要接口传过来匹配上,就能够自动转成枚举类型。
既然这样,我们就规范下id和code取值。为了扩展,定义三个接口:IdBaseEnum、CodeBaseEnum以及IdCodeBaseEnum。
publicinterfaceIdBaseEnum{
IntegergetId();
publicinterfaceCodeBaseEnum{
StringgetCode();
publicinterfaceIdCodeBaseEnumextendsIdBaseEnum,CodeBaseEnum{
接下来就该定义我们的主角了。
前面定义了三个接口,分别是单独id、单独code,和有id和code的。这样,我们就可以定义三种枚举,分别对应三个接口。三种方式类似,所以就不在文中重复列举了。感兴趣的可以关注公众号「看山的小屋」回复spring获取源码。
我们定义一个性别枚举,枚举包含id和code两个属性。
publicenumGenderIdCodeEnumimplementsIdCodeBaseEnum{
MALE(1,"male"),
FEMALE(2,"female");
privatefinalIntegerid;
privatefinalStringcode;
GenderIdCodeEnum(Integerid,Stringcode){
this.id=id;
this.code=code;
@Override
publicStringgetCode(){
returncode;
@Override
publicIntegergetId(){
returnid;
这里需要注意一点,id和code不能重复。
id与id、code与code不能重复,比如MAIL定义id是1,FAMLE就不能定义id是1了。
id与code之间也不能重复,比如,MALE定义id是1001,FEMALE定义code是1001。
这是由于Spring在转换参数的时候,将输入参数全部视为String类型。虽然我们定义id和code类型不同,但是在匹配的时候,都是按照字符串匹配的。如果存在相同值,就会产生歧义。
Converter和ConverterFactory
根据规范,接下来定义一下Converter和ConverterFactory。这些是Spring留给我们的扩展口,按照规范定义即可。
Converter类:
publicclassIdCodeToEnumConverterTextendsIdCodeBaseEnumimplementsConverterString,T{
privatefinalMapString,TidEnumMap=Maps.newHashMap();
privatefinalMapString,TcodeEnumMap=Maps.newHashMap();
publicIdCodeToEnumConverter(ClassTenumType){
Arrays.stream(enumType.getEnumConstants())
.forEach(x-{
idEnumMap.put(x.getId().toString(),x);
codeEnumMap.put(x.getCode(),x);
@Override
publicTconvert(Stringsource){
returnOptional.of(source)
.map(codeEnumMap::get)
.orElseGet(()-Optional.of(source)
.map(idEnumMap::get)
.orElseThrow(()-newCodeBaseException(ErrorResponseEnum.PARAMS_ENUM_NOT_MATCH)));
ConverterFactory类:
publicclassIdCodeToEnumConverterFactoryimplementsConverterFactoryString,IdCodeBaseEnum{
@SuppressWarnings("rawtypes")
privatestaticfinalMapClass,ConverterCONVERTERS=Maps.newHashMap();
@Override
publicTextendsIdCodeBaseEnumConverterString,TgetConverter(ClassTtargetType){
//noinspectionunchecked
ConverterString,Tconverter=CONVERTERS.get(targetType);
if(converter==null){
converter=newIdCodeToEnumConverter(targetType);
CONVERTERS.put(targetType,converter);
returnconverter;
这两个就是转换的核心了,我们只要将他们装配到Spring的类型转换器中,就能够实现枚举类型的自动转化了。
将我们定义的Converter和ConverterFactory注册到Spring的类型转换器中。
@Configuration
publicclassWebConfigimplementsWebMvcConfigurer{
@Override
publicvoidaddFormatters(FormatterRegistryregistry){
registry.addConverterFactory(newIdCodeToEnumConverterFactory());
registry.addConverterFactory(newCodeToEnumConverterFactory());
registry.addConverterFactory(newIdToEnumConverterFactory());
}
至此,核心定义全部结束。
写一个Controller作为测试入口:
@RestController
@RequestMapping("echo")
publicclassEchoController{
@GetMapping("gender-id-code")
publicStringgenderIdCode(@RequestParam("gender")GenderIdCodeEnumgender){
return();
}
准备测试用例测试:
@SpringBootTest(classes=SpringEnumParamApplication.class)
@AutoConfigureMockMvc
classEchoControllerTest{
@Autowired
privateMockMvcmockMvc;
@ParameterizedTest
@ValueSource(strings={"MALE","male","1"})
voidgenderIdCode(Stringgender)throwsException{
finalStringresult=mockMvc.perform(
MockMvcRequestBuilders.get("/echo/gender-id-code")
.param("gender",gender)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn()
.getResponse()
.getContentAsString();
Assertions.assertEquals("MALE",result);
}
实现枚举参数并不难,只要按照Spring的扩展规范实现即可。需要注意的是,注意枚举类中唯一的id和code。
本文是应用,下篇说一下原理。以及httpbody形式请求的枚举转换逻辑。
SpringBo
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 语文学科核心素养观照下的小学习作教学衔接策略
- 2026三年级数学上册 两位数乘一位数口算
- 2026二年级数学 北师大版儿童乐园时间认识
- 护理感染预防的实践指南
- 打架斗殴责任制度
- 扫黑除恶主体责任制度
- 承销商法律责任制度
- 抗震质量责任制度
- 护路联防部门责任制度
- 指挥中心工作责任制度
- 第一单元《写作:考虑目的和对象》八年级语文下册同步课件(统编版新教材)
- 2025~2026学年新版教科版六年级下册科学教学计划
- 2026上海烟草机械有限责任公司招聘9人笔试参考题库及答案解析
- 2026银行间市场数据报告库(上海)股份有限公司招聘30人笔试参考题库及答案解析
- 2026年吉安幼儿师范高等专科学校单招综合素质考试题库含答案详解(巩固)
- 电梯应急处置预案和应急救援措施方案
- 妇科妇科肿瘤靶向治疗护理
- 2026及未来5年中国凝血酶行业市场供需态势及未来趋势研判报告
- 雨课堂学堂在线学堂云《短视频创意与制作(北京邮电)》单元测试考核答案
- (2026年)心理健康中小学生主题班会课件
- 2024年首都医科大学辅导员招聘考试真题汇编附答案
评论
0/150
提交评论