hualinux springMVC 5.8:@ModelAtrribute注解

目录

一、@ModelAttribute注解详解之使用场景

1.1 常用场景分析

1.2 有问题的做法

1.2.1 传统做法

1.2.2 传统做法实现代码

1.3 正确做法

1.3.1 正确做法图示

1.3.2 实现代码

1.4 @ModelAtrribute注解的执行流程

二、 @ModelAtrribute源代码分析

三、 springMVC 确定目标方法 POJO 类型入参的过程

四、解决@ModelAtrribute中,map的键与执行目标方法的参数名不一致


@ModelAttribute注释方法 ,
在Spring mvc中,注解@ModelAttribute是一个非常常用的注解,其功能主要在两方面:

1、运用在参数上,会将客户端传递过来的参数按名称注入到指定对象中,并且会将这个对象自动加入ModelMap中,便于View层使用;

2、运用在方法上,会在每一个@RequestMapping标注的方法前执行,如果有返回值,则自动将该返回值加入到ModelMap中;

@ModelAttribute等价于上一章的 model.addAttribute("attributeName", abc); 

 

一、@ModelAttribute注解详解之使用场景

1.1 常用场景分析

表有几个字段,只修改符合条件的一条记录中的字段,其它一个字段不能修改。如密码不能修改,id是自增的

1.2 有问题的做法

1.2.1 传统做法

传统一般做法,如图:

new一个对象,然后表单参数传给这个对象,再执行update命令更新整个对象,其中两个字段有值,但会出现一个问题,其中一个字段没斌值,没有被更新的字段值会为空!

 

1.2.2 传统做法实现代码

先建立相关代码
src/main/java/com.hualinux.springmvc.entities/User2.java代码

package com.hualinux.srpingmvc.entities;

public class User2 {
    private Integer  id;
    private String username;
    private String password;
    private String email;
    private int age;

    public User2() {
    }

    public User2(Integer id, String username, String password, String email, int age) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.email = email;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User2{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}

在src/main/java/com.hualinux.srpingmvc.handers/SpringMVCTest.java,添加如下代码

先把 @SessionAttributes注解掉

    @RequestMapping("/springmvc/testModelAtrribute2")
    public String testModelAtrribute2(User2 user2){
        System.out.println("修改:"+user2);
        return "ok";
    }

打开web/index.jsp,在其页面的<body></body>标签中添加如下代码:

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

</div>

运行tomcat,idea会自动打开主页点,输入如下内容:

看到返回“ok,访问成功!”时,再看idea最下方的日志输出如下:

修改:User2{id=1, username='Tom', password='null', email='tom@hualinux.com', age=12}

上面发现密码是空,原来是123456的,你现在把它变成空了,肯定不行,不符合需求!

 

1.3 正确做法

1.3.1 正确做法图示

 

1.3.2 实现代码

在src/main/java/com.hualinux.srpingmvc.handers/SpringMVCTest.java,添加多一段代码,如下:

    //有@ModelAtrribute注解的方法,会在每个目标方法执行前被springMVC调用
    @ModelAttribute
    public void getUser(@RequestParam(value = "id",required = false) Integer id,
                        Map<String,Object> map ){
        if (id != null){
            //模拟从数据库中获取对象,这里为了方便就没有设置连接数据库
            User2 user2 = new User2(1,"li","123456","li@hualinux.com",20);
            System.out.println("从数据库中获取一个对象:"+user2);
            //把信息放在map中,
            map.put("user2",user2);
        }
    }

注意:在@ModelAttribute 修饰方法中,放入到Map时的键需要和目标方法入参参数的第一个字母小字的字符串一致。

这样总的代码有2段,如下:

 

再次运行一次看一下效果


看到返回“ok,访问成功!”时,再看idea最下方的日志输出如下:

发现名字、email、年龄都被修改了,密码没变,正是我们想要的效果

1.4 @ModelAtrribute注解的执行流程

1.执行@ModelAtrribute注解修饰的方法:从数据库中取出对象,并把对象放到了Map中,键为user

2.springMVC从Map集合中取出User对象,并把表单的请求参数赋值给user对象相应的属性

3.springMVC把上述对象传入目标方法的参数

4.这个user对象是存在request中,如果jsp表单中有对应的字段,还会自动填充表单

注意:在@ModelAtrribute修饰的方法中,放入Map时的键要和目标方法的参数名一致

 

二、 @ModelAtrribute源代码分析

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

 

三、 springMVC 确定目标方法 POJO 类型入参的过程

SpringMVC 确定目标方法P0J0类型入参的过程
1. 确定一个key:
  1)若目标方法的P0J0类型的参数木有使用@ModelAttribute作为修饰,则key为P0J0类名第一个字母的小写
  2)若使用了@ModelAttribute 来修饰,则key为@ModelAttribute注解的value属性值。

2.在implicitModel 中查找key对应的对象,若存在,则作为入参传入。
若在@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和P0J0类型的对象保存到implicitModel中,进而会保存到request中。

 

四、解决@ModelAtrribute中,map的键与执行目标方法的参数名不一致

解决@ModelAtrribute注解中,map集合的键与执行目标方法的参数名不一致的情况

其实我们可以在目标方法里面的参数中,定义一个@ModelAtrribute注解,并把其值指定为@ModelAtrribute注解修饰的方法中的map的键

src/main/java/com.hualinux.srpingmvc.handers/SpringMVCTest.java,相关的代码进行了一下修改

运行tomcat,idea会自动打开主页点,输入如下内容:

看到返回“ok,访问成功!”时,再看idea最下方的日志输出如下:

修改后的结果和没修改前的结果是一样的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值