SpringBoot中的枚举映射-创新互联

1、概述

在本篇文章中,我们将探讨在 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、使用ApplicationConversionService

ApplicationConversionService类带有一组已配置的转换器和格式化程序。

在这些开箱即用的转换器中,我们找到了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.commonscommons-lang33.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元起,快前往官网查看详情吧


文章名称:SpringBoot中的枚举映射-创新互联
文章URL:http://scyanting.com/article/dscedi.html