Spring MVC Controller傳遞枚舉值
功能描述
本文將通過一個小示例,展示在請求參數(shù)中傳遞枚舉值。
枚舉定義
角色類定義:
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之內(nèi)作為@RequestParam參數(shù)。
請求示例
Case1: http://localhost:8080/home?role=EMPLOYEE
結(jié)論: 正確返回, 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 |
實(shí)現(xiàn)分析:
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()); } } } |
底層實(shí)現(xiàn)為將String轉(zhuǎn)換為Enum值的過程。
結(jié)論
基于枚舉可以限定具體值,簡單易用。但是缺點(diǎn)是在擴(kuò)展enum之時,無法做法平滑過度升級,會吹安短暫的異常情況。
Spring MVC 枚舉傳值問題
今天遇到算是棘手的一個枚舉的問題,后臺Controller參數(shù)是一個對象,而對象里面有個枚舉類型的屬性,死活不能傳值。
最后找到解決方案
實(shí)體對象:
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, /** 發(fā)貨單 */ 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 > |
因?yàn)閟pringMVC對于枚舉這種特殊的數(shù)據(jù)類型不能直接進(jìn)行數(shù)據(jù)注入,所以訪問Controller的時候直接就是400錯誤。
所以我這里用String去接收前臺傳來的枚舉需要的數(shù)據(jù),也就是“tp”,用到Enum.ValueOf();
ValueOf需要兩個參數(shù),第一個參數(shù)類型就是自己定義的枚舉類類型,第二個參數(shù)是你枚舉里面
定義的字段名字,這個字段就對應(yīng)了你枚舉所得到的值。
最終取到值后賦值給對象里面的枚舉。
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://blade.blog.csdn.net/article/details/106116025