Spring Boot 中的枚举(Enum)映射 您所在的位置:网站首页 枚举类型函数有哪些特征 Spring Boot 中的枚举(Enum)映射

Spring Boot 中的枚举(Enum)映射

2024-07-12 12:36| 来源: 网络整理| 查看: 265

1、概览

在本教程中,我们将学习如何在 Spring Boot 中实现不区分大小写的枚举映射。

2、Spring 默认的枚举映射

在处理请求参数时,Spring 依靠几个内置 Converter 来处理字符串转换。

通常情况下,将枚举作为请求参数时,默认会使用 StringToEnumConverterFactory 将传递的字符串转换为枚举。

该 Converter 会调用 Enum.valueOf(Class, String),这意味着给定的字符串必须要完全匹配枚举中的常量实例。

例如,让我们来看看 Level 枚举:

public enum Level { LOW, MEDIUM, HIGH }

接下来,创建一个使用枚举作为参数的 Handler Method:

@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

Handler Method 会返回 MEDIUM,即枚举实例 MEDIUM 的名称(name())。

现在,让我们传递 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。它没有将 medium 识别为枚举实例。

3、不区分大小写的枚举映射

在映射枚举时,Spring 提供了几种方便的方法来解决大小写敏感性问题。

3.1、使用 ApplicationConversionService

ApplicationConversionService 类带有一组已配置好的的 Converter 和 Formatter。

在这些开箱即用的 Converter 中,有一个 StringToEnumIgnoringCaseConverterFactory。顾名思义,它能以大小写不敏感的方式将字符串转换为枚举实例。

首先,添加并配置 ApplicationConversionService:

@Configuration public class EnumMappingConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { ApplicationConversionService.configure(registry); } }

该类使用适合大多数 Spring Boot 应用的 Converter 来配置 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 参数 已成功转换为 MEDIUM。

3.2、使用自定义 Converter

另一种解决方案是使用自定义 Converter。在这里,我们要使用 Apache Commons Lang 3 库。

首先,我们需要添加其依赖:

org.apache.commons commons-lang3 3.12.0

这里的基本思路是创建一个 Converter,将表示 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 只是一个实现 Converter 接口的简单类。

正如我们所见,我们将 String 对象转换为大写。然后,我们使用 Apache Commons Lang 3 库中的 EnumUtils 工具类从 Level 中获取枚举实例。

最后一步,需要告诉 Spring 我们自定义的 Converter。为此,我们将使用之前的 FormatterRegistry。它提供了 addConverter() 方法来注册自定义 Converter:

@Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new StringToLevelConverter()); }

现在,可以在 ConversionService 中使用 StringToLevelConverter 了。

像使用其他 Converter 一样使用它:

@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、使用自定义 Property Editor

Spring 使用多个内置 Property Editor 来管理 String 值和 Java 对象之间的转换。

同样,我们可以创建一个自定义 Property Editor,将 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() 方法的目的是将给定字符串转换为大写后,解析为 Level 枚举实例。

注意,PropertyEditorSupport 还提供了 getAsText() 方法。它在将 Java 对象序列化为字符串时被调用。因此,我们无需在此覆写它。

Spring 不会自动检测自定义的 Property Editor,我们需要手动注册 LevelEditor。

在 Spring Controller 中创建一个注解了 @InitBinder 的 initBinder 方法:

@InitBinder public void initBinder(WebDataBinder dataBinder) { dataBinder.registerCustomEditor(Level.class, new LevelEditor()); }

现在,我们把所有组件组装在一起,使用一个测试用例来确认我们的自定义 Property Editor 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,我们需要稍微修改一下 Handler Method:

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、总结

在本文中,我们学习了如何使用内置的 ApplicationConversionService、以及自定义 Converter 或 Property Editor 来实现不区分大消息的枚举映射。

参考:https://www.baeldung.com/spring-boot-enum-mapping



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有