zoukankan      html  css  js  c++  java
  • Spring MVC @ModelAttribute注解

      在一个Controller内,被@ModelAttribute标注的方法会在此controller的每个handler方法执行前被执行。

      被@ModelAttribute标注的方法的参数绑定规则和普通handler方法相同。

      可以理解为:

    1. 请求到达Controller后,不论其他handler方法的RequestMapping值是多少,请求都会路由至被@ModelAttribute标注的方法;
    2. 由springMVC再对request执行一次forward,路由至真正的handler方法。

    一 @ModelAttribute用于注解方法

    1 方法返回类型为void

      这种情况,@ModelAttribute只是单纯的作为请求路由的第一站,使用者可在方法内部操作Model和Request等参数实现功能。

       对于如下请求:

    http://localhost:8080/TestModelAttributeController/testHandler.action?reqParam=123

      对应的Controller:

    @Controller
    @RequestMapping("/TestModelAttributeController")
    public class TestModelAttributeController {
    
        @ModelAttribute
        public void modelAttributeMethod(HttpServletRequest request, String reqParam, Model model){
            model.addAttribute("reqParam",reqParam);
            request.setAttribute("methodParam","Hello ModelAttribute");
        }
    
    
        @RequestMapping("/testHandler")
        public String testHandler(){
            return "testModelAttribute";
        }
    }

       testModelAttribute.jsp如下:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <h1>${reqParam}</h1>
    <h1>${methodParam}</h1>
    </body>
    </html>

      最终可以在页面中看到:

      123

      Hello ModelAttribute

    2 方法返回类型不为void

    这种情况,@ModelAttribute会将返回值放到Model中,并将该类型名称的首字母小写作为model中的属性名

    请求地址和参数不变。

    对应的Controller:

        @ModelAttribute
        public User userModelAttributeMethod2(){
            User user = new User();
            user.setAge(31);
            user.setName("James");
            user.setEmail("123456@qq.com");
            return user;  //相当于model.addAttribute("user",user);
        }
    
    
        @RequestMapping("/testHandler")
        public String testHandler(Model model){
            System.out.println(model.containsAttribute("user"));  //true
            return "testModelAttribute";
    }

     对应的jsp页面

    <h1>${user.age}</h1>
    <h1>${user.email}</h1>
    <h1>${user.name}</h1>

       实际上,对于返回类型为void的方法,@ModelAttribute也会在model中添加一对键值对,“void”->"null"

    3 方法返回类型不为void,且@ModelAttribute指定属性名称

      这种情况下,@ModelAttribute会将返回值放到Medel中,且对应的key值为@ModelAttribute置顶的属性名

       对应的Controller:

     @ModelAttribute("myUser")
        public User userModelAttributeMethod2(){
            User user = new User();
            user.setAge(31);
            user.setName("James");
            user.setEmail("123456@qq.com");
            return user;  //相当于model.addAttribute("user",user);
        }
    
    
        @RequestMapping("/testHandler")
        public String testHandler(Model model){
            System.out.println(model.containsAttribute("user"));  //true
            return "testModelAttribute";
    }

      对应的jsp页面:

    <h1>${myUser.age}</h1>
    <h1>${myUser.email}</h1>
    <h1>${myUser.name}</h1>

    4 @ModelAttribute和@RequestMapping注解同一个方法

      这种情况下:

    1. 在controller处理其他请求时,不会再首先进入被@ModelAttribute和@RequestMapping同时注解的方法
    2. 该方法的返回值不再是视图的逻辑名称,而是按照@ModelAttribute的规则被加入到Model中;
    3. @RequestMapping注解的value值具有两个作用
      • 作为URI,实现请求的路由;
      • 作为此次请求的逻辑视图名(严格来说此时视图的逻辑视图名是:controller的RequestMapping值+method的RequestMapping值
    @Controller
    @RequestMapping("/TestModelAttributeController")
    public class TestModelAttributeController {
    
        @RequestMapping("/testModelAttribute")
        @ModelAttribute("result")
        public String testModelAttribute(){
            return "excellent";
        }
    <body>
    <h1>${result}</h1>
    </body>

    如上Controller和jsp:

    testModelAttribute方法的作用是:

    1. 处理路径为 /TestModelAttributeController/testModelAttribute*的请求
    2. 将键值对"result"->"excellent"放至model中,为视图渲染提供数据
    3. 返回逻辑视图名 /TestModelAttributeController/testModelAttribute

    二 @ModelAttribute注解方法入参

    @ModelAttribute("attrName")用在方法入参上时,作用为:

    • 从当前的隐式model对象中取key值attrName所对应的attrValue值,并将attrValue赋给被注解的参数。
    • 而且自动暴露为模型数据用于视图页面展示时使用

    1 @ModelAttribute指定注解的value值attrName

      如下所示,myUser和newParam两个model属性对应的attrValue值,将被赋值给方法入参。

        @ModelAttribute("myUser")
        public User userModelAttributeMethod2(Model model){
            User user = new User();
            user.setAge(31);
            user.setName("James");
            user.setEmail("123456@qq.com");
            
            model.addAttribute("newParam","new parameter");
            return user;
        }
    
    
        @RequestMapping("/testHandler")
        public String testHandler(@ModelAttribute("myUser") User user,@ModelAttribute("newParam") String newParam){
            System.out.println(user);
            System.out.println(newParam);
            return "testModelAttribute";
        

    2 @ModelAttribute注解value值缺省

      这时默认的attrName为类型名称的首字母小写

      如下例,user能够从model中获取,但是 newParam从model中获取的值为null

        @ModelAttribute("user") //此处必须是 user
        public User userModelAttributeMethod2(Model model){
            User user = new User();
            user.setAge(31);
            user.setName("James");
            user.setEmail("123456@qq.com");
    
            model.addAttribute("newParam","new parameter");
            return user;
        }
    
    
        @RequestMapping("/testHandler")
        public String testHandler(@ModelAttribute User user,@ModelAttribute String newParam){
            System.out.println(user);
            System.out.println(newParam);
            return "testModelAttribute";
        }

    3 入参不使用@ModelAttribute注解

      这种情况下,简单类型参数不会从model中取值,简单类型定义由 org.springframework.beans.BeanUtils#isSimpleValueType指定,如下:

        /**
         * Check if the given type represents a "simple" value type:
         * a primitive, an enum, a String or other CharSequence, a Number, a Date,
         * a URI, a URL, a Locale or a Class.
         * @param clazz the type to check
         * @return whether the given type represents a "simple" value type
         */
        public static boolean isSimpleValueType(Class<?> clazz) {
            return (ClassUtils.isPrimitiveOrWrapper(clazz) ||
                    Enum.class.isAssignableFrom(clazz) ||
                    CharSequence.class.isAssignableFrom(clazz) ||
                    Number.class.isAssignableFrom(clazz) ||
                    Date.class.isAssignableFrom(clazz) ||
                    URI.class == clazz || URL.class == clazz ||
                    Locale.class == clazz || Class.class == clazz);
        }
    View Code

      非简单类型会从model中取值,这时默认的attrName为类型名称的首字母小写。

      如下例,user能够从model中获取,但是newParam是简单类型,所以不会从model中取值。

     4 使用request参数和@ModelAttribute同时为同一个入参赋值

    这种情况需要根据入参的类型区别对待

    1. 对于非简单类型,spring会先使用@ModelAttribute为参数赋值,然后使用request的参数对入参的属性值进行覆盖;
    2. 对于简单类型,spring会使用@ModelAttribute为参数赋值,忽略request参数;

    如下例所示,URL为:

    这时user的name和age属性最终会被设置为request对应的参数值(也就是实现了对象合并),而reqParam的值最终会采用@ModelAttribute得到的值

        @ModelAttribute("user") //此处必须是 user
        public User userModelAttributeMethod2(Model model){
            User user = new User();
            user.setAge(31);
            user.setName("James");
            user.setEmail("123456@qq.com");
    
            model.addAttribute("reqParam","from @ModelAttribute");
            return user;
        }
    
    
        @RequestMapping("/testHandler")
        public String testHandler( @ModelAttribute("user") User user, @ModelAttribute("reqParam") String reqParam){
            System.out.println(user);  //user 对象的属性会被request的参数覆盖
            System.out.println(reqParam);  //reqParam参数的值始终是@ModelAttribute中的值,不会被覆盖
            return "testModelAttribute";
        }

    三 @ModelAttribute注解方法返回值

      此时@ModelAttribute的作用是将返回值添加至model,而这时的逻辑视图名称为:controller的RequestMapping值+method的RequestMapping值

      其实,这种用法和 @ModelAttribute和@RequestMapping注解同一个方法相同

  • 相关阅读:
    [二分][dp] Jzoj P3463 军训
    [树状数组] Jzoj P3462 休息
    [期望] Jzoj P3459 TheSwaps
    [dp] Jzoj P3460 Mixing Chemicals
    [数位dp][状压dp] Jzoj P3458 密码
    [匈牙利] Jzoj P1156 使命的召唤
    [bfs][状压] Jzoj P2121 分球
    [dp] Jzoj P1187 最大公共子串
    [树套树] Jzoj P5699 【gdoi2018 day1】涛涛接苹果
    [枚举] Jzoj P3387 终极武器
  • 原文地址:https://www.cnblogs.com/canger/p/10241576.html
Copyright © 2011-2022 走看看