Spring MVC Controller传递枚举值
功能描述
本文将通过一个小示例,展示在请求参数中传递枚举值。
枚举定义
角色类定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public enum RoleEnum {
EMPLOYEE(( short ) 1 , "Employee" ), MANAGER(( short ) 2 , "Manager" );
private Short value;
private String desc;
private RoleEnum(Short value, String desc) {
this .value = value;
this .desc = desc;
}
public Short value() {
return value;
}
public String desc() {
return desc;
}
}
|
定义Controller类
1
2
3
4
5
6
7
8
9
|
@RestController
@Slf4j
public class HomeController {
@GetMapping ( "/home" )
public String getDemo( @RequestParam ( "role" ) RoleEnum role) {
log.info( "Role Enum:{}" + role);
return role.desc();
}
}
|
说明: 在这里RoleEnum之内作为@RequestParam参数。
请求示例
Case1: http://localhost:8080/home?role=EMPLOYEE
结论: 正确返回, Employee
Case2: http://localhost:8080/home?role=Employee
报错,具体信息如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu May 14 11 : 21 : 32 CST 2020
There was an unexpected error (type=Bad Request, status= 400 ).
Failed to convert value of type 'java.lang.String' to required type 'org.course.data.domain.RoleEnum' ; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [ @org .springframework.web.bind.annotation.RequestParam org.course.data.domain.RoleEnum] for value 'employee' ; nested exception is java.lang.IllegalArgumentException: No enum constant org.course.data.domain.RoleEnum.employee
org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'org.course.data.domain.RoleEnum' ; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [ @org .springframework.web.bind.annotation.RequestParam org.course.data.domain.RoleEnum] for value 'employee' ; nested exception is java.lang.IllegalArgumentException: No enum constant org.course.data.domain.RoleEnum.employee
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java: 133 )
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java: 127 )
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java: 167 )
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java: 134 )
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java: 105 )
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java: 893 )
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java: 798 )
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java: 87 )
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java: 1040 )
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java: 943 )
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java: 1006 )
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java: 898 )
at javax.servlet.http.HttpServlet.service(HttpServlet.java: 634 )
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java: 883 )
at javax.servlet.http.HttpServlet.service(HttpServlet.java: 741 )
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java: 231 )
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java: 166 )
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java: 53 )
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java: 193 )
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java: 166 )
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java: 100 )
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java: 119 )
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java: 193 )
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java: 166 )
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java: 93 )
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java: 119 )
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java: 193 )
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java: 166 )
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java: 94 )
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java: 119 )
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java: 193 )
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java: 166 )
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java: 201 )
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java: 119 )
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java: 193 )
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java: 166 )
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java: 202 )
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java: 96 )
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java: 541 )
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java: 139 )
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java: 92 )
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java: 74 )
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java: 343 )
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java: 367 )
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java: 65 )
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java: 868 )
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java: 1639 )
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java: 49 )
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java: 1149 )
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java: 624 )
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java: 61 )
at java.lang.Thread.run(Thread.java: 748 )
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [ @org .springframework.web.bind.annotation.RequestParam org.course.data.domain.RoleEnum] for value 'employee' ; nested exception is java.lang.IllegalArgumentException: No enum constant org.course.data.domain.RoleEnum.employee
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java: 47 )
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java: 191 )
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java: 129 )
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java: 73 )
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java: 53 )
at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java: 693 )
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java: 125 )
... 51 more
Caused by: java.lang.IllegalArgumentException: No enum constant org.course.data.domain.RoleEnum.employee
at java.lang.Enum.valueOf(Enum.java: 238 )
at org.springframework.core.convert.support.StringToEnumConverterFactory$StringToEnum.convert(StringToEnumConverterFactory.java: 52 )
at org.springframework.core.convert.support.StringToEnumConverterFactory$StringToEnum.convert(StringToEnumConverterFactory.java: 38 )
at org.springframework.core.convert.support.GenericConversionService$ConverterFactoryAdapter.convert(GenericConversionService.java: 436 )
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java: 41 )
... 57 more
|
实现分析:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
StringToEnumConverterFactory() {
}
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToEnumConverterFactory.StringToEnum(ConversionUtils.getEnumType(targetType));
}
private class StringToEnum<T extends Enum> implements Converter<String, T> {
private final Class<T> enumType;
public StringToEnum(Class<T> enumType) {
this .enumType = enumType;
}
public T convert(String source) {
return source.isEmpty() ? null : Enum.valueOf( this .enumType, source.trim());
}
}
}
|
底层实现为将String转换为Enum值的过程。
结论
基于枚举可以限定具体值,简单易用。但是缺点是在扩展enum之时,无法做法平滑过度升级,会吹安短暂的异常情况。
Spring MVC 枚举传值问题
今天遇到算是棘手的一个枚举的问题,后台Controller参数是一个对象,而对象里面有个枚举类型的属性,死活不能传值。
最后找到解决方案
实体对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
@Entity
@Table (name= "xx_sn" )
@SequenceGenerator (name = "sequenceGenerator" , sequenceName = "xx_sn_sequence" )
public class ShoppTest extends BaseEntity{
private static final long serialVersionUID = 2756395514949325790L;
/**
* 枚举
* @author Administrator
*
*/
public enum Type{
/** 商品 */
product,
/** 订单 */
order,
/** 收款单 */
payment,
/** 退款单 */
refunds,
/** 发货单 */
shipping,
/** 退货单 */
returns
}
@Column (nullable = false , updatable = false , unique = true )
private Type type;
@Column (nullable = false )
private String lastValue;
public String getLastValue() {
return lastValue;
}
public void setLastValue(String lastValue) {
this .lastValue = lastValue;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this .type = type;
}
|
Controller代码:
1
2
3
4
5
6
|
@RequestMapping ( "/save" )
public String save(ShoppTest st,String tp){
st.setType(Enum.valueOf(Type. class , tp));
shoppTestServiceImpl.save(st);
return "redirect:list.jhtml" ;
}
|
前台代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
< form id = "inputForm" action = "save.jhtml" method = "post" >
< table class = "input" >
< tr >
< th >
${message("test.lastValue")}:
</ th >
< td colspan = "2" >
< input type = "text" name = "lastValue" class = "text" >
</ td >
</ tr >
< tr >
< th >
< span class = "requiredField" >*</ span >${message("test.type")}:
</ th >
< td colspan = "2" >
< input type = "text" name = "tp" class = "text" maxlength = "200" />
</ td >
</ tr >
</ table >
< table class = "input" >
< tr >
< th >
</ th >
< td >
< input type = "submit" class = "button" value = "${message(" admin.common.submit")}" />
< input type = "button" class = "button" value = "${message(" admin.common.back")}" ο nclick = "location.href='list.jhtml'" />
</ td >
</ tr >
</ table >
</ form >
|
因为springMVC对于枚举这种特殊的数据类型不能直接进行数据注入,所以访问Controller的时候直接就是400错误。
所以我这里用String去接收前台传来的枚举需要的数据,也就是“tp”,用到Enum.ValueOf();
ValueOf需要两个参数,第一个参数类型就是自己定义的枚举类类型,第二个参数是你枚举里面
定义的字段名字,这个字段就对应了你枚举所得到的值。
最终取到值后赋值给对象里面的枚举。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blade.blog.csdn.net/article/details/106116025