处理模型数据

输出模型数据:

  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(推荐)

 

posted on 2018-11-07 18:05  溪水静幽  阅读(199)  评论(0编辑  收藏  举报