在國內企業開發項目中大多數都已經偏向Spring
家族式的開發風格,在前幾年國內項目都是以Structs2
做爲Web
開發的主導,不過因爲近幾年發生的事情確實讓開發者對它失去了以往的信心。與此同時Spring
家族發佈了SpringMVC
,並且完美的整合Spring
來開發企業級大型Web
項目。它有着比Structs2
更強大的技術支持以及更靈活的自定義配置,接下來咱們就看看本章的內容,咱們自定義實現SpringMVC
參數綁定規則,根據業務定製參數裝載實現方式。html
根據項目定製SpringMVC
參數狀態並瞭解SpringMVC
的裝載過程以及實現方式。java
咱們先來建立一個SpringBoot
項目,添加本章所需的依賴,pom.xml配置文件以下所示:git
...//省略部分配置 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- spring boot tomcat jsp 支持開啓 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <!--servlet支持開啓--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> </dependency> <!-- jstl 支持開啓 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <!--lombok支持--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--fastjson支持--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.38</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> ...//省略部分配置
本章須要JSP
相關的依賴支持,因此須要添加對應的依賴,修改application.properties
配置文件讓JSP
生效,配置內容以下所示:web
spring.mvc.view.prefix=/WEB-INF/jsp/ spring.mvc.view.suffix=.jsp
相關JSP
配置能夠訪問第二章:SpringBoot與JSP間不可描述的祕密查看講解。spring
在講解咱們自定義參數裝載以前,咱們先來看看SpringMVC
內部爲咱們提供的參數裝載方式。數據庫
咱們首先來添加一個測試的jsp頁面,頁面上添加一些輸入元素,代碼以下所示:apache
<%-- Created by IntelliJ IDEA. User: hengyu Date: 2017/9/17 Time: 10:33 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form method="post" action="/submit"> 教師姓名:<input type="text" name="name"/><br/><br/> 學生姓名:<input type="text" name="name"/><br/><br/> 學生年齡:<input type="text" name="age"/><br/><br/> <input type="submit"/> </form> </body> </html>
在index.jsp
內添加了三個name
的文本輸入框,若是咱們如今提交到後臺SpringMVC
爲默認爲咱們解析成一個數組,若是根據描述而言的來處理則是不合理的,固然也可使用各類手段完成字段參數的裝載,好比:爲教師的name
添加一個數組或者List集合進行接受,這種方式也是能夠實現但不優雅
。json
若是大家項目組有嚴格的開發規範要求,這種方式是不容許出如今
Controller
方法內的。api
那這個問題就讓人頭疼了,在以前咱們使用Struct2
的時候是能夠根據指定的前綴,如:xxx.xxx
來進行映射的,而SpringMVC
並無提供這個支持,不過它提供了自定義參數裝載的實現方法,那就沒有問題了,咱們能夠手寫。數組
既然上面的代碼實現知足不了咱們的需求,那麼我接下來就來重寫參數裝載。
對於一直使用SpringMVC
的朋友來講,應該對@RequestParam
很熟悉,而本章咱們自定義的註解跟@RequestParam
相似,主要目的也是標識指定參數完成數據的綁定。下面咱們先來看看該註解的源碼,以下所示:
package com.yuqiyu.chapter36.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 參數實體映射註解 * 配置該註解的參數會使用 com.yuqiyu.chapter36.resovler.CustomerArgumentResolver類完成參數裝載 * ======================== * Created with IntelliJ IDEA. * User:恆宇少年 * Date:2017/9/16 * Time:22:19 * 碼雲:http://git.oschina.net/jnyqy * ======================== */ @Target(value = ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface ParameterModel { }
該註解目前沒有添加任何一個屬性,這個也是能夠根據項目的需求已經業務邏輯進行相應添加的,好比@RequestParam
內經常使用的屬性required
、defaultValue
等屬性,因爲咱們本章內容不須要自定義註解內的屬性因此這裏就不添加了。
該註解的做用域是在參數上@Target(value = ElementType.PARAMETER)
,咱們僅能夠在方法參數上使用。
咱們能夠回到上面看看index.jsp
的內容,咱們須要教師的基本信息以及學生的基本信息,那咱們就爲教師、以及學生建立實體(注意:這個實體能夠是對應數據庫內的實體)
package com.yuqiyu.chapter36.bean; import lombok.Data; /** * ======================== * Created with IntelliJ IDEA. * User:恆宇少年 * Date:2017/9/17 * Time:10:40 * 碼雲:http://git.oschina.net/jnyqy * ======================== */ @Data public class TeacherEntity { //教師姓名 private String name; }
教師實體內目前爲了測試就添加一個跟頁面參數有關的字段。
package com.yuqiyu.chapter36.bean; import lombok.Data; /** * ======================== * Created with IntelliJ IDEA. * User:恆宇少年 * Date:2017/9/17 * Time:10:41 * 碼雲:http://git.oschina.net/jnyqy * ======================== */ @Data public class StudentEntity { //學生姓名 private String name; //年齡 private String age; }
學生實體添加與頁面參數對應的字段,名稱、年齡。
在寫參數裝載以前,咱們須要先了解下它的接口HandlerMethodArgumentResolver
,該接口內定義了兩個方法:
boolean supportsParameter(MethodParameter var1);
supportsParameter
方法顧名思義,是容許裝載的參數,也就是說方法返回true
時纔會指定裝載方法完成參數裝載。
Object resolveArgument(MethodParameter var1, ModelAndViewContainer var2, NativeWebRequest var3, WebDataBinderFactory var4) throws Exception;
resolveArgument
方法是參數狀態的實現邏輯方法,該方法返回的值會直接裝載到指定的參數上,有木有很神奇啊?下面咱們就建立實現類來揭開這位神奇的姑娘的面紗吧!
建立CustomerArgumentResolver
實現接口HandlerMethodArgumentResolver
內的兩個方法,具體實現代碼以下所示:
package com.yuqiyu.chapter36.resovler; import com.yuqiyu.chapter36.annotation.ParameterModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.core.MethodParameter; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; import org.springframework.util.StringUtils; import org.springframework.validation.DataBinder; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.HandlerMapping; import java.lang.reflect.Field; import java.util.*; /** * 自定義參數裝載 * ======================== * Created with IntelliJ IDEA. * User:恆宇少年 * Date:2017/9/16 * Time:22:11 * 碼雲:http://git.oschina.net/jnyqy * ======================== */ public class CustomerArgumentResolver implements HandlerMethodArgumentResolver { /** * 日誌對象 */ private Logger logger = LoggerFactory.getLogger(CustomerArgumentResolver.class); /** * 該方法返回true時調用resolveArgument方法執行邏輯 * spring家族的架構設計萬變不離其宗啊,在以前event & listener也是用到了一樣的方式 * @param methodParameter * @return */ @Override public boolean supportsParameter(MethodParameter methodParameter) { return methodParameter.hasParameterAnnotation(ParameterModel.class); } /** * 裝載參數 * @param methodParameter 方法參數 * @param modelAndViewContainer 返回視圖容器 * @param nativeWebRequest 本次請求對象 * @param webDataBinderFactory 數據綁定工廠 * @return * @throws Exception */ @Override public Object resolveArgument ( MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory ) throws Exception { String parameterName = methodParameter.getParameterName(); logger.info("參數名稱:{}",parameterName); /** * 目標返回對象 * 若是Model存在該Attribute時從module內獲取並設置爲返回值 * 若是Model不存在該Attribute則從request parameterMap內獲取並設置爲返回值 */ Object target = modelAndViewContainer.containsAttribute(parameterName) ? modelAndViewContainer.getModel().get(parameterName) : createAttribute(parameterName, methodParameter, webDataBinderFactory, nativeWebRequest);; /** * 返回內容,這裏返回的內容纔是最終裝載到參數的值 */ return target; } /** * 根據參數attributeName獲取請求的值 * @param attributeName 請求參數 * @param parameter method 參數對象 * @param binderFactory 數據綁定工廠 * @param request 請求對象 * @return * @throws Exception */ protected Object createAttribute(String attributeName, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { /** * 獲取attributeName的值 */ String value = getRequestValueForAttribute(attributeName, request); /** * 若是存在值 */ if (value != null) { /** * 進行類型轉換 * 檢查請求的類型與目標參數類型是否能夠進行轉換 */ Object attribute = convertAttributeToParameterValue(value, attributeName, parameter, binderFactory, request); /** * 若是存在轉換後的值,則返回 */ if (attribute != null) { return attribute; } } /** * 檢查request parameterMap 內是否存在以attributeName做爲前綴的數據 * 若是存在則根據字段的類型來進行設置值、集合、數組等 */ else { Object attribute = putParameters(parameter,request); if(attribute!=null) { return attribute; } } /** * 若是以上兩種條件不符合,直接返回初始化參數類型的空對象 */ return BeanUtils.instantiateClass(parameter.getParameterType()); } /** * 將attribute的值轉換爲parameter參數值類型 * @param sourceValue 源請求值 * @param attributeName 參數名 * @param parameter 目標參數對象 * @param binderFactory 數據綁定工廠 * @param request 請求對象 * @return * @throws Exception */ protected Object convertAttributeToParameterValue(String sourceValue, String attributeName, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { /** * 獲取類型轉換業務邏輯實現類 */ DataBinder binder = binderFactory.createBinder(request, null, attributeName); ConversionService conversionService = binder.getConversionService(); if (conversionService != null) { /** * 源類型描述 */ TypeDescriptor source = TypeDescriptor.valueOf(String.class); /** * 根據目標參數對象獲取目標參數類型描述 */ TypeDescriptor target = new TypeDescriptor(parameter); /** * 驗證是否能夠進行轉換 */ if (conversionService.canConvert(source, target)) { /** * 返回轉換後的值 */ return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter); } } return null; } /** * 從request parameterMap集合內獲取attributeName的值 * @param attributeName 參數名稱 * @param request 請求對象 * @return */ protected String getRequestValueForAttribute(String attributeName, NativeWebRequest request) { /** * 獲取PathVariables參數集合 */ Map<String, String> variables = getUriTemplateVariables(request); /** * 若是PathVariables參數集合內存在該attributeName * 直接返回相對應的值 */ if (StringUtils.hasText(variables.get(attributeName))) { return variables.get(attributeName); } /** * 若是request parameterMap內存在該attributeName * 直接返回相對應的值 */ else if (StringUtils.hasText(request.getParameter(attributeName))) { return request.getParameter(attributeName); } //不存在時返回null else { return null; } } /** * 獲取指定前綴的參數:包括uri varaibles 和 parameters * * @param namePrefix * @param request * @return * @subPrefix 是否截取掉namePrefix的前綴 */ protected Map<String, String[]> getPrefixParameterMap(String namePrefix, NativeWebRequest request, boolean subPrefix) { Map<String, String[]> result = new HashMap(); /** * 從PathVariables內獲取該前綴的參數列表 */ Map<String, String> variables = getUriTemplateVariables(request); int namePrefixLength = namePrefix.length(); for (String name : variables.keySet()) { if (name.startsWith(namePrefix)) { //page.pn 則截取 pn if (subPrefix) { char ch = name.charAt(namePrefix.length()); //若是下一個字符不是 數字 . _ 則不多是查詢 只是前綴相似 if (illegalChar(ch)) { continue; } result.put(name.substring(namePrefixLength + 1), new String[]{variables.get(name)}); } else { result.put(name, new String[]{variables.get(name)}); } } } /** * 從request parameterMap集合內獲取該前綴的參數列表 */ Iterator<String> parameterNames = request.getParameterNames(); while (parameterNames.hasNext()) { String name = parameterNames.next(); if (name.startsWith(namePrefix)) { //page.pn 則截取 pn if (subPrefix) { char ch = name.charAt(namePrefix.length()); //若是下一個字符不是 數字 . _ 則不多是查詢 只是前綴相似 if (illegalChar(ch)) { continue; } result.put(name.substring(namePrefixLength + 1), request.getParameterValues(name)); } else { result.put(name, request.getParameterValues(name)); } } } return result; } /** * 驗證參數前綴是否合法 * @param ch * @return */ private boolean illegalChar(char ch) { return ch != '.' && ch != '_' && !(ch >= '0' && ch <= '9'); } /** * 獲取PathVariables集合 * @param request 請求對象 * @return */ protected final Map<String, String> getUriTemplateVariables(NativeWebRequest request) { Map<String, String> variables = (Map<String, String>) request.getAttribute( HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); return (variables != null) ? variables : Collections.emptyMap(); } /** * 從request內獲取parameter前綴的全部參數 * 並根據parameter的類型將對應字段的值設置到parmaeter對象內並返回 * @param parameter * @param request * @return */ protected Object putParameters(MethodParameter parameter,NativeWebRequest request) { /** * 根據請求參數類型初始化空對象 */ Object object = BeanUtils.instantiateClass(parameter.getParameterType()); /** * 獲取指定前綴的請求參數集合 */ Map<String, String[]> parameters = getPrefixParameterMap(parameter.getParameterName(),request,true); Iterator<String> iterator = parameters.keySet().iterator(); while(iterator.hasNext()) { //字段名稱 String fieldName = iterator.next(); //請求參數值 String[] parameterValue = parameters.get(fieldName); try { Field field = object.getClass().getDeclaredField(fieldName); field.setAccessible(true); //字段的類型 Class<?> fieldTargetType = field.getType(); /** * List(ArrayList、LinkedList)類型 * 將數組類型的值轉換爲List集合對象 */ if(List.class.isAssignableFrom(fieldTargetType)) { field.set(object, Arrays.asList(parameterValue)); } /** *Object數組類型,直接將數組值設置爲目標字段的值 */ else if(Object[].class.isAssignableFrom(fieldTargetType)) { field.set(object, parameterValue); } /** * 單值時獲取數組索引爲0的值 */ else { field.set(object, parameterValue[0]); } } catch (Exception e) { logger.error("Set Field:{} Value Error,In {}",fieldName,object.getClass().getName()); continue; } } return object; } }
上面我直接貼出了參數裝載的所有實現方法,下面咱們就開始按照裝載的流程進行講解。
/** * 該方法返回true時調用resolveArgument方法執行邏輯 * spring家族的架構設計萬變不離其宗啊,在以前event & listener也是用到了一樣的方式 * @param methodParameter * @return */ @Override public boolean supportsParameter(MethodParameter methodParameter) { return methodParameter.hasParameterAnnotation(ParameterModel.class); }
咱們只對配置了ParameterModel
註解的參數進行裝載。
/** * 裝載參數 * @param methodParameter 方法參數 * @param modelAndViewContainer 返回視圖容器 * @param nativeWebRequest 本次請求對象 * @param webDataBinderFactory 數據綁定工廠 * @return * @throws Exception */ @Override public Object resolveArgument ( MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory ) throws Exception { String parameterName = methodParameter.getParameterName(); logger.info("參數名稱:{}",parameterName); /** * 目標返回對象 * 若是Model存在該Attribute時從module內獲取並設置爲返回值 * 若是Model不存在該Attribute則從request parameterMap內獲取並設置爲返回值 */ Object target = modelAndViewContainer.containsAttribute(parameterName) ? modelAndViewContainer.getModel().get(parameterName) : createAttribute(parameterName, methodParameter, webDataBinderFactory, nativeWebRequest);; /** * 返回內容,這裏返回的內容纔是最終裝載到參數的值 */ return target; }
該方法做爲裝載參數邏輯的入口,咱們從MethodParameter
對象內獲取了參數的名稱,根據該名稱檢查Model內是否存在該名稱的值,若是存在則直接使用並返回,反則須要從ParameterMap
內獲取對應該參數名稱的值返回。
咱們下面主要看看從parameterMap
獲取的方法實現
/** * 根據參數attributeName獲取請求的值 * @param attributeName 請求參數 * @param parameter method 參數對象 * @param binderFactory 數據綁定工廠 * @param request 請求對象 * @return * @throws Exception */ protected Object createAttribute(String attributeName, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { /** * 獲取attributeName的值 */ String value = getRequestValueForAttribute(attributeName, request); /** * 若是存在值 */ if (value != null) { /** * 進行類型轉換 * 檢查請求的類型與目標參數類型是否能夠進行轉換 */ Object attribute = convertAttributeToParameterValue(value, attributeName, parameter, binderFactory, request); /** * 若是存在轉換後的值,則返回 */ if (attribute != null) { return attribute; } } /** * 檢查request parameterMap 內是否存在以attributeName做爲前綴的數據 * 若是存在則根據字段的類型來進行設置值、集合、數組等 */ else { Object attribute = putParameters(parameter,request); if(attribute!=null) { return attribute; } } /** * 若是以上兩種條件不符合,直接返回初始化參數類型的空對象 */ return BeanUtils.instantiateClass(parameter.getParameterType()); }
該方法的邏輯存在兩個分支,首先經過調用getRequestValueForAttribute
方法從parameterMap
內獲取指定屬性名的請求值,若是存在值則須要驗證是否能夠完成類型轉換,驗證經過後則直接返回值。
上面的部分實際上是SpringMVC
原有的參數裝載的流程,下面咱們就來根據需求個性化定製裝載邏輯。
該方法實現了自定義規則xxx.xxx
方式進行參數裝載的邏輯,咱們在前臺傳遞參數的時候只須要將Controller
內方法參數名稱做爲傳遞的前綴便可,如:teacher.name
、student.name
。
/** * 從request內獲取parameter前綴的全部參數 * 並根據parameter的類型將對應字段的值設置到parmaeter對象內並返回 * @param parameter * @param request * @return */ protected Object putParameters(MethodParameter parameter,NativeWebRequest request) { /** * 根據請求參數類型初始化空對象 */ Object object = BeanUtils.instantiateClass(parameter.getParameterType()); /** * 獲取指定前綴的請求參數集合 */ Map<String, String[]> parameters = getPrefixParameterMap(parameter.getParameterName(),request,true); Iterator<String> iterator = parameters.keySet().iterator(); while(iterator.hasNext()) { //字段名稱 String fieldName = iterator.next(); //請求參數值 String[] parameterValue = parameters.get(fieldName); try { Field field = object.getClass().getDeclaredField(fieldName); field.setAccessible(true); //字段的類型 Class<?> fieldTargetType = field.getType(); /** * List(ArrayList、LinkedList)類型 * 將數組類型的值轉換爲List集合對象 */ if(List.class.isAssignableFrom(fieldTargetType)) { field.set(object, Arrays.asList(parameterValue)); } /** *Object數組類型,直接將數組值設置爲目標字段的值 */ else if(Object[].class.isAssignableFrom(fieldTargetType)) { field.set(object, parameterValue); } /** * 單值時獲取數組索引爲0的值 */ else { field.set(object, parameterValue[0]); } } catch (Exception e) { logger.error("Set Field:{} Value Error,In {}",fieldName,object.getClass().getName()); continue; } } return object; }
該方法首先實例化了一個MethodParameter
類型的空對象
,而後經過getPrefixParameterMap
獲取PathVariables
、ParameterMap
內前綴爲MethodParameter
名稱的請求參數列表,遍歷列表對應設置object
內的字段,用於完成參數的裝載,在裝載過程當中,我這裏分別根據Collection
、List
、Array
、Single
類型進行了處理(注意:這裏須要根據項目需求進行調整裝載類型)。
咱們將CustomerArgumentResolver
託管交付給Spring
框架,咱們來建立一個名叫WebMvcConfiguration
的配置類,該類繼承抽象類WebMvcConfigurerAdapter
,代碼以下所示:
/** * springmvc 註解式配置類 * ======================== * Created with IntelliJ IDEA. * User:恆宇少年 * Date:2017/9/16 * Time:22:15 * 碼雲:http://git.oschina.net/jnyqy * ======================== */ @Configuration public class WebMvcConfiguration extends WebMvcConfigurerAdapter { /** * 添加參數裝載 * @param argumentResolvers */ @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { /** * 將自定義的參數裝載添加到spring內託管 */ argumentResolvers.add(new CustomerArgumentResolver()); } /** * 配置靜態請求視圖映射 * @param registry */ @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/index").setViewName("index"); } }
咱們重寫了WebMvcConfigurerAdapter
抽象類內的兩個方法addArgumentResolvers
、addViewControllers
,其中addArgumentResolvers
方法完成了參數裝載的託管。
addViewControllers
配置了視圖控制器映射,這樣咱們訪問/index
地址就能夠請求到index.jsp
頁面。
建立名爲IndexController
的控制器並添加數據提交的方法,具體代碼以下所示:
/** * 表單提交控制器 * ======================== * Created with IntelliJ IDEA. * User:恆宇少年 * Date:2017/9/16 * Time:22:26 * 碼雲:http://git.oschina.net/jnyqy * ======================== */ @RestController public class IndexController { /** * 裝載參數測試 * @return */ @RequestMapping(value = "/submit") public String resolver(@ParameterModel TeacherEntity teacher, @ParameterModel StudentEntity student) { return "教師名稱:"+ JSON.toJSON(teacher.getName()) +",學生名稱:"+student.getName()+",學生年齡:"+student.getAge(); } }
能夠看到咱們爲TeacherEntity
、StudentEntity
分別添加了註解@ParameterModel
,也就證實了這兩個實體須要使用咱們的CustomerArgumentResolver
完成參數裝載。
在運行測試以前,咱們須要修改下index.jsp
內的參數映射前綴,修改後代碼以下所示:
<form method="post" action="/submit"> 教師姓名:<input type="text" name="teacher.name"/><br/><br/> 學生姓名:<input type="text" name="student.name"/><br/><br/> 學生年齡:<input type="text" name="student.age"/><br/><br/> <input type="submit"/> </form>
咱們爲教師名稱、學生名稱、學生年齡都分別添加了前綴,下面咱們來啓動項目,訪問項目根下路徑/index
,以下圖1所示:
在上圖1中輸入了部分請求參數,點擊「提交」按鈕查看界面輸出的效果,圖下所示:
教師名稱:王老師,學生名稱:張小跑,學生年齡:23
能夠看到參數已經被正確的裝載到了不一樣的實體類內。
上面的例子只是針對實體內的單個值的裝載,下面咱們來測試下
List
類型的值是否能夠裝載?
咱們先來修改下教師實體內的名稱爲List,字段名稱不須要變更,以下所示:
//教師姓名 private List<String> name;
再來修改下index.jsp
輸入框,以下所示:
<form method="post" action="/submit"> 語文老師姓名:<input type="text" name="teacher.name"/><br/><br/> 數學教師姓名:<input type="text" name="teacher.name"/><br/><br/> 學生姓名:<input type="text" name="student.name"/><br/><br/> 學生年齡:<input type="text" name="student.age"/><br/><br/> <input type="submit"/> </form>
在上代碼中咱們添加了兩位老師的名稱,接下來重啓項目,再次提交測試,查看是否是咱們想要的效果?
修改後的界面以下圖2所示:
界面輸出內容以下所示:
教師名稱:["王老師","李老師"],學生名稱:張小跑,學生年齡:24
能夠看到咱們已經拿到了兩位老師的名稱,這也證實了咱們的CustomerArgumentResolver
是能夠完成List
的映射裝載的。
以上內容就是本章的所有講解內容,本章簡單實現了參數的狀態,其中還有不少細節性質的邏輯,如:@Valid
註解的生效、文件的上傳等。在下一章咱們會降到若是經過參數裝載實現接口服務的安全認證。
本章代碼已經上傳到碼雲:
網頁地址:http://git.oschina.net/jnyqy/lessons
Git地址:https://git.oschina.net/jnyqy/lessons.git
SpringBoot相關係列文章請訪問:目錄:SpringBoot學習目錄
QueryDSL相關係列文章請訪問:QueryDSL通用查詢框架學習目錄
SpringDataJPA相關係列文章請訪問:目錄:SpringDataJPA學習目錄
感謝閱讀!
歡迎加入QQ技術交流羣,共同進步。