SpringMVC中@ModelAttribute应用实践

简介: SpringMVC中@ModelAttribute应用实践

【1】场景需求与分析

背景需求如下,当更新一个对象时,某个字段比如密码不能被修改。

常见解决思路有如下


① new 一个对象,form表单中密码域为隐藏域,该种方法有风险。

② new 一个对象,在更新的时候再次从数据库查询密码从而进行更新,该方法比较麻烦。

SpringMVC的解决思路:使用@ModelAttribute

① JSP页面

<form action="springmvc/testModelAttribute" method="Post">
  <input type="hidden" name="id" value="1"/>
  //注意此处隐藏域为id
  username: <input type="text" name="username" value="Tom"/>
  <br>
  email: <input type="text" name="email" value="tom@baidu.com"/>
  <br>
  age: <input type="text" name="age" value="18"/>
  <br>
  <input type="submit" value="Submit"/>
</form>


② 后台代码

使用@ModelAttribute注解标注方法。

//该方法模拟根据id从数据库获取对象。
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false) Integer id, Map<String, Object> map){
  System.out.println("modelAttribute method execute...");
  if(id != null){
    //模拟从数据库中获取对象
    User user = new User(1, "Tom", "123456", "tom@baidu.com", 12);
    System.out.println("从数据库中获取一个对象: " + user);
    map.put("user", user);
  }
}
//根据表单name属性值对model中的user对象进行更新。因为表单域没有密码,故密码使用数据库查询得到的。
@RequestMapping("/testModelAttribute")
public String testModelAttribute(@ModelAttribute("user") User user){
  System.out.println("修改: " + user);
  return SUCCESS;
}


测试结果

从数据库中获取一个对象: User [username=Tom, password=123456, email=tom@baidu.com, age=12, address=null]
修改: User [username=Tom, password=123456, email=tom@baidu.com, age=18, address=null]

对比可知,age进行了更新 ,password延用了数据库查询的数据。如下图所示,map中最终放的user并非数据库查询得到,而是经过了表单更新后的user。

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

① 合并sessionAttributes中value不为null的属性到model中;

② 调用@ModelAttribute的方法;

③ 检测sessionAttributes存在标注了@ModelAttribute注解的方法参数但是值为null的情况,这种情况将会抛出异常


e0dc4f5e96d24ce08c2cb711a68eeccf.png


④ 确定目标方法参数的name(key)


若使用了 @ModelAttribute 且指定了value属性值如 @ModelAttribute("user") SysUser sysUser , 则 key 为 @ModelAttribute 注解的 value 属性值。

否则为若目标方法的 POJO 类型的名称如SysUser-sysUser;

⑤ 确定value


若model中存在key,则直接返回value;

若使用了@SessionAttributes注解且key-value存在不为空,则返回value(实际从session获取);

反射实例化一个空的pojo对象返回

⑥ 返回target和绑定结果(如果绑定过程出错,这个会有需要)

【3】@ModelAttribute运用实例

① @ModelAttribute注释void返回值的方法

@Controller  
 public class HelloWorldController {  
     @ModelAttribute  
     public void populateModel(@RequestParam String abc, Model model) {  
        model.addAttribute("attributeName", abc);  //返回model
     }  
     @RequestMapping(value = "/helloWorld")  
     public String helloWorld() {  
        return "helloWorld";  //返回的视图名
     }  
}


这个例子,在获得请求/helloWorld 后,populateModel方法在helloWorld方法之前先被调用,它把请求参数(/helloWorld?abc=text)加入到一个名为attributeName的model属性中,在它执行后helloWorld被调用,返回视图名helloWorld和model(已由@ModelAttribute方法生产好了)。

② @ModelAttribute注释返回具体类的方法

@ModelAttribute  
public Account addAccount(@RequestParam String number) {  
    return accountManager.findAccount(number);  
 }


这种情况,model属性的名称没有指定,它由返回类型隐含表示,如这个方法返回Account类型,那么这个model属性的名称是account(默认为对象类型的首字母小写)。

③ @ModelAttribute(value="")注释返回具体类的方法

 @Controller  
public class HelloWorldController {  
      @ModelAttribute("abc")  
      public String addAccount(@RequestParam String abc) {  
         return abc;  
      }  
      @RequestMapping(value = "/helloWorld")  
      public String helloWorld() {  
         return "helloWorld";  //返回的视图名
      }  
  }   


这个例子中使用@ModelAttribute注释的value属性,来指定model属性的名称。model属性对象就是方法的返回值(abc),它无须要特定的参数。


如果 @ModelAttribute(“abc”),然后方法里面使用了map.put(“user”,user)。那么,map额外会存在一个 key为abc,value为null的对象!其他方法如果绑定了 abc属性,那么将会获取到null!

④ @ModelAttribute和@RequestMapping同时注释一个方法

@Controller  
public class HelloWorldController {  
     @RequestMapping(value = "/helloWorld.do")  
     @ModelAttribute("attributeName")  
     public String helloWorld() {  
        return "hi";  
     }  
}

这时这个方法的返回值并不是表示一个视图名称,而是model属性的值,视图名称由RequestToViewNameTranslator根据请求"/helloWorld.do"转换为逻辑视图helloWorld。

Model属性名称有@ModelAttribute(value=””)指定,相当于在request中封装了key=attributeName,value=hi。

⑤ @ModelAttribute注释一个方法的参数

@Controller  
public class HelloWorldController {  
       @ModelAttribute("user")  
       public User addAccount() {  
          return new User("jz","123");  
       }  
       @RequestMapping(value = "/helloWorld")  
       public String helloWorld(@ModelAttribute("user") User user) {  
          user.setUserName("jizhou");  
          return "helloWorld";  
       }  
}


在这个例子里,@ModelAttribute("user") User user注释方法参数,参数user的值来源于addAccount()方法中的model属性。


因为@ModelAttribute 注解的方法总会在其他方法调用前执行。


此时如果类没有标注@SessionAttributes("user"),那么scope为request,如果标注了,那么scope为session。如果controller上标注了@SessionAttributes("user"),那么如果从model中获取不到,就会从session中尝试获取。如果仍旧获取不到,则会抛出异常!

目录
相关文章
|
XML 前端开发 JavaScript
Spring MVC应用的开发步骤
Spring MVC应用的开发步骤
120 0
|
6月前
|
数据采集 前端开发 Java
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
68 3
|
JSON 前端开发 Java
构建健壮的Spring MVC应用:JSON响应与异常处理
构建健壮的Spring MVC应用:JSON响应与异常处理
63 0
|
11月前
|
Java Apache Maven
Tiles与SpringMVC整合应用实践
Tiles与SpringMVC整合应用实践
102 0
|
设计模式 XML JSON
Spring MVC 深度解析与应用实践(1)
1. 引言 1.1 Spring MVC 概述 Spring MVC(Model-View-Controller)是 Spring 框架的一部分,专门用于设计创建分层的 Java Web 应用。它是一个全功能的 MVC 模块,能够提供强大的配置选项,并利用默认的约定,使基本项目的配置降至最低。Spring MVC 提供了一种分离的方式,使得能够通过控制器(Controller)进行业务处理,模型(Model)进行数据处理,视图(View)进行展示处理,这样使得 Web 层的开发变得更加简洁明了。
4928 1
Spring MVC 深度解析与应用实践(1)
|
数据库
“构建高效的SpringMVC增删改查应用“(下)
“构建高效的SpringMVC增删改查应用“
61 0
“构建高效的SpringMVC增删改查应用“(上)
“构建高效的SpringMVC增删改查应用“
50 0
|
XML 前端开发 Java
【Spring MVC 系列】异常处理,为你的应用加层防护
概述 异常处理是几乎所有编程语言都具有的特性,主要是处理程序运行时的非预期行为,保证程序的健壮性。JVM 运行时如果遇到未经处理的异常线程将意外退出,为了避免这种情况需要为线程设置默认的异常处理器。
193 0
【Spring MVC 系列】异常处理,为你的应用加层防护
|
前端开发 JavaScript Java
ContentNegotiation内容协商机制(三)---在视图View上的应用:ContentNegotiatingViewResolver深度解析【享学Spring MVC】(下)
ContentNegotiation内容协商机制(三)---在视图View上的应用:ContentNegotiatingViewResolver深度解析【享学Spring MVC】(下)
ContentNegotiation内容协商机制(三)---在视图View上的应用:ContentNegotiatingViewResolver深度解析【享学Spring MVC】(下)
|
JSON 前端开发 Java
ContentNegotiation内容协商机制(三)---在视图View上的应用:ContentNegotiatingViewResolver深度解析【享学Spring MVC】(中)
ContentNegotiation内容协商机制(三)---在视图View上的应用:ContentNegotiatingViewResolver深度解析【享学Spring MVC】(中)
ContentNegotiation内容协商机制(三)---在视图View上的应用:ContentNegotiatingViewResolver深度解析【享学Spring MVC】(中)