处理模型数据
输出模型数据:
ModelAndView: 处理方法返回值类型为 ModelAndView时, 方法体即可通过该对象添加模型数据
Map 及 Model : 入参为org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map中的数据会自动添加到模型中
@SessionAttributes: 将模型中的某个属性暂存到 HttpSession 中,以便多个请求之间可以共享这个属性
@ModelAttribute: 方法入参标注该注解后, 入参的对象就会放到数据模型中
ModelAndView
控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息
SpringMVC 会把 ModelAndView 的 model 中数据放入到 request 域对象中
添加模型数据:
MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map<String, ?> modelMap)
设置视图:
void setView(View view )
void setViewName(String viewName)
Map 及 Model
Spring MVC在内部使用一个org.springframework.ui.Model接口存储模型数据
具体步骤
Spring MVC在调用方法前,会创建一个隐含的模型对象作为模型数据的存储容器
如果方法的入参为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些入参。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据
/** * 目标方法可以添加 Map 类型(实际上也可以是 Model 类型或 ModelMap 类型)的参数. * @param map * @return */ @RequestMapping("/testMap") public String testMap(Map<String, Object> map){ System.out.println(map.getClass().getName()); map.put("names", Arrays.asList("Tom", "Jerry", "Mike")); return SUCCESS; }
@SessionAttributes
若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个 @SessionAttributes, Spring MVC 将在模型中,对应的属性暂存到 HttpSession 中
@SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型,指定哪些模型属性需要放到会话中
@SessionAttributes(types=User.class) //会将隐含模型中所有类型为 User.class 的属性添加到会话中
@SessionAttributes(value={“user1”, “user2”}) //将名为 user1 和 user2 的模型属性添加到会话中
@SessionAttributes(types={User.class, Dept.class}) //将模型中所有类型为 User 及 Dept 的属性添加到会话中
@SessionAttributes(value={“user1”, “user2”}, types={Dept.class}) //将名为 user1 和 user2 的模型属性添加到会话中,同时将所有类型为 Dept 的模型属性添加到会话中
//SessionAttributes只能放在类上,不能在方法上 @SessionAttributes(value={"user"}, types={String.class}) @RequestMapping("/springmvc") @Controller public class SessionController { private static final String SUCCESS = "success"; @RequestMapping("/testSessionAttributes") public String testSessionAttributes(Map<String, Object> map) { User user = new User("Jack", "123"); map.put("user", user); map.put("msg", "hello"); return SUCCESS; } }
@ModelAttribute
在方法定义上使用 @ModelAttribute 注解:Spring MVC 在调用目标处理方法前,会先逐个调用在方法级上标注@ModelAttribute 的方法
在方法的入参前使用@ModelAttribute 注解:可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数绑定到对象模型中,再传入参
@ModelAttribute public void getUser(@RequestParam(value="id",required=false) Integer id, Map<String, Object> map){ System.out.println("modelAttribute method"); if(id != null){ //模拟从数据库中获取对象 User user = new User(1, "Tom", "123456", "tom@163.com", 12); System.out.println("从数据库中获取一个对象: " + user); map.put("user", user); } } @RequestMapping("/testModelAttribute") public String testModelAttribute(User user){ System.out.println("修改: " + user); return SUCCESS; }
运行流程:
1. 执行 @ModelAttribute 注解修饰的方法: 从数据库中取出对象, 把对象放入到了 Map 中,键为: user
2. SpringMVC 从 Map 中取出 User 对象, 并把表单的请求参数赋给该 User 对象的对应属性.
3. SpringMVC 把上述对象传入目标方法的参数.
注意: 在 @ModelAttribute 修饰的方法中, 放入到 Map 时,键需要和目标方法入参类型的第一个字母小写的字符串一致
SpringMVC 确定目标方法 POJO 类型入参的过程
1、 SpringMVC在调用处理方法前,在请求线程中自动创建一个隐含的模型对象
2、调用所有的标注@ModelAttribute的方法,并将方法的返回值添加到隐含对象中
3、查看Session中是否存在@SessionAttribute("xxx")所指向的xxx属性,如果有,将其添加到隐含模型中,如果隐含模型中已经存在xxx属性,会覆盖模型中已有的属性
4. 确定一个 key:
1). 若目标方法的 POJO 类型的参数没有使用 @ModelAttribute 作为修饰, 则 key 为 POJO 类名第一个字母的小写
2). 若使用@ModelAttribute 来修饰, 则 key 为 @ModelAttribute 注解的 value 属性值.
5. 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入,再用请求消息填充该入参对象直接返回,否则走6
6. 检查当前的 Handler 是否使用 @SessionAttributes(“xxx”) 注解修饰,即XXX是会话属性, 若使用该注解, 则会从 HttpSession 中来获取 key 所对应的 value 值, 若存在,将其赋给入参,再用请求消息填充该入参对象直接返回, 若不存在则将抛出异常HttpSessionRequiredException异常
7. 若 Handler 没有标识 @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则会通过反射来创建 POJO 类型的参数,再用请求消息填充入参, 传入为目标方法的参数
8. SpringMVC 会把 key 和 POJO 类型的对象保存到 implicitModel 中, 进而会保存到 request 中.
由使用@SessionAttributes引发的异常
如果在处理类定义处标注了@SessionAttributes(“xxx”),则尝试从会话中获取该属性,并将其赋给该入参,然后再用请求消息填充该入参对象。如果在会话中找不到对应的属性,则抛出 HttpSessionRequiredException 异常
RequestMapping方法中取ModelAttribute方法中的值
@ModelAttribute public void model(Model model){ //每次请求都会调用一次,使用一次对象清掉 model.addAttribute("name","Jim"); model.addAttribute("password","12345"); User user = new User(); user.setUserName("wwwwww"); user.setPassword("8888888"); user.setRealName("大叔"); model.addAttribute("user",user); } @RequestMapping("/test") public String testPage(){ return "user/test"; } @RequestMapping("/testAgain") public void test( @ModelAttribute("name") String name, //将ModelAttribute("name")的属性去掉,Model中的值将会被覆盖提交的值,如果参数是对象 @ModelAttribute("password") String password, //无论有无ModelAttribue("xxx"),提交内容总覆盖Model中的值,前台回显时,
//不回显passord的标签,再次提交password将不会更改 @RequestParam("name") String username, @RequestParam("password") String userPwd){ System.out.println(name+"----------"+password); System.out.println(username+"========"+userPwd); }
输入请求的/test,回显Jim,12345,输入Lucy,111提交/testAgain,打印的结果
Jim---------12345
Lucy======111
<table> <tr> <td>用户名:</td> <td><input type="text" name="name" value="${name}"/></td> </tr> <tr> <td>密码:</td> <td><input type="password" name="password" value="${password}"/></td> </tr> </table>
参考:
https://www.cnblogs.com/qdhxhz/p/8207047.html(推荐)