這一篇部落格我們簡單的介紹一下ModelAttribute的使用和運作原理。
1、首先@ModelAttribute是使用在方法或者上的,當使用在方法上時其作用于本身所在的Controller,在通路Controller中的所有請求時都會執行到@ModelAttribute所注解的方法。
@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";
}
}
當通路連接配接http://localhost/modelAttribute時會在頁面中看到test和test1的值。

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中,現在看來其實作機制也還是比較容易了解的。