Spring MVC 中“拦截器”处理模型数据 (二) @ModelAttribute

在这里强烈建议看看我之前写的几篇关于SpringMVC的博客,都是串通的。

@ModelAttribute这个是SpringMVC中处理模型数据的最难也是最重要的点。相当于以前Struct的拦截器。

用途:比如我们要修改一个对象的部分数据,按照以前的思维,new一个对象保存数据,然后赋值,把不修改数据先拿出来保存起来。但是这个已经Out了, 在SpringMVC中,是拿到数据库的实例,然后把传进来的值也就是需要修改的值set进去,那么没有set的值即为不需要修改的值。

index.jsp

<!-- 模拟修改操作
        1. 原始数据 : 1, yexx, 123456, yexx@hust.com, 12
        2. 密码不能被修改
        3. 表单回显, 模拟操作直接在表单填写对应的属性值
     -->
    <form action="springmvc/testModelAttributes" method="post">
        <input type="hidden" name="id" value="1"/>
        username: <input type="text" name="username" value="yexx"/>
        <br/>
        email: <input type="text" name="email" value="yexx@hust.com"/>
        <br/>
        age: <input type="text" name="age" value="13"/>
        <br/>
        <input type="submit" value="Submit"/>
    </form>
package com.hust.springmvc1;

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 com.hust.springmvc.entities.User;

//@SessionAttributes(value={"user"}, types={String.class})
@Controller
@RequestMapping("/springmvc")
public class SpringMVCTest { 

    private static final String SUCCESS = "success";

    /**
     * 1. 由@ModelAttribute 标记的方法,会在每个目标方法执行之前被SpringMVC调用!
     * 2. @ModelAttribute 注解也可以来修饰目标方法POJO 类型的入参,且value 属性值如下的作用:
     * 1). SpringMVC 会使用value 属性值 在implicitModel 中查找对应的对象,若存在则会直接传入到目标方法的入参中。
     * 2). SpringMVC 会一value 为 key , POJO 类型的对象为value, 存入request 中。
     */
    @ModelAttribute
    public void getUser(@RequestParam(value="id", required=false) Integer id,
            Map<String, Object> map) {
        System.out.println("ModelAttribute");
        if (id!=null) {
            //模拟从数据库中获取对象
            User user = new User(1, "yexx", "123456", "yexx@hust.com", 12);
            System.out.println("从数据库中获取一个对象:" + user);
            map.put("user", user);
        }
    }

    /**
     * 运行流程:
     * 1. 执行@ModelAttribute 注解修饰的方法:从数据库中取出对象,把对象放入到Map中。键为:user
     * 2. SpringMVC 从 Map 中取出user对象, 并把表单的请求参数赋给该User 对象对应的属性。
     * 3. SpringMVC 把上述对象传入目标方法的参数。
     *
     * 注意: 在@ModelAttribute  修饰的方法中,放入到Map时的键需要和目标方法入参类型的第一个字母小写的字符串一致
     *
     * SpringMVC 确定目标方法POJO 类型入参的过程
     * 1. 确定一个key:
     * 1). 若目标方法的POJO类型的参数木有使用@ModelAttribute 作为修饰,则key 为 POJO类名第一个字母的小写
     * 2). 若使用了@ModelAttribute 来修饰, 则key 为@ModelAttribute 注解的value属性值。
     * 2. 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入
     * 1). 若在@ModelAttribute 标记的方法中在 Map 中保存过, 且 key 和 1 确定的key 一致,则会获取到。
     * 3. 若 implicitModel 中不存在key 对应的对象, 则检查当前的 Handler 是否使用了@SessionAttributes 注解修饰,
     * 若使用了该注解, 且 @SessionAttributes 注解的 value 属性值中包含了key, 则会从HttpSession 中来获取 key 所对应
     * 的value 的值, 若存在则直接传入到目标方法的入参中, 若不存在则将抛出异常。
     * 4. 若Handler 没有表示@SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则会
     * 通过反射来创建 POJO类型的参数, 传入为目标方法的参数
     * 5. SpringMVC 会把key 和 POJO 类型的对象 保存到implicitModel 中, 进而会保存到 request 中。
     *
     * 源代码分析的流程
     * 1. 调用@ModelAttribute 注解修饰的方法。 实际上把@ModelAttribute 方法中Map 中的数据放在了 implicitModel中。
     * 2. 解析请求处理器的目标参数,实际上该目标参数来自于 WebDataBinder 对象的 target属性
     * 1). 创建WebDataBinder 对象
     * ① 确定objectName 属性: 若传入的attrName 属性值为空,则objectName 为类名第一个字母小写。
     * *注意: attrName 若目标方法的POJO属性使用了@ModelAttribute 来修饰,则attrName 值即为 @ModelAttribute的value值
     * ② 确定target 属性:
     *  > 在implicitModel 中查找 attrName 对应的属性值。 若存在。 OK
     *  > 若不存在: 则验证当前Handler 是否使用了@sessionAttributes 进行修饰,若使用了,则尝试从Session中获取attrName 所对应
     *  的属性值。 若session 中没有对应的属性值,则抛出异常
     *  > 若Handler 没有使用@SessionAttributes 进行修饰, 或@SessionAttribute 中没有使用 value 值制定的 key
     *  和 attrName 相匹配,则通过反射创建POJO对象
     *
     *  2). SpringMVC 把表单的请求参数赋给了WebDataBinder 的target 属性
     *  3). *SpringMVC 会把WebDataBinder 的attrName 和 target 给到 implicitModel
     *  4). 把WebDataBinder 的 target 作为参数传递给目标方法入参。
     */
    @RequestMapping("/testModelAttributes")
    public String testModelAttributes(@ModelAttribute("user") User user) {
        System.out.println("update:" + user);
        return SUCCESS;
    }
}

这段程序的运行结果就会是:

该回显数据也是能够显示出来。我把执行过程和源码分析拿出来特别的说一下。

运行流程:

 * 1. 执行@ModelAttribute 注解修饰的方法:从数据库中取出对象,把对象放入到Map中。键为:user
 * 2. SpringMVC 从 Map 中取出user对象, 并把表单的请求参数赋给该User 对象对应的属性。
 * 3. SpringMVC 把上述对象传入目标方法的参数。
 *
 * 注意: 在@ModelAttribute  修饰的方法中,放入到Map时的键需要和目标方法入参类型的第一个字母小写的字符串一致。

源代码分析的流程

 * 1. 调用@ModelAttribute 注解修饰的方法。 实际上把@ModelAttribute 方法中Map 中的数据放在了 implicitModel中。
 * 2. 解析请求处理器的目标参数,实际上该目标参数来自于 WebDataBinder 对象的 target属性
 * 1). 创建WebDataBinder 对象
 * ① 确定objectName 属性: 若传入的attrName 属性值为空,则objectName 为类名第一个字母小写。
 * *注意: attrName 若目标方法的POJO属性使用了@ModelAttribute 来修饰,则attrName 值即为 @ModelAttribute的value值
 * ② 确定target 属性:
 *  > 在implicitModel 中查找 attrName 对应的属性值。 若存在。 OK
 *  > 若不存在: 则验证当前Handler 是否使用了@sessionAttributes 进行修饰,若使用了,则尝试从Session中获取attrName 所对应
 *  的属性值。 若session 中没有对应的属性值,则抛出异常
 *  > 若Handler 没有使用@SessionAttributes 进行修饰, 或@SessionAttribute 中没有使用 value 值制定的 key
 *  和 attrName 相匹配,则通过反射创建POJO对象
 *
 *  2). SpringMVC 把表单的请求参数赋给了WebDataBinder 的target 属性
 *  3). *SpringMVC 会把WebDataBinder 的attrName 和 target 给到 implicitModel
 *  4). 把WebDataBinder 的 target 作为参数传递给目标方法入参。

SpringMVC 确定目标方法POJO 类型入参的过程

 * 1. 确定一个key:
 * 1). 若目标方法的POJO类型的参数木有使用@ModelAttribute 作为修饰,则key 为 POJO类名第一个字母的小写
 * 2). 若使用了@ModelAttribute 来修饰, 则key 为@ModelAttribute 注解的value属性值。
 * 2. 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入
 * 1). 若在@ModelAttribute 标记的方法中在 Map 中保存过, 且 key 和 1 确定的key 一致,则会获取到。
 * 3. 若 implicitModel 中不存在key 对应的对象, 则检查当前的 Handler 是否使用了@SessionAttributes 注解修饰,
 * 若使用了该注解, 且 @SessionAttributes 注解的 value 属性值中包含了key, 则会从HttpSession 中来获取 key 所对应
 * 的value 的值, 若存在则直接传入到目标方法的入参中, 若不存在则将抛出异常。
 * 4. 若Handler 没有表示@SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则会
 * 通过反射来创建 POJO类型的参数, 传入为目标方法的参数
 * 5. SpringMVC 会把key 和 POJO 类型的对象 保存到implicitModel 中, 进而会保存到 request 中。

总结

* 1. 由@ModelAttribute 标记的方法,会在每个目标方法执行之前被SpringMVC调用!
 * 2. @ModelAttribute 注解也可以来修饰目标方法POJO 类型的入参,且value 属性值如下的作用:
 * 1). SpringMVC 会使用value 属性值 在implicitModel 中查找对应的对象,若存在则会直接传入到目标方法的入参中。
 * 2). SpringMVC 会一value 为 key , POJO 类型的对象为value, 存入request 中。

这里有一个特别值得注意的地方


如果你的Controller被@SessionAttributes修饰了,而且value也是那个,而且没用@ModelAttribute修饰方法,同时也没有@ModelAttribute修饰目标方法入参。这个时候就会抛出异常。我们知道原理之后很容易去避免这个异常。

时间: 2024-10-16 05:09:45

Spring MVC 中“拦截器”处理模型数据 (二) @ModelAttribute的相关文章

spring mvc 使用拦截器和在controller中使用if语句的服务器资源使用率和效率对比?

问题描述 spring mvc 使用拦截器和在controller中使用if语句的服务器资源使用率和效率对比? 就比如 用户权限问题,一个没有权限的用户要访问只有管理员才有权限访问的请求地址 使用框架配的拦截器的方式与在controller或者userServiceimpl中使用if语句进行权限访问的控制方式,两种方式的服务器资源使用率和执行效率方面比较情况是怎样的? 解决方案 个人观点,这就像数据库的,lazy模式和非lazy模式差不多

Spring MVC 之拦截器(八)

 在springMVC中实现拦截器有两种方式 1.实现HandlerInterceptor接口 2.继承HandlerInterceptorAdaptor类 编写拦截器: 1 package com.cy.springannotation.interceptor; 2 3 import javax.servlet.http.HttpServletRequest; 4 import javax.servlet.http.HttpServletResponse; 5 6 import org.apa

springmvc-spring MVC 的拦截器怎么拦截不了

问题描述 spring MVC 的拦截器怎么拦截不了 我想用spring mvc实现登录拦截: 配置文件:mvc:interceptorsmvc:interceptor /mvc:interceptormvc:interceptor /mvc:interceptor 因为是spring3.0不支持 <mvc:exclude-mapping >标签,所以我在perHandle的方法来排除不需要的拦截的url. 问题如下: 在controller里@Controller @RequestMappi

MVC中使用Knockout,json获取数据成功后,遍历填充视图模型时,代码不执行怎么回事

问题描述 MVC中使用Knockout,json获取数据成功后,遍历填充视图模型时,代码不执行怎么回事 function AppViewModel() { var self = this; self.brandstandards = ko.observableArray(); self.cart = ko.observableArray(); self.orders = ko.observableArray(); function BrandStandardViewModel(firstself

easyui-关于spring mvc框架 easyUI界面将excel数据导入到数据库中的方法

问题描述 关于spring mvc框架 easyUI界面将excel数据导入到数据库中的方法 将一个excel表格的文件导入到数据库中,在界面调用得到所有数据的方法将数据显示在页面上,如何将excel表格的文件导入到数据库中呢 解决方案 可以使用poi 插件,对Excel进行操作,获取数据,保存到数据库中

Spring MVC 中的@RequestMapping(method = RequestMethod.OPTIONS)无法拦截

问题描述 Spring MVC 中的@RequestMapping(method = RequestMethod.OPTIONS)无法拦截,貌似这个注解不能拦截OPTIONS方法,get,post,put都能,为什么这个不能,有什么解决办法 解决方案 这里给个提示,看是否解决:http://stackoverflow.com/questions/23103832/spring-mvc-does-not-handle-requestmethod-options

Spring MVC中的MultiActionController用法详解

Spring MVC 中 Controller 的层次实在是多,有些眼花缭乱了 .在单个的基础上,再新加两三个叫做丰富,再多就未必是好事, 反而会令人缩手新闻片脚,无从定夺.多数 Controller 都是只完 成一个任务,不过也有一个像 Struts 的 DispatchAction 的那样 的 Conntroller, org.springframework.web.servlet.mvc.multiaction.MultiActio nController,意即在一个 Controller

jsp页面传值在spring mvc中的controller中的获取

问题描述 jsp页面传值在spring mvc中的controller中的获取 <% Seller seller =(Seller)session.getAttribute("sellerinfo"); %> <form action="<%=basePath%>plmanage/updateSeller.do" method="post"> <input type="hidden"

Http请求中Content-Type讲解以及在Spring MVC中的应用

引言: 在Http请求中,我们每天都在使用Content-type来指定不同格式的请求信息,但是却很少有人去全面了解content-type中允许的值有多少,这里将讲解Content-Type的可用值,以及在Spring MVC中如何使用它们来映射请求信息. Content-Type MediaType,即是Internet Media Type,互联网媒体类型:也叫做MIME类型,在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息. [html] view pl