在本篇文章中,我们将探讨在 Spring Boot 中实现不区分大小写的enum映射的不同方法。
创新互联公司专注于衡水网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供衡水营销型网站建设,衡水网站制作、衡水网页设计、衡水网站官网定制、成都微信小程序服务,打造衡水网络公司原创品牌,更为您提供衡水网站排名全网营销落地服务。首先,我们将了解enum在 Spring 中是如何默认映射的。然后,我们将学习如何应对大小写的区分。
2、Spring默认enum映射Spring 在处理请求参数时依赖于几个内置的转换器来处理字符串转换。
通常,当我们将枚举作为请求参数传递时,它会在后台使用StringToEnumConverterFactory将传递的字符串转换为枚举。
按照设计,此转换器调用Enum.valueOf(Class, String)这意味着给定的字符串必须与声明的枚举常量之一完全匹配。
例如,让我们考虑Level枚举:
public enum Level {LOW, MEDIUM, HIGH
}
接下来,让我们创建一个接受枚举作为参数的处理程序方法:
@RestController
@RequestMapping("enummapping")
public class EnumMappingController {@GetMapping("/get")
public String getByLevel(@RequestParam(required = false) Level level){return level.name();
}
}
使用 CURL向http://localhost:8080/enummapping/get?level=MEDIUM发送请求:
curl http://localhost:8080/enummapping/get?level=MEDIUM
处理程序方法发回MEDIUM,枚举常量MEDIUM的名称。现在,让我们传递medium而不是MEDIUM,看看会发生什么:
curl http://localhost:8080/enummapping/get?level=medium
{"timestamp":"2022-11-18T18:41:11.440+00:00","status":400,"error":"Bad Request","path":"/enummapping/get"}
正如我们所看到的,请求被认为是无效的并且应用程序失败并出现错误:
Failed to convert value of type 'java.lang.String' to required type 'com.baeldung.enummapping.enums.Level';
nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam com.baeldung.enummapping.enums.Level] for value 'medium';
...
查看堆栈跟踪,我们可以看到 Spring 抛出了ConversionFailedException。它没有识别为枚举常量。
3、不区分大小写的枚举映射Spring 提供了几种方便的方法来解决映射枚举时区分大小写的问题。让我们仔细看看每种方法。
3.1、使用ApplicationConversionServiceApplicationConversionService类带有一组已配置的转换器和格式化程序。
在这些开箱即用的转换器中,我们找到了StringToEnumIgnoringCaseConverterFactory。顾名思义,它以不区分大小写的方式将字符串转换为枚举。
首先,我们需要添加和配置ApplicationConversionService:
@Configuration
public class EnumMappingConfig implements WebMvcConfigurer {@Override
public void addFormatters(FormatterRegistry registry) {ApplicationConversionService.configure(registry);
}
}
此类使用适用于大多数 Spring Boot 应用程序的现成转换器配置FormatterRegistry 。
现在,让我们使用测试用例确认一切都按预期工作:
@RunWith(SpringRunner.class)
@WebMvcTest(EnumMappingController.class)
public class EnumMappingIntegrationTest {@Autowired
private MockMvc mockMvc;
@Test
public void whenPassingLowerCaseEnumConstant_thenConvert() throws Exception {mockMvc.perform(get("/enummapping/get?level=medium"))
.andExpect(status().isOk())
.andExpect(content().string(Level.MEDIUM.name()));
}
}
正如我们所见,作为参数传递的中间值已成功转换为MEDIUM。
3.2、使用自定义转换器另一种解决方案是使用自定义转换器。在这里,我们将使用 Apache Commons Lang 3 库。
首先,我们需要添加它的 依赖:
org.apache.commons commons-lang3 3.12.0
这里的基本思想是创建一个转换器,将 Level 常量的字符串表示 形式 转换为真正的Level常量:
public class StringToLevelConverter implements Converter{@Override
public Level convert(String source) {if (StringUtils.isBlank(source)) {return null;
}
return EnumUtils.getEnum(Level.class, source.toUpperCase());
}
}
从技术角度来看,自定义转换器是一个实现Converter接口的简单类。
如我们所见,我们将String对象转换为大写。然后,我们使用Apache Commons Lang 3 库中的EnumUtils实用程序类从大写字符串中获取Level常量。
现在,让我们添加最后一块缺失的拼图。我们需要告诉 Spring 我们新的自定义转换器。为此,我们将使用与之前相同的FormatterRegistry。它提供了addConverter()方法来注册自定义转换器:
@Override
public void addFormatters(FormatterRegistry registry) {registry.addConverter(new StringToLevelConverter());
}
就是这样。我们的StringToLevelConverter现在在ConversionService中可用。
现在,我们可以像使用任何其他转换器一样使用它:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = EnumMappingMainApplication.class)
public class StringToLevelConverterIntegrationTest {@Autowired
ConversionService conversionService;
@Test
public void whenConvertStringToLevelEnumUsingCustomConverter_thenSuccess() {assertThat(conversionService.convert("low", Level.class)).isEqualTo(Level.LOW);
}
}
如上所示,测试用例确认“low”值已转换为Level.LOW。
3.3、使用自定义属性编辑器Spring 在后台使用多个内置属性编辑器来管理String值和 Java 对象之间的转换。
同样,我们可以创建一个自定义属性编辑器来将String对象映射到Level常量。
例如,让我们将自定义编辑器命名为LevelEditor:
public class LevelEditor extends PropertyEditorSupport {@Override
public void setAsText(String text) {if (StringUtils.isBlank(text)) {setValue(null);
} else {setValue(EnumUtils.getEnum(Level.class, text.toUpperCase()));
}
}
}
如我们所见,我们需要扩展PropertyEditorSupport类并覆盖setAsText()方法。
覆盖setAsText()的想法是将给定字符串的大写版本转换为级别枚举。
值得注意的是,PropertyEditorSupport也提供了getAsText()。它在将 Java 对象序列化为字符串时调用。所以,我们不需要在这里重写它。
我们需要注册LevelEditor,因为 Spring 不会自动检测自定义属性编辑器。为此,我们需要在Spring 控制器中创建一个用@InitBinder注释的方法:
@InitBinder
public void initBinder(WebDataBinder dataBinder) {dataBinder.registerCustomEditor(Level.class, new LevelEditor());
}
现在我们将所有部分放在一起,让我们确认我们的自定义属性编辑器LevelEditor使用测试用例工作:
public class LevelEditorIntegrationTest {@Test
public void whenConvertStringToLevelEnumUsingCustomPropertyEditor_thenSuccess() {LevelEditor levelEditor = new LevelEditor();
levelEditor.setAsText("lOw");
assertThat(levelEditor.getValue()).isEqualTo(Level.LOW);
}
}
这里要提到的另一件重要的事情是EnumUtils.getEnum()在找到时返回枚举,否则返回null。
所以,为了避免NullPointerException,我们需要稍微改变我们的处理方法:
public String getByLevel(@RequestParam(required = false) Level level) {if (level != null) {return level.name();
}
return "undefined";
}
现在,让我们添加一个简单的测试用例来测试它:
@Test
public void whenPassingUnknownEnumConstant_thenReturnUndefined() throws Exception {mockMvc.perform(get("/enummapping/get?level=unknown"))
.andExpect(status().isOk())
.andExpect(content().string("undefined"));
}
4、总结在本文中,学习了在 Spring 中实现不区分大小写的枚举映射的多种方法。在此过程中,我们研究了一些使用内置和自定义转换器来完成此操作的方法。然后,我们了解了如何使用自定义属性编辑器实现相同的目标。
学习的目的,是为了我们能在实战中获得收获的几乎,huntsbot.com提供一站式副业的机会,感兴趣的同学可以关注。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧