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中尝试获取。如果仍旧获取不到,则会抛出异常!

目录
相关文章
|
24天前
|
XML 前端开发 安全
Spring MVC:深入理解与应用实践
Spring MVC是Spring框架提供的一个用于构建Web应用程序的Model-View-Controller(MVC)实现。它通过分离业务逻辑、数据、显示来组织代码,使得Web应用程序的开发变得更加简洁和高效。本文将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring MVC,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
54 2
|
JSON 前端开发 Java
构建健壮的Spring MVC应用:JSON响应与异常处理
构建健壮的Spring MVC应用:JSON响应与异常处理
67 0
|
7月前
|
数据采集 前端开发 Java
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
76 3
|
7月前
|
前端开发 Java Spring
参数解密:揭示Spring MVC请求参数处理的实际应用指南
参数解密:揭示Spring MVC请求参数处理的实际应用指南
59 1
|
7月前
|
前端开发 Java 数据库
【Spring原理进阶】SpringMVC调用链+JSP模板应用讲解
【Spring原理进阶】SpringMVC调用链+JSP模板应用讲解
|
存储 JSON Java
SpringMVC应用
SpringMVC应用
62 0
|
Java Apache Maven
Tiles与SpringMVC整合应用实践
Tiles与SpringMVC整合应用实践
109 0
|
自然语言处理 前端开发 Java
SpringMVC中form标签与数据绑定应用实践
SpringMVC中form标签与数据绑定应用实践
102 0
|
Java 数据库连接 Maven
SpringMvc 之crud增删改查应用
SpringMvc 之crud增删改查应用
62 0
|
7月前
|
设计模式 前端开发 JavaScript
Spring MVC(一)【什么是Spring MVC】
Spring MVC(一)【什么是Spring MVC】