from:http://www.cnblogs.com/yy3b2007com/p/8204004.html cctext
Spring MVC提供了以下几种途径输出模型数据:
1)ModelAndView:处理方法返回值类型为ModelAndView时,方法体即可通过该对象添加模型数据;
2)Map及Model:处理方法入参为org.springframework.ui.Model、org.springframework.ui.ModelMap或java.util.Map时,处理方法返回时,Map中的数据会自动被添加到模型中;
3)@SessionAttributes:将模型中的某个属性暂存到HttpSeession中,以便多个请求之间可以共享这个属性;
4)@ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。
使用示例:
在TestModelData.java类中追加方法:
1 @RequestMapping("/testMap") 2 public String testMap(Mapmap) { 3 map.put("mapTestKey", "mapTestValue"); 4 return SUCCESS; 5 }
修改/WEB-INF/views/success.jsp页面,中
测试地址:http://localhost:8080/SpringMVC_02/testMap
返回页面打印信息:
SUCCESS PAGE
current time:
testMap mapTestKey:mapTestValue
查看此时入参Map实际什么类型,修改TestModelData.java代码:
@RequestMapping("/testMap") public String testMap(Mapmap) { map.put("mapTestKey", "mapTestValue"); System.out.println(map); System.out.println(map.getClass()); return SUCCESS; }
打印结果:
{mapTestKey=mapTestValue} class org.springframework.validation.support.BindingAwareModelMap
从打印结果发现,实际上入参Map是BildingAwareModelMap
public class BindingAwareModelMap extends ExtendedModelMap
public class ExtendedModelMap extends ModelMap implements Model
由于BildingAwareModelMap继承了ExtendedModelMap,而ExtendedModelMap又继承了ModeMap和实现了Model接口,因此,这里Map入参可以替换为ModelMap和Model。
从调试跟踪发现,入参map最终被解析的类是MapMethodProcessor.java
MapMethodProcessor.java
1 /* 2 * Copyright 2002-2017 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.web.method.annotation; 18 19 import java.util.Map; 20 21 import org.springframework.core.MethodParameter; 22 import org.springframework.lang.Nullable; 23 import org.springframework.util.Assert; 24 import org.springframework.web.bind.support.WebDataBinderFactory; 25 import org.springframework.web.context.request.NativeWebRequest; 26 import org.springframework.web.method.support.HandlerMethodArgumentResolver; 27 import org.springframework.web.method.support.HandlerMethodReturnValueHandler; 28 import org.springframework.web.method.support.ModelAndViewContainer; 29 30 /** 31 * Resolves {@link Map} method arguments and handles {@link Map} return values. 32 * 33 *A Map return value can be interpreted in more than one ways depending
34 * on the presence of annotations like {@code @ModelAttribute} or 35 * {@code @ResponseBody}. Therefore this handler should be configured after 36 * the handlers that support these annotations. 37 * 38 * @author Rossen Stoyanchev 39 * @since 3.1 40 */ 41 public class MapMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler { 42 43 @Override 44 public boolean supportsParameter(MethodParameter parameter) { 45 return Map.class.isAssignableFrom(parameter.getParameterType()); 46 } 47 48 @Override 49 @Nullable 50 public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, 51 NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { 52 53 Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure"); 54 return mavContainer.getModel(); 55 } 56 57 @Override 58 public boolean supportsReturnType(MethodParameter returnType) { 59 return Map.class.isAssignableFrom(returnType.getParameterType()); 60 } 61 62 @Override 63 @SuppressWarnings({ "unchecked", "rawtypes" }) 64 public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, 65 ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { 66 67 if (returnValue instanceof Map){ 68 mavContainer.addAllAttributes((Map) returnValue); 69 } 70 else if (returnValue != null) { 71 // should not happen 72 throw new UnsupportedOperationException("Unexpected return type: " + 73 returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); 74 } 75 } 76 77 }
当页面返回时,该入参会被加载到Request请求域。
3)@SessionAttributes:将模型中的某个属性暂存到HttpSeession中,以便多个请求之间可以共享这个属性;
1)若希望在多个请求之间共享某个模型属性数据,则可以在控制器类上标注@SessionAttributes,Spring MVC将在模型中对应的属性暂存到HttpSession中。
测试1:
在TestModelData.java中添加方法testSessionAttribute:
1 @RequestMapping("/testSessionAttribute") 2 public String testSessionAttribute(Mapmap) { 3 Account account = new Account("user1", "pwd123", "2018-01-07", "127.0.0.1"); 4 map.put("account", account); 5 6 System.out.println("testSessionAttribute:"+map); 7 8 return SUCCESS; 9 }
Account.java
修改index.jsp,添加链接HTML:
<a href="testSessionAttribute">test SessionAttributea>
修改/WEB-INF/views/success.jsp,添加HTML脚本:
SUCCESS PAGE<br> testSessionAttribute request:${requestScope.account.username }<br> testSessionAttribute session:${sessionScope.account.username }<br>
此时访问index.jsp,并点击链接后条状到success.jsp也页面显示信息如下:
测试2:
此时默认情况下,并没有把account实体存放到HttpSession中,如何才能实现呢?-------修改TestModelData.java,在TestModelData类上添加注解@SessionAttributes:
1 @SessionAttributes(value = { "account" }) 2 @Controller 3 public class TestModelData { 4 private final String SUCCESS = "success"; 5 6 @RequestMapping("/testSessionAttribute") 7 public String testSessionAttribute(Mapmap) { 8 Account account = new Account("user1", "pwd123", "2018-01-07", "127.0.0.1"); 9 map.put("account", account); 10 11 System.out.println("testSessionAttribute:" + map); 12 13 return SUCCESS; 14 } 15 }
此时重新测试,跳转到success.jsp页面时,显示结果如下:
说明已经把account实体对象存放到map的同时,也存放到了HttpSession中。
2)@SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中。
测试3:
上边是通过指定属性名称的方式将account对象存放到HttpSession中的,实际上我们也可以通过指定对象类型实现把某一类对象存放到HttpSession。
修改TestModelData.java
1 @SessionAttributes(value = { "my_value_key" }, types = { Account.class, Integer.class }) 2 @Controller 3 public class TestModelData { 4 private final String SUCCESS = "success"; 5 6 @RequestMapping("/testSessionAttribute") 7 public String testSessionAttribute(Mapmap) { 8 Account account = new Account("user1", "pwd123", "2018-01-07", "127.0.0.1"); 9 map.put("account", account); 10 map.put("my_value_key", "my_value"); 11 Integer age = 30; 12 map.put("age", age); 13 Float onlineHours = 129.88f; 14 map.put("onlineHours", onlineHours); 15 16 System.out.println("testSessionAttribute:" + map); 17 18 return SUCCESS; 19 } 20 }
修改/WEB-INF/views/success.jsp页面:
1 SUCCESS PAGE<br> 2 testSessionAttribute request account.username:${requestScope.account.username }<br> 3 testSessionAttribute session account.username:${sessionScope.account.username }<br> 4 <br> 5 testSessionAttribute request my_value_key:${requestScope.my_value_key }<br> 6 testSessionAttribute session my_value_key:${sessionScope.my_value_key }<br> 7 <br> 8 testSessionAttribute request age:${requestScope.age }<br> 9 testSessionAttribute session age:${sessionScope.age }<br> 10 <br> 11 testSessionAttribute request age:${requestScope.onlineHours }<br> 12 testSessionAttribute session age:${sessionScope.onlineHours }<br>
此时访问链接地址,跳转到success.jsp页面后,显示结果:
4)@ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。
Account.java
1 package com.dx.springlearn.entities; 2 3 public class Account { 4 public Integer id; 5 private String username; 6 private String password; 7 private String registerDate; 8 private String registerIP; 9 10 public Account() { 11 } 12 13 public Account(Integer id, String username, String password, String registerDate, String registerIP) { 14 super(); 15 this.id = id; 16 this.username = username; 17 this.password = password; 18 this.registerDate = registerDate; 19 this.registerIP = registerIP; 20 } 21 22 public Account(String username, String password, String registerDate, String registerIP) { 23 super(); 24 this.username = username; 25 this.password = password; 26 this.registerDate = registerDate; 27 this.registerIP = registerIP; 28 } 29 30 public Integer getId() { 31 return id; 32 } 33 34 public void setId(Integer id) { 35 this.id = id; 36 } 37 38 public String getUsername() { 39 return username; 40 } 41 42 public void setUsername(String username) { 43 this.username = username; 44 } 45 46 public String getPassword() { 47 return password; 48 } 49 50 public void setPassword(String password) { 51 this.password = password; 52 } 53 54 public String getRegisterDate() { 55 return registerDate; 56 } 57 58 public void setRegisterDate(String registerDate) { 59 this.registerDate = registerDate; 60 } 61 62 public String getRegisterIP() { 63 return registerIP; 64 } 65 66 public void setRegisterIP(String registerIP) { 67 this.registerIP = registerIP; 68 } 69 70 @Override 71 public String toString() { 72 return "Account [id=" + id + ", username=" + username + ", password=" + password + ", registerDate=" 73 + registerDate + ", registerIP=" + registerIP + "]"; 74 } 75 76 77 }
Handler类TestModelData.java
1 package com.dx.springlearn.hanlders; 2 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import java.util.Map; 6 7 import org.springframework.stereotype.Controller; 8 import org.springframework.web.bind.annotation.ModelAttribute; 9 import org.springframework.web.bind.annotation.RequestMapping; 10 import org.springframework.web.bind.annotation.RequestParam; 11 import org.springframework.web.servlet.ModelAndView; 12 13 import com.dx.springlearn.entities.Account; 14 15 @Controller 16 public class TestModelData { 17 private final String SUCCESS = "success"; 18 19 @ModelAttribute 20 public void getAccount(@RequestParam(name = "id", required = false) Integer id, Mapmap) { 21 if (id != null) { 22 System.out.println("read account(id=" + id + ") from db"); 23 Account account = new Account(1, "tommy", "123456", "2018-01-20 21:56:09", "127.0.0.1"); 24 map.put("account", account); 25 } else { 26 System.out.println("the acount id is null"); 27 } 28 } 29 30 @RequestMapping("/testModelAttribute") 31 public ModelAndView testModelAttribute(Account account) { 32 System.out.println("accept account:" + account); 33 String viewName = SUCCESS; 34 ModelAndView modelAndView = new ModelAndView(viewName); 35 modelAndView.addObject("currentTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); 36 37 return modelAndView; 38 } 39 }
测试表单页面:
<form id="form_testModelAttribute" action="testModelAttribute" method="POST"> <input name="id" type="hidden" value="1"/> username:<input name="username" type="text" value="tommy" /><br> register date:<input name="registerDate" type="text" value="2018-01-20 21:56:09" /><br> register ip:<input name="registerIP" type="text" value="127.0.0.1"/><br> <input type="submit" value="Submit"/> form>
除了handler目标方法参数第一个参数名称与存放到map中的对象名称一致外,也可以使用@ModelAttribute标注handler目标方法参数:
package com.dx.springlearn.hanlders; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import com.dx.springlearn.entities.Account; @Controller public class TestModelData { private final String SUCCESS = "success"; @ModelAttribute public void getAccount(@RequestParam(name = "id", required = false) Integer id, Mapmap) { if (id != null) { System.out.println("read account(id=" + id + ") from db"); Account account = new Account(1, "tommy", "123456", "2018-01-20 21:56:09", "127.0.0.1"); map.put("testabc", account); } else { System.out.println("the acount id is null"); } } @RequestMapping("/testModelAttribute") public ModelAndView testModelAttribute(@ModelAttribute("testabc") Account account) { System.out.println("accept account:" + account); String viewName = SUCCESS; ModelAndView modelAndView = new ModelAndView(viewName); modelAndView.addObject("currentTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); return modelAndView; } }
1)运行有@ModelAttribute注解标注的方法:从数据库中取出对象,把对象放入到Map中,键值为:user;
2)SpringMVC从Map中取出User对象,并把表单的请求参数赋值给该User对象的对应属性;
3)SpringMVC把上述对象传入目标方法的参数(参数名称必须与Map中的键值一致)。
注意:在@ModelAttribute修饰的方法中,放入Map是的键类型要与目标方法入参类型一直,而且Map是的键名称要与目标方法入参的参数名一致。