springMVC原始碼分析[email protected]
阿新 • • 發佈:2019-02-06
這一篇部落格我們簡單的介紹一下ModelAttribute的使用和執行原理。
1、首先@ModelAttribute是使用在方法或者上的,當使用在方法上時其作用於本身所在的Controller,在訪問Controller中的所有請求時都會執行到@ModelAttribute所註解的方法。
當訪問連線http://localhost/modelAttribute時會在頁面中看到test和test1的值。@Controller public class ModelAttributeController { @ModelAttribute public void init(Model model){ model.addAttribute("test", "測試資訊"); } @RequestMapping("/modelAttribute") public String modelAttribute(Model model){ model.addAttribute("test1", "測試資訊1"); return "modelAttribute"; } }
2、@ModelAttribute也是可以作用於引數上的,我們在上面的程式碼中再新增一個作用於引數的引數。
當訪問如下連結時就可以獲得如下資訊了。@Controller public class ModelAttributeController { @ModelAttribute public void init(Model model){ model.addAttribute("test", "測試資訊"); } @RequestMapping("/modelAttribute") public String modelAttribute(Model model,@ModelAttribute("test3")String test3){ model.addAttribute("test1", "測試資訊1"); model.addAttribute("test3", test3); return "modelAttribute"; } }
3、@ModelAttribute註釋返回具體類,如下:
也可以指定屬性名稱@Controller public class Hello2ModelController { @ModelAttribute public User populateModel() { User user=new User(); user.setAccount("ray"); return user; } @RequestMapping(value = "/helloWorld2") public String helloWorld(User user) { user.setName("老王"); return "helloWorld.jsp"; } }
@Controller
public class Hello2ModelController {
@ModelAttribute(value="myUser")
public User populateModel() {
User user=new User();
user.setAccount("ray");
return user;
}
@RequestMapping(value = "/helloWorld2")
public String helloWorld(Model map) {
return "helloWorld.jsp";
}
}
總結:
@ModelAttribute一個具有如下三個作用:
①繫結請求引數到命令物件:放在功能處理方法的入參上時,用於將多個請求引數繫結到一個命令物件,從而簡化綁
定流程,而且自動暴露為模型資料用於檢視頁面展示時使用;
②暴露表單引用物件為模型資料:放在處理器的一般方法(非功能處理方法)上時,是為表單準備要展示的表單引用
物件,如註冊時需要選擇的所在城市等,而且在執行功能處理方法(@RequestMapping 註解的方法)之前,自動新增
到模型物件中,用於檢視頁面展示時使用;
③暴露@RequestMapping 方法返回值為模型資料:放在功能處理方法的返回值上時,是暴露功能處理方法的返回值為
模型資料,用於檢視頁面展示時使用。
為什麼@ModelAttribute註解的方法是作用於整個Controller的,實際上是在執行Controller的每個請求時都會執行@ModelAttribute註解的方法。執行過程在RequestMappingHandlerAdapter中,每次執行Controller時會執行@ModelAttribute註解的方法
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
......
//執行@ModelAttribute註解的方法
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
......
//執行Controller中的方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
......
}
initModel中會執行@ModelAttribute註解的方法public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
throws Exception {
Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
mavContainer.mergeAttributes(sessionAttributes);
//執行@ModelAttribute註解的方法
invokeModelAttributeMethods(request, mavContainer);
//方法執行結果的值放到mavContainer
for (String name : findSessionAttributeArguments(handlerMethod)) {
if (!mavContainer.containsAttribute(name)) {
Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
if (value == null) {
throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");
}
mavContainer.addAttribute(name, value);
}
}
}
在invokeModelAttributeMethods中會判斷方法上是否被@ModelAttribute註解,如果是則會執行這個方法,並將返回值放到mavContainer中
private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer mavContainer)
throws Exception {
while (!this.modelMethods.isEmpty()) {
InvocableHandlerMethod attrMethod = getNextModelMethod(mavContainer).getHandlerMethod();
//判斷方法是否被@ModelAttribute註解
String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value();
if (mavContainer.containsAttribute(modelName)) {
continue;
}
//執行被@ModelAttribute註解的方法
Object returnValue = attrMethod.invokeForRequest(request, mavContainer);
//返回值放到mavContainer
if (!attrMethod.isVoid()){
String returnValueName = getNameForReturnValue(returnValue, attrMethod.getReturnType());
if (!mavContainer.containsAttribute(returnValueName)) {
mavContainer.addAttribute(returnValueName, returnValue);
}
}
}
}
總結:這邊部落格簡單地介紹了一下@ModelAttribute的用法,當其註解方法時,這個方法在每次訪問Controller時都會被執行,其執行到的原理就是在每次執行Controller時都會判斷一次,並執行@ModelAttribute的方法,將執行後的結果值放到mavContainer中,現在看來其實現機制也還是比較容易理解的。