Java Spring 的 @RequestParam 与枚举
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39774427/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring's @RequestParam with Enum
提问by Antoine Martin
I have this enum :
我有这个枚举:
public enum SortEnum {
asc, desc;
}
That I want to use as a parameter of a rest request :
我想用作休息请求的参数:
@RequestMapping(value = "/events", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<Event> getEvents(@RequestParam(name = "sort", required = false) SortEnum sort) {
It works fine when I send these requests
当我发送这些请求时它工作正常
/events
/events?sort=asc
/events?sort=desc
But when I send :
但是当我发送:
/events?sort=somethingElse
I get a 500 response and this message in the console :
我在控制台中收到 500 响应和此消息:
2016-09-29 17:20:51.600 DEBUG 5104 --- [ XNIO-2 task-6] com.myApp.aop.logging.LoggingAspect : Enter: com.myApp.web.rest.errors.ExceptionTranslator.processRuntimeException() with argument[s] = [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type [java.lang.String] to required type [com.myApp.common.SortEnum]; 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.myApp.common.SortEnum] for value 'somethingElse'; nested exception is java.lang.IllegalArgumentException: No enum constant com.myApp.common.SortEnum.somethingElse]
2016-09-29 17:20:51.600 DEBUG 5104 --- [ XNIO-2 task-6] com.myApp.aop.logging.LoggingAspect : Exit: com.myApp.web.rest.errors.ExceptionTranslator.processRuntimeException() with result = <500 Internal Server Error,com.myApp.web.rest.errors.ErrorVM@1e3343c9,{}>
2016-09-29 17:20:51.601 WARN 5104 --- [ XNIO-2 task-6] .m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type [java.lang.String] to required type [com.myApp.common.SortEnum]; 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.myApp.common.SortEnum] for value 'somethingElse'; nested exception is java.lang.IllegalArgumentException: No enum constant com.myApp.common.SortEnum.somethingElse
Is there a way to prevent spring from throwing these exceptions and set the enum to null ?
有没有办法防止 spring 抛出这些异常并将枚举设置为 null ?
EDIT
编辑
The Strelok's accepted answer works. However, I decided to deal with handling the MethodArgumentTypeMismatchException.
Strelok 接受的答案有效。但是,我决定处理 MethodArgumentTypeMismatchException。
@ControllerAdvice
public class ExceptionTranslator {
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseBody
public ResponseEntity<Object> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
Class<?> type = e.getRequiredType();
String message;
if(type.isEnum()){
message = "The parameter " + e.getName() + " must have a value among : " + StringUtils.join(type.getEnumConstants(), ", ");
}
else{
message = "The parameter " + e.getName() + " must be of type " + type.getTypeName();
}
return buildResponse(HttpStatus.UNPROCESSABLE_ENTITY, message);
}
采纳答案by Strelok
You can create a custom converter that will return null
instead of an exception when an invalid value is supplied.
您可以创建一个自定义转换器,null
当提供无效值时,该转换器将返回而不是异常。
Something like this:
像这样的东西:
@Configuration
public class MyConfig extends WebMvcConfigurationSupport {
@Override
public FormattingConversionService mvcConversionService() {
FormattingConversionService f = super.mvcConversionService();
f.addConverter(new MyCustomEnumConverter());
return f;
}
}
And a simple converter might look like this:
一个简单的转换器可能如下所示:
public class MyCustomEnumConverter implements Converter<String, SortEnum> {
@Override
public SortEnum convert(String source) {
try {
return SortEnum.valueOf(source);
} catch(Exception e) {
return null; // or SortEnum.asc
}
}
}
回答by satish chennupati
you need to do the following
您需要执行以下操作
@InitBinder
public void initBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(YourEnum.class, new YourEnumConverter());
}
refer the following : https://machiel.me/post/java-enums-as-request-parameters-in-spring-4/
请参阅以下内容:https: //machiel.me/post/java-enums-as-request-parameters-in-spring-4/
回答by user3862533
The answers provided so far are not complete. Here is an answer example step-by-step that worked for me:-
到目前为止提供的答案并不完整。这是一个对我有用的分步答案示例:-
1st Define the enum in your endpoint signature(subscription type).
Example:
1st 在端点签名(订阅类型)中定义枚举。
示例:
public ResponseEntity v1_getSubscriptions(@PathVariable String agencyCode,
@RequestParam(value = "uwcompany", required = false) String uwCompany,
@RequestParam(value = "subscriptiontype", required = false) SubscriptionType subscriptionType,
@RequestParam(value = "alert", required = false) String alert,
2nd Define a custom property editor that will be used to translate from String to enum:
2nd 定义一个自定义属性编辑器,用于从字符串转换为枚举:
import java.beans.PropertyEditorSupport;
public class SubscriptionTypeEditor extends PropertyEditorSupport {
public void setAsText(String text) {
try {
setValue(SubscriptionType.valueOf(text.toUpperCase()));
} catch (Exception ex) {
setValue(null);
}
}
}
3rd Register the property editor with the controller:
3rd 向控制器注册属性编辑器:
@InitBinder ("subscriptiontype")
public void initBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(SubscriptionType.class, new SubscriptionTypeEditor());
}
Translations from string to enum should happen perfectly now.
从字符串到枚举的转换现在应该完美地发生。
回答by Cnfn
If you are using Spring Boot, this is the reasonthat you should not use WebMvcConfigurationSupport
.
如果您使用的是 Spring Boot,这就是您不应该使用WebMvcConfigurationSupport
.
The best practice, you should implement interface org.springframework.core.convert.converter.Converter
, and with annotation @Component
. Then Spring Boot will auto load all Converter
's bean. Spring Boot code
最佳实践,你应该实现 interface org.springframework.core.convert.converter.Converter
,并带有 annotation @Component
。然后 Spring Boot 将自动加载 allConverter
的 bean。春季启动代码
@Component
public class GenderEnumConverter implements Converter<String, GenderEnum> {
@Override
public GenderEnum convert(String value) {
return GenderEnum.of(Integer.valueOf(value));
}
}
回答by andrej
you can use String
instead of SortEnum
param
你可以使用String
代替SortEnum
参数
@RequestParam(name = "sort", required = false) String sort
and convert it using
并使用转换它
SortEnum se;
try {
se = SortEnum.valueOf(source);
} catch(IllegalArgumentException e) {
se = null;
}
inside of getEvents(...) endpoint method losing elegance but gaining more control over conversion and possible error handling.
在 getEvents(...) 端点方法内部失去了优雅,但获得了对转换和可能的错误处理的更多控制。
回答by Esteban
If you are already implementing WebMvcConfigurer, instead of WebMvcConfigurationSupport, you can add new converter by implementing the method addFormatters
如果你已经在实现WebMvcConfigurer,而不是WebMvcConfigurationSupport,你可以通过实现 addFormatters 方法来添加新的转换器
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new MyCustomEnumConverter());
}
回答by Constantino Cronemberger
If you have multiple enums then if you follow the other answers you'll end up creating one converter for each one.
如果您有多个枚举,那么如果您遵循其他答案,您最终将为每个枚举创建一个转换器。
Here is a solution that works for all enums.
这是适用于所有枚举的解决方案。
Converter or PropertyEditorSupport are not appropriate in this case because they don't allow us to know the target class.
Converter 或 PropertyEditorSupport 在这种情况下不合适,因为它们不允许我们知道目标类。
In this example I have used the Hymanson ObjectMapper, but you could replace this part by a call to the static method via reflection or move the call to values() to the converter.
在这个例子中,我使用了 Hymanson ObjectMapper,但你可以通过反射调用静态方法来替换这部分,或者将调用 values() 移动到转换器。
@Component
public class HymansonEnumConverter implements GenericConverter {
private ObjectMapper mapper;
private Set<ConvertiblePair> set;
@Autowired
public HymansonEnumConverter(ObjectMapper mapper) {
set = new HashSet<>();
set.add(new ConvertiblePair(String.class, Enum.class));
this.mapper = mapper;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return set;
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
try {
return mapper.readValue("\"" + source + "\"", targetType.getType());
} catch (IOException e) {
throw new InvalidFieldException(targetType.getName(),source.toString());
}
}
}
and in this case, because I'm using Hymanson, the enum class has to have a static method annotated with @JsonCreator so I can map using the value rather than the constant name:
在这种情况下,因为我使用的是 Hymanson,所以枚举类必须有一个用 @JsonCreator 注释的静态方法,以便我可以使用值而不是常量名称进行映射:
public enum MyEnum {
VAL_1("val-1"), VAL_2("val-2");
private String value;
MyEnum(String value) {
this.value = value;
}
@JsonValue
public String getValue() {
return value;
}
@JsonCreator
public static MyEnum fromValue(String value) {
for (MyEnum e : values()) {
if (e.value.equalsIgnoreCase(value)) {
return e;
}
}
return null;
}
}
In the fromValue method I handle the case to return null if no match is found.
在 fromValue 方法中,如果找不到匹配项,我将处理返回 null 的情况。