我有一个有效的控制器,但我不明白为什么它有效。这是:
@Controller
@RequestMapping("/someUrl")
public class MyController {
@Autowired
private SomeService someService;
@RequestMapping(method = RequestMethod.GET)
public String page() throws ApplicationException {
return "page";
}
@ModelAttribute("modelAttribute")
public PageModel loadPageModel() throws ApplicationException {
return someService.createPageModel();
}
}
访问“/ someUrl”会让我看到名称“page”的视图,正如预期的那样。令人费解的是,尽管模型属性为“modelAttribute”,或者类型“PageModel”的对象未在方法页面附近的任何位置引用,但对于视图仍然可以看到modelAttribute。我很高兴这有效,但我不明白为什么。有什么想法吗?
答案 0 :(得分:0)
正如contract for the ModelAttribute annotation所说:
将(...)方法返回值绑定到指定模型属性的注释,公开给Web视图。 支持使用@RequestMapping方法的控制器类。
换句话说,您通过返回隐含地添加属性。
为什么会这样?
我不知道Spring内部是如何做到的,但我们知道的是我们如何才能让它有资格让Spring MVC识别并使其可用于well documented视图:
答案 1 :(得分:0)
仔细查看ModelAttributeMethodProcessor
并查找handleReturnValue
方法。此方法将在使用@ModelAttribute
注释的控制器方法上执行。
/**
* Add non-null return values to the {@link ModelAndViewContainer}.
*/
@Override
public void handleReturnValue(
Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws Exception {
if (returnValue != null) {
String name = ModelFactory.getNameForReturnValue(returnValue, returnType);
mavContainer.addAttribute(name, returnValue);
}
}
您可以看到它只是将它的返回值添加到模型中,并且会针对该特定控制器的每个请求调用它。
P.S。大多数“magic”操作的起点可以在RequestMappingHandlerAdapter
中找到,这是现代Spring MVC应用程序的默认HandlerAdapter
。
答案 2 :(得分:0)
@ModelAttribute
有点过载,根据声明的位置提供两个主要功能。
使用方法参数:
@RequestMapping(value="/create", method=POST)
public String createPage(@ModelAttribute("pageModel") PageModel pageModel) ...
例如,当使用方法参数声明@ModelAttribute
并向该方法提交参数时,Spring将尝试将提交的参数绑定到类型为PageModel
的对象。它在哪里得到PageModel
:1)如果有一个当前在Spring托管模型中,使用它2)否则它将使用PageModel对象的默认构造函数创建一个PageModel
在方法声明中(您如何使用它):
@ModelAttribute("modelAttribute")
public PageModel loadPageModel() throws ApplicationException {
return someService.createPageModel();
}
在您的情况下,当在方法级别声明@ModelAttribute
时,它告诉Spring该方法将在为特定请求调用任何RequestMapping之前提供PageModel。创建的PageModel实例将放入" modelAttribute"下的Springs托管模型中。键。然后从您的视图中,您应该能够引用该PageModel。
所以请求是这样的(我只显示相关事件):
@RequestMapping
注释,所以它在执行page()之前调用所有用@ModelAttribute
注释的方法(在方法级别)注意: