SpringMVC中的Model和ModelAndView详解
0.前言
1.Model是什么?
model是”模型“的意思,是MVC架构中的”M“部分,是用来传输数据的。
2.ModelAndView是什么?
如果翻译过来就是”模型和视图“,可以理解成MVC架构中的”M“和”V“,其中包含”Model“和”view“两部分,主要功能是:
- 设置转向地址
- 将底层获取的数据进行存储(或者封装)
- 最后将数据传递给View
区别?
1.Model只是用来传输数据的,并不会进行业务的寻址。ModelAndView 却是可以进行业务寻址的,就是设置对应的要请求的静态文件,这里的静态文件指的是类似jsp的文件。Model是每次请求中都存在的默认参数,利用其addAttribute()方法即可将服务器的值传递到jsp页面中;ModelAndView包含model和view两部分,使用时需要自己实例化,利用ModelMap用来传值,也可以设置view的名称。
2.Model是每一次请求可以自动创建,但是ModelAndView 是需要我们自己去new的。
1.Model的使用
查看Model的源码发现,里面比较重要的就是前4个。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
package org.springframework.ui; import java.util.Collection; import java.util.Map; import org.springframework.lang.Nullable; /** * Java-5-specific interface that defines a holder for model attributes. * Primarily designed for adding attributes to the model. * Allows for accessing the overall model as a {@code java.util.Map}. * * @author Juergen Hoeller * @since 2.5.1 */ public interface Model { /** * Add the supplied attribute under the supplied name. * @param attributeName the name of the model attribute (never {@code null}) * @param attributeValue the model attribute value (can be {@code null}) */ Model addAttribute(String attributeName, @Nullable Object attributeValue); /** * Add the supplied attribute to this {@code Map} using a * {@link org.springframework.core.Conventions#getVariableName generated name}. * <p><i>Note: Empty {@link java.util.Collection Collections} are not added to * the model when using this method because we cannot correctly determine * the true convention name. View code should check for {@code null} rather * than for empty collections as is already done by JSTL tags.</i> * @param attributeValue the model attribute value (never {@code null}) */ Model addAttribute(Object attributeValue); /** * Copy all attributes in the supplied {@code Collection} into this * {@code Map}, using attribute name generation for each element. * @see #addAttribute(Object) */ Model addAllAttributes(Collection<?> attributeValues); /** * Copy all attributes in the supplied {@code Map} into this {@code Map}. * @see #addAttribute(String, Object) */ Model addAllAttributes(Map<String, ?> attributes); /** * Copy all attributes in the supplied {@code Map} into this {@code Map}, * with existing objects of the same name taking precedence (i.e. not getting * replaced). */ Model mergeAttributes(Map<String, ?> attributes); /** * Does this model contain an attribute of the given name? * @param attributeName the name of the model attribute (never {@code null}) * @return whether this model contains a corresponding attribute */ boolean containsAttribute(String attributeName); /** * Return the attribute value for the given name, if any. * @param attributeName the name of the model attribute (never {@code null}) * @return the corresponding attribute value, or {@code null} if none * @since 5.2 */ @Nullable Object getAttribute(String attributeName); /** * Return the current set of model attributes as a Map. */ Map<String, Object> asMap(); } |
- Model addAttribute(String attributeName, @Nullable Object attributeValue)
- Model addAttribute(Object attributeValue);
- Model addAllAttributes(Collection<?> attributeValues);
- Model addAllAttributes(Map<String, ?> attributes);
具体用法1:返回一个字符
Controller层的写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.cat.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; /* * controller 负责提供访问应用程序的行为,通常通过接口定义或者注解定义两种方法实现。 * 控制器负责解析用户的请求并将其转换为一个模型。 * */ @Controller //代表这个类会被spring接管,被这个注解的类中所有方法,如果返回值是string,并且有具体的页面可以跳转,那么就会被视图解析器解析 public class IndexController { @RequestMapping ( "/hello" ) //意为请求 localhost:8080/hello public String hello(Model model){ //封装数据(向模型中添加数据,可以jsp页面直接取出并渲染) model.addAttribute( "name" , "张三" ); model.addAttribute( "sex" , "男" ); model.addAttribute( "age" , 23 ); System.out.println(model); //会被视图解析器处理 return "hello" ; //返回到哪个页面 } } |
jsp写法(注意和路径对应)
1
2
3
4
5
6
7
8
9
10
11
12
|
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> hello.jsp页面 <p>姓名:${name}</p> <p>性别:${sex}</p> <p>年龄:${age}</p> </body> </html> |
正常情况如下所示:
具体用法2:返回一个对象
model方法是可以返回一个对象的。我们创建一个对象
Person实体类,至少要加上get方法。不然前端取不到数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
package com.cat.domain; public class Person { public String name; public String sex; public int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", sex='" + sex + '\'' + ", age=" + age + '}'; } } |
IndexController代码改成下面这样。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package com.cat.controller; import com.cat.domain.Person; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping public class IndexController { @RequestMapping ( "/hello" ) public String hello(Model model){ Person person = new Person(); person.name= "张三" ; person.age= 16 ; person.sex= "男" ; System.out.println(person); model.addAttribute( "person" ,person); return "hello" ; } } |
hello.jsp改成下面这样子。
1
2
3
4
5
6
7
8
9
10
11
12
|
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> hello.jsp页面 <p>姓名:${person.name}</p> <p>性别:${person.sex}</p> <p>年龄:${person.age}</p> </body> </html> |
页面重新请求后变成下面样子说明请求成功
![](https://www.longkui.site/wp-content/uploads/2020/09/image-204.png)
返回map和collection类型暂时不做演示。
2.ModelAndView
ModelAndView有的方法和Model很类似,一共有下面这些方法。
构造方法:
1
2
3
4
5
6
7
|
ModelAndView() //默认构造函数豆式的用法:填充bean的属性,而不是将在构造函数中的参数。 ModelAndView(String viewName) //方便的构造时,有没有模型数据暴露。 ModelAndView(String viewName, Map model) //给出创建一个视图名称和模型新的ModelAndView。 ModelAndView(String viewName, String modelName, Object modelObject) //方便的构造采取单一的模式对象。 ModelAndView(View view) //构造方便在没有模型数据暴露。 ModelAndView(View view, Map model) //创建给定一个视图对象和模型,新的ModelAndView。 ModelAndView(View view, String modelName, Object modelObject) //方便的构造采取单一的模式对象。 |
类方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
ModelAndView addAllObjects(Map modelMap) //添加包含在所提供的地图模型中的所有条目。 ModelAndView addObject(Object modelObject) //添加对象使用的参数名称生成模型。 ModelAndView addObject(String modelName,ObjectmodelObject) //对象添加到模型中。 void clear() //清除此ModelAndView对象的状态。 Map getModel() //返回的模型图。 protectedMap getModelInternal() //返回的模型图。 ModelMap getModelMap() //返回底层ModelMap实例(从不为null)。 View getView() //返回View对象,或者为null,如果我们使用的视图名称由通过一个ViewResolverDispatcherServlet会得到解决。 String getViewName() //返回视图名称由DispatcherServlet的解决,通过一个ViewResolver,或空,如果我们使用的视图对象。 boolean hasView() //指示此与否的ModelAndView有一个观点,无论是作为一个视图名称或作为直接查看实例。 boolean isEmpty() //返回此ModelAndView对象是否为空,即是否不持有任何意见,不包含模型。 boolean isReference() //返回,我们是否使用视图的参考,i.e. void setView(Viewview) //设置此ModelAndView的视图对象。 void setViewName(StringviewName) //此ModelAndView的设置视图名称,由通过一个ViewResolverDispatcherServlet会得到解决。 String toString() //返回这个模型和视图的诊断信息。 boolean wasCleared()?? //返回此ModelAndView对象是否为空的调用的结果,以清除(),即是否不持有任何意见,不包含模型。 |
在Controller中添加一个新的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package com.cat.controller; import com.cat.domain.Person; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller @RequestMapping public class IndexController { // @RequestMapping("/hello") // public String hello(Model model){ // Person person =new Person(); // person.name="张三"; // person.age=16; // person.sex="男"; // System.out.println(person); // model.addAttribute("person",person); // return "hello"; // } @RequestMapping ( "/hello2" ) public ModelAndView hello(){ ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName( "hello" ); //返回到那个文件 modelAndView.addObject( "name" , "派大星" ); modelAndView.addObject( "sex" , "男" ); modelAndView.addObject( "age" , 53 ); System.out.println(modelAndView); return modelAndView; } } |
hello.jsp改成
1
2
3
4
5
6
7
8
9
10
11
12
|
<%@ page contentType= "text/html;charset=UTF-8" language= "java" %> <html> <head> <title>Title</title> </head> <body> hello.jsp页面 <p>姓名:${name}</p> <p>性别:${sex}</p> <p>年龄:${age}</p> </body> </html> |
请求新的地址后发现数据没有问题。
同理,ModelAndView也可以返回一个对象。这里就不做演示了。