Spring MVC Controller傳遞枚舉值的實例
Spring MVC Controller傳遞枚舉值
功能描述
本文將通過一個小示例,展示在請求參數(shù)中傳遞枚舉值。
枚舉定義
角色類定義:
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類
@RestController @Slf4j public class HomeController { @GetMapping("/home") public String getDemo(@RequestParam("role") RoleEnum role) { log.info("Role Enum:{}" + role); return role.desc(); } }
說明: 在這里RoleEnum之內作為@RequestParam參數(shù)。
請求示例
Case1: http://localhost:8080/home?role=EMPLOYEE
結論: 正確返回, Employee
Case2: http://localhost:8080/home?role=Employee
報錯,具體信息如下:
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
實現(xiàn)分析:
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()); } } }
底層實現(xiàn)為將String轉換為Enum值的過程。
結論
基于枚舉可以限定具體值,簡單易用。但是缺點是在擴展enum之時,無法做法平滑過度升級,會吹安短暫的異常情況。
Spring MVC 枚舉傳值問題
今天遇到算是棘手的一個枚舉的問題,后臺Controller參數(shù)是一個對象,而對象里面有個枚舉類型的屬性,死活不能傳值。
最后找到解決方案
實體對象:
@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代碼:
@RequestMapping("/save") public String save(ShoppTest st,String tp){ st.setType(Enum.valueOf(Type.class, tp)); shoppTestServiceImpl.save(st); return "redirect:list.jhtml"; }
前臺代碼:
<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對于枚舉這種特殊的數(shù)據類型不能直接進行數(shù)據注入,所以訪問Controller的時候直接就是400錯誤。
所以我這里用String去接收前臺傳來的枚舉需要的數(shù)據,也就是“tp”,用到Enum.ValueOf();
ValueOf需要兩個參數(shù),第一個參數(shù)類型就是自己定義的枚舉類類型,第二個參數(shù)是你枚舉里面
定義的字段名字,這個字段就對應了你枚舉所得到的值。
最終取到值后賦值給對象里面的枚舉。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
springboot如何去獲取前端傳遞的參數(shù)的實現(xiàn)
這篇文章主要介紹了springboot如何去獲取前端傳遞的參數(shù)的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-05-05Springboot通過aop實現(xiàn)事務控制過程解析
這篇文章主要介紹了Springboot通過aop實現(xiàn)事務控制過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-03-03java8實現(xiàn)list集合中按照某一個值相加求和,平均值等操作代碼
這篇文章主要介紹了java8實現(xiàn)list集合中按照某一個值相加求和,平均值等操作代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08Java 將PPT幻燈片轉為HTML文件的實現(xiàn)思路
本文以Java程序代碼為例展示如何通過格式轉換的方式將PPT幻燈片文檔轉為HTML文件,本文通過實例代碼圖文相結合給大家分享實現(xiàn)思路,需要的朋友參考下吧2021-06-06