zoukankan      html  css  js  c++  java
  • Spring MVC 中 @ModelAttribute 注解的妙用

    Spring MVC 中 @ModelAttribute 注解的妙用

    Spring MVC 提供的这种基于注释的编程模型,极大的简化了 web 应用的开发。其中 @Controller@RestController 注解的组件使用 @RequestMapping@ExceptionHandler 等注解来表示请求映射,请求输入,异常处理等,使得开发者能专注于业务逻辑的编写,提高了开发效率。 带注释的控制器具有灵活的方法签名,不必扩展基类,也不需要实现特定的接口。

    可以使用 ServletWebApplicationContext 中的标准 Spring bean 定义来定义控制器 bean。 所有带有 @Controller 注解的类会被自动检测,就像 Spring 通常的扫描方式一样,检测类路径中的 @Component 类,并为它们自动注册 bean 定义。 它也充当注释类的刻板,表示它可以作为一个 Web 组件。

    带有 @RequestMapping 注解的方法叫做 Handler Method - 处理器方法,它的参数可以来自很多地方,比如 ServletRequestServletResponseHttpSession 等。

    @ModelAttribute

    在控制器的处理器方法参数上添加 @ModelAttribute 注释可以访问模型中的属性,如果不存在这个模型,则会自动将其实例化,产生一个新的模型。 模型属性还覆盖了来自 HTTP Servlet 请求参数的名称与字段名称匹配的值,也就是请求参数如果和模型类中的域变量一致,则会自动将这些请求参数绑定到这个模型对象,这被称为数据绑定,从而避免了解析和转换每个请求参数和表单字段这样的代码。 例如:

    @PostMapping("/componies/{componyId}/departments/{departmentId}/edit")
    public String processSubmit(@ModelAttribute Department department) { }
    

    这个处理器方法中的 department 参数会被从以下几个来源进行匹配绑定:

    • 已经定义过的模型方法(带有 @ModelAttribute 的方法,后面解释)
    • HTTP Session 中和字段名匹配的会话方法(带有 @SessionAttribute 的方法,和模型方法类似,只是作用域不同)
    • 经过 URL 转换器解析过的路径变量
    • 该模型类的默认构造方法
    • 调用具有与 Servlet 请求参数匹配的参数的 “主构造函数”; 参数名称通过 JavaBeans @ConstructorProperties 或通过字节码中的运行时保留参数名称确定。

    虽然一般都是使用模型方法 Model method 来使用属性填充模型,但另一种方法是依靠 Converter<String,T> 识别 URI 路径变量来绑定。在下面的例子中,模型属性名称 “user” 与 URI 路径变量 “user” 匹配,并且通过将 String 类型的用户名交给给已注册的 Converter<String,User> 这个转换器来生成创建模型:

    @PutMapping("/users/{user}")
    public String saveUser(@ModelAttribute("user") User user) {
        // ...
    }
    

    在获得模型属性实例之后,请求数据就会被绑定到模型属性上。 WebDataBinder 负责将 Servlet 请求参数名称(查询参数或表单字段)和目标模型对象上的字段名称进行匹配。 必要时会将属性的类型进行转换后再填充对应字段。

    数据绑定不能保证不会出错,发生错误时默认情况下会抛出 BindException 异常,但要在处理器方法中识别出这些错误,需要在 @ModelAttribute 后面添加一个 BindingResult 类型的参数,需要注意的是:这个参数必须和模型属性参数 (@ModelAttribute 参数)相邻,如下所示:

    @PostMapping("/owners/{componyId}/departments/{departmentId}/edit")
    public String processSubmit(@ModelAttribute("compony") Compony compony, BindingResult result) {
        if (result.hasErrors()) {
            return "componyForm";
        }
        // ...
    }
    

    这个例子表示如果用户提交的表单不符合预期的匹配规则,就会返回视图 componyForm

    有时候我们需要获得一个不带数据绑定的模型属性,也就是需要在处理器方法中使用 new 关键字来实例化一个对象。但是在 Spring MVC 中就不用这么麻烦了,我们可以将模型注入控制器并直接访问它,或者可以添加 @ModelAttribute(binding = false) 来表示不需要绑定数据,如下所示:

    @ModelAttribute
    public UserForm setUpForm() {
        return new UserForm();
    }
    

    @ModelAttribute
    public User findUser(@PathVariable String userId) {
    return userRepository.findOne(userId);
    }

    @PostMapping("update")
    public String update(@Valid UserUpdateForm form, BindingResult result,
    @ModelAttribute(binding=false)
    User user)
    {
    // ...
    }

    在参数上添加 javax.validation.Valid 注解或 Spring 的 @Validated 注解,就可以在数据绑定后使用字段校验功能了,就像这样:

    @PostMapping("/componies/{componyId}/departments/{departmentId}/edit")
    public String processSubmit(@Valid @ModelAttribute("department") Department department, BindingResult result) {
        if (result.hasErrors()) {
            return "departmentForm";
        }
        // ...
    }
    

    这样写和在方法体中写 model.addAttribute("compony",compony) 是等价的。

    需要注意的是 @ModelAttribute 注解如果不加,按照 BeanUtils 中的 isSimpleProperty 方法来判断,如果不属于简单类型的参数,都会被自动视为 ModelAttribute

    欢迎访问 郑保乐的博客

          </div>
        </div>
    </div>
  • 相关阅读:
    socket编程之二:两种链接类型tcp和udp
    屌丝、小白怎么拿国内巨头offer
    python调用tcpdump抓包过滤
    设计模式6大原则
    Javascript中bind()方法的使用与实现
    vue-cli中的check-versions.js配置文件包括semver,chalk,shell插件的解释
    基础组件(二)
    浏览器跨域请求之credentials
    跨域资源共享 CORS 详解
    PHP从入门到精通(六)
  • 原文地址:https://www.cnblogs.com/jpfss/p/10438646.html
Copyright © 2011-2022 走看看