一.@ModelAttribute
1.用于实现数据回显
a):springmvc默认支持数据回显,spring自动将形参中的pojo重新放回request域中,request的key是pojo的类名首字母小写.对于简单数据类型,如:Integer、String、Float等使用Model将传入的参数再放到request域实现显示。
testmode.jsp:
<form method="post" action="${pageContext.request.contextPath}/modeattribute.action">
<input type="text" name="username"/>
<input type="submit" value="提交"/>
</form>
回显值:<br>
username:${user.username}<br>
@RequestMapping("/modeattribute")
public String modeattribute(User user)
{
return "testmode";
}
比如上面的代码,没有将user加入模型数据,可以在页面取到值
b):可以使用@ModelAttribute指定pojo回显到页面在request中的key.
<form method="post" action="${pageContext.request.contextPath}/modeattribute.action">
<input type="text" name="username"/>
<input type="submit" value="提交"/>
</form>
回显值:<br>
username:${user0.username}<br>
@RequestMapping("/modeattribute")
public String modeattribute(@ModelAttribute("user0") User user)
{
return "testmode";
}
如果不用@ModelAttribute也可以使用model.addAttribute(“user0”, user)完成数据回显
2.将方法返回值暴露为模型数据传到视图页面
<form method="post" action="${pageContext.request.contextPath}/modeattribute.action">
<input type="text" name="username"/>
<input type="submit" value="提交"/>
</form>
回显值:<br>
username:${user0.username}<br>
方法返回值:<br>
username:${user1.username}<br>
@ModelAttribute("user1")
public User setUser()
{
User user = new User();
user.setUsername("tom");
return user;
}
@RequestMapping("/modeattribute")
public String modeattribute(@ModelAttribute("user0") User user)
{
return "testmode";
}
二.@SessionAttributes
将模型中的属性暂存在session中,使同一个控制器类中的请求之间可以共享.(加载和更新过程在下文三)
showmode.jsp
username:${user1.username}<br>
testmode.jsp
<form method="post" action="${pageContext.request.contextPath}/modeattribute.action">
<input type="text" name="username"/>
<input type="submit" value="提交"/>
</form>
@Controller
@SessionAttributes("user1")
public class testmode {
@ModelAttribute("user1")
public User setUser()
{
User user = new User();
user.setUsername("tom");
return user;
}
@RequestMapping("/modeattribute")
public String modeattribute(@ModelAttribute("user1") User user)
{
return "redirect:/showmode.action";
}
@RequestMapping("/showmode")
public String showmode(ModelMap modelMap, SessionStatus sessionStatus)
{
//清除session数据的共享
sessionStatus.setComplete();
return "showmode";
}
}
三.@ModelAttribute和@SessionAttributes在ModelFactory中的加载
基于:org.springframework.web.method.annotation.ModelFactory
模型初始化:
public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
throws Exception {
//查看session中是否存在@SessionAttributes("")指定的属性,如果存在,添加到隐含模型;如果隐含模型中已经有该属性,覆盖已有的值.retrieveAttributes返回值可能是空
Map<String, ?> attributesInSession = this.sessionAttributesHandler.retrieveAttributes(request);
mavContainer.mergeAttributes(attributesInSession);
//将@ModelAttribute标注的方法的返回值添加到隐含模型
invokeModelAttributeMethods(request, mavContainer);
//findSessionAttributeArguments:返回被@ModelAttribute和@SessionAttributes注释的参数
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);
}
}
}
private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer mavContainer)
throws Exception {
for (InvocableHandlerMethod attrMethod : this.attributeMethods) {
String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value();
//存在就不再添加也就是原文所说:Attributes are added only if not already present in the model.
if (mavContainer.containsAttribute(modelName)) {
continue;
}
Object returnValue = attrMethod.invokeForRequest(request, mavContainer);
//方法返回值不为void,添加属性
if (!attrMethod.isVoid()){
String returnValueName = getNameForReturnValue(returnValue, attrMethod.getReturnType());
if (!mavContainer.containsAttribute(returnValueName)) {
mavContainer.addAttribute(returnValueName, returnValue);
}
}
}
}
模型更新:
//更新session中的值,更新model中的值
public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {
if (mavContainer.getSessionStatus().isComplete()){
this.sessionAttributesHandler.cleanupAttributes(request);
}
else {
this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel());
}
if (!mavContainer.isRequestHandled()) {
updateBindingResult(request, mavContainer.getModel());
}
}