1. 今日内容
2. SpringMVC概述
2.1 SpringMVC
1. SpringMVC是应用于表现层的框架。
2. MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写, 是一种用于设计创建 Web 应用程序表现层的模式。MVC 中每个部分各司其职:
1. Model(模型):
* 通常指的就是我们的数据模型。作用一般情况下用于封装数据。
2. View(视图):
* 通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。
3. Controller(控制器):
* 是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的,比如验证信息、跳转到哪个页面等等。
3. 优点:
清晰的角色划分:
前端控制器(DispatcherServlet)
请求到处理器映射(HandlerMapping)
处理器适配器(HandlerAdapter)
视图解析器(ViewResolver)
处理器或页面控制器(Controller)
验证器( Validator)
命令对象(Command 请求参数绑定到的对象就叫命令对象)
表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
SpringMVC 在三层架构的位置 :
2.1 SpringMVC和Struts2 的优略分析
3. SpringMVC入门案例
3.1 建立项目,并将项目结构补充完整
点击新建项目。出现如下图:
接着选择项目的生成的坐标:
上面的键值对如下:
archetypeCatalog | internal |
---|
生成的项目结构如下:
接着,将项目的结构补充完整:
最终完整的项目结构如下:
3.2 配置项目
3.2.1 在pom.xml中导入SpringMVC依赖jar包
再在dependencies
标签内导入一下依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
再在build
标签内粘贴以下代码:
<!--配置插件-->
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 项目访问路径 -->
<path>/springmvc</path>
<!-- 访问项目的端口号 -->
<port>80</port>
</configuration>
</plugin>
</plugins>
3.2.2 创建springmvc.xml文件
在springmvc.xml文件中粘贴下面的代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
再点击一下右上角的config提示。
3.2.3 在web.xml中配置核心控制器DispatcherServlet
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--解决中文乱码的问题-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 设置过滤器中的属性值 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- 启动过滤器 -->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- SpringMVC的核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 -->
<init-param>
<param-name>contextConfigLocation</param-name> <!-- 这个名字必须是contextConfigLocation -->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 配置servlet启动时加载对象 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern> <!-- / 表示拦截所有请求交给dispatcherServlet处理 -->
</servlet-mapping>
</web-app>
3.2.4 配置springmvc.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置spring创建容器时要扫描的包 -->
<context:component-scan base-package="cn.wanghao.springmvc"></context:component-scan>
<!-- 注解如何找到。 配置spring开启注解mvc的支持。注解驱动,以使得访问路径与方法的匹配可以通过注解配置 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 注解的方法返回的字符串如何找到对应的页面。 配置视图解析器 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 目录 -->
<property name="prefix" value="/WEB-INF/pages/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
3.2.5 编写控制器类
package cn.wanghao.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/hello")
public class helloController {
@RequestMapping("/sayHello")
public String sayHello(){
System.out.println("hello springMVC!!!");
return "success";
}
}
3.2.6 编写index.jsp
先将项目自动生成的index.jsp删除,再从新键一个,然后编写:
<%--
Created by IntelliJ IDEA.
User: WangHao
Date: 2020/3/21
Time: 13:47
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="hello/sayHello">springMVC入门案例</a>
</body>
</html>
3.3 案例效果
3.4 入门案例的执行流程
1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象, 就会加载springmvc.xml配置文件
2. 开启了注解扫描,那么HelloController对象就会被创建
3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 找到执行的具体方法
4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
5. Tomcat服务器渲染页面,做出响应
4. SpringMVC执行过程
1. DispatcherServlet:前端控制器
* 用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
2. HandlerMapping:处理器映射器
* HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的 映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3. HandlAdapter:处理器适配器
* 通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理 器进行执行。
4. Handler:处理器
* 它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由 Handler 对具体的用户请求进行处理。即用来执行我们编写的代码。
5. View Resolver:视图解析器
* 根据处理器返回的字符串(逻辑视图),找到该页面(物理视图)。
6. View:视图
* SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView 等。我们最常用的视图就是 jsp。
除了dispatcaherServlet
是在web.xml
配置外。其余的什么器都是其类或者自定义其继承类,在springmvc.xml
中用bean标签
实例化就构成了什么什么器,
5. SpringMVC细节
5.1 mvc:annotation-driven说明
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使用mvc:annotation-driven 自动加载 RequestMappingHandlerMapping (处理映射器)和 RequestMappingHandlerAdapter ( 处 理 适 配 器 ), 所以视图解析器需要我们自己建立。
一般开发中,我们都需要写上此标签(虽然从入门案例中看,我们不写也行,随着课程的深入,该标签还 有具体的使用场景)。
5.2 RequestMapping注解
1. 作用:用于建立url和处理请求方法之间的对应关系
2. 出现位置:
1. 类上
* 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。
2. 类的方法上
* 请求 URL 的第二级访问目录。 写的话需要以/开头。
* 举例:
@Controller
@RequestMapping("/hello")
public class helloController {
@RequestMapping("/sayHello")
public String sayHello(){
System.out.println("hello springMVC!!!");
return "success";
}
}
访问路径: 项目路径/hello/sqyHello
3. 属性: 可以点进RequestMapping类中去看
1. path:配置访问目录。
2. value:用于指定请求的 URL。它和 path 属性的作用是一样的。
3. method:用于指定请求的方式。
eg:method = {RequestMethod.POST} post请求才接受
4. params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。也可以只设置key。但是我们一般不用他做参数检验,因为不一样页面会出错。
eg :
1. params = {"accountName"},表示请求参数必须有 accountName
2. params = {"moeny!100"},表示请求参数中 money 不能是 100。
3. params = {"moeny=100"},表示请求参数中 money 必须是 100。
5. headers:用于指定限制请求消息头的条件。 没有就会报错。
eg:headers = {“accept”}
浏览器访问会在项目路径后面带上/
, 项目里面不带。
5.3 请求参数的绑定
如果在被注解的控制器类的方法中定义参数,则springMVC会自动的将前端参数映射到类的形参中。
1. 绑定的机制
* 我们都知道,表单中请求参数都是基于 key=value 的。 SpringMVC 绑定请求参数的过程是通过把表单提交请求参数,自动的转换为控制器中方法的形参的值。
* 例如:
<a href="account/findAccount?accountId=10">查询账户</a> 中参数是:accountId=10
@RequestMapping("/findAccount")
public String findAccount(Integer accountId) {
System.out.println("查询了账户。。。。"+accountId);
return "success";
}
结果: 查询了账户。。。。10
2. 支持的数据类型
1. 基本类型和 String 类型
2. 实体类(包括实体类中属性为其他的实体类)
3. 包括 List 结构和 Map 结构的集合(包括数组)
* 注意:SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求。
3. 使用要求
1. 如果是基本类型或者 String类型:
* 要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
2. 如果是实体类类型:
* 要求表单中参数名称和实体类的属性名称保持一致。并且控制器方法的参数类型是实体类 类型
* 比如:
方法的形参是:User user 且User类中有属性username、password和一个Account类型的属性acccount。Account类中有属性meney。
前端标签是:
<input type="text" name="username">
<input type="text" name="password">
<input type="text" name="acccount.meney">
3. List 结构和 Map 结构的集合:
1. 第一种:
要求集合类型的请求参数必须在 实体类 中。在表单中请求参数名称要和 实体类 中集合属性名称相同。
给 List 集合中的元素赋值,使用下标。
给 Map 集合中的元素赋值,使用键值对。
eg :
方法的形参是:User user 且User类中有属性list<Account> accounts和Map<String, Account> accountsMap。Account类中有属性meney
前端标签是:
<input type="text" name="accounts[0].meney">
<input type="text" name="accountsMap["one"].meney">
注意:请求参数的绑定对于post和get请求都可以。
5.4 自定义类型转换器
首先,需要知道springMVC会自动将前端的字符串参数转换为被注解的方法的形参类型。其实内部是使用转换器实现的。但是,在开发的过程中,我们可能遇到类型无法转换的问题,这个时候就需要我们自己来定义类型转换器,使用自己的类型转换器来转换。
比如,如果前端输入的参数是:2020-3-21
,这个就无法转换,2020/3/21
可以。报的错误如下:
接下来介绍如何自定义类型转换器 :
- 第一步:定义一个类,实现 Converter 接口,该接口有两个泛型。 该接口定义如下:
package cn.wanghao.springmvc.utils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringToDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
if (StringUtils.isEmpty(source)) {
throw new NullPointerException("请输入要转换的日期");
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = df.parse(source);
return date;
} catch (ParseException e) {
throw new RuntimeException("输入日期有误");
}
}
}
- 第二步:在 spring配置文件中配置类型转换器。
spring 配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去。
<!--配置自定义类型转换器-->
<bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<array>
<bean class="cn.wanghao.springmvc.utils.StringToDateConverter"></bean>
</array>
</property>
</bean>
- 第三步:在 annotation-driven标签中引用配置conversion-service属性
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>
这样,用户输入2020-3-21
,就能够转换了,但是如果输入2020/3/21
不能转换了。
这是因为从String
到Date
类型的转换器被我们自己写的从String
到Date
类型的转换器覆盖了。
5.5 使用 ServletAPI 对象作为方法参数
SpringMVC 还支持使用原始 ServletAPI 对象作为控制器方法的参数。支持原始 ServletAPI 对象有:
HttpServletRequest
HttpServletResponse
HttpSession
java.security.Principal
Locale
InputStream
OutputStream
Reader
Writer
我们可以把上述对象,直接写在控制的方法参数中使用。
例如:
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
System.out.println(request);
System.out.println(response);
System.out.println(session);
return "success";
}
6. 常用注解
6.1 @RequestParam()
1. 作用:
1. 为前端传来的参数取别名
2. 之前如果前端传的参数个数不等于关于前端参数的形参个数,不会报错。所以required属性没多大用。
现在可以通过required属性设置,不是必须的,那么缺少就不会报错。
2. 属性:
1. value:请求参数中的名称。
2. required:请求参数中是否必须提供此参数。默认值:true可以不写。表示必须提供,如果不提供将报错。
注意:@RequestParam Map<String, Object> map 可以获取所有的参数,以键值对的形式存放在map中。
例子:
6.2 @ RequestBody
1. 作用:
用于获取请求体内容。直接使用得到是 key=value&key=value...字符串结构的数据。
get 请求方式不适用。
2. 属性:
* required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值 为 false,get 请求得到是 null。
注意:@RequestBody Map<String, Object> map 可以获取所有的请求体中的参数,以键值对的形式存放在map中。
案例:
如果要将请求体中的参数封装成Map结构,可以这样写:
public String useRequestBody(@RequestBody(required = false) Map<String, Object> param){ }
6.3 @PathVaribale
1. 作用:用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。 url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
2. 属性:
1. value:用于指定 url 中占位符名称。
2. required:是否必须提供占位符。
6.4 @RequestHeader()
1. 作用:
* 用于获取消息头。
2. 属性:
1. value:提供消息头名称
2. required:是否必须有此消息头
注意:在实际开发中一般不怎么用。
注意:@RequestHeader Map<String, Object> map 可以获取所有的请求头中的参数,以键值对的形式存放在map中。
例子:
6.5 @CookieValue()
1. 作用:
* 指定要获取的cookie的名称,从而获取该cookie的值
2. 属性:
1. value:指定 cookie 的名称
2. required:是否必须有此 cookie。
注意:要获取所有的cookie目前不能通过注释,要先获取原生servlet的reques,再用request.getCookies();
例子:
6.6 @ ModelAttribute
1. 作用:
1. 出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。如果该方法有返回值,则
2. 出现在参数上,获取指定的数据给参数赋值。
* 注意:@ModelAttribute最主要的作用是将数据添加到模型对象中,用于视图页面展示时使用。
2. 属性:
value:用于获取数据的 key。
@ ModelAttribute(value = "one") 修饰在方法上,是设置值
@ ModelAttribute(value = "one") 修饰在参数上,是取值
3. 应用场景:
* 当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
* 例如:
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数 据是肯定没有此字段的内容,
一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。
@ModelAttribute最主要的作用是将数据添加到模型对象中,用于视图页面展示时使用。
@ModelAttribute等价于 model.addAttribute(“attributeName”, abc); 但是根据@ModelAttribute注释的位置不同,和其他注解组合使用,致使含义有所不同。具体区别如下:
6.6.1 @ModelAttribute注释方法
例子(1),(2),(3)类似,但是(3)这种形式用的最多。被@ModelAttribute注释的方法会在此controller每个方法执行前被执行,因此对于一个controller映射多个URL的用法来说,要谨慎使用。
Mode可以理解为jsp这种展示页面。
(1)@ModelAttribute注释void返回值的方法
@Controller
public class HelloWorldController {
@ModelAttribute
public void populateModel(@RequestParam String abc, Model model) {
model.addAttribute("attributeName", abc);
}
@RequestMapping(value = "/helloWorld")
public String helloWorld(@ModelAttribute("attributeName") String str) {
System.out.println(str);
return "helloWorld";
}
}
这个例子,在获得请求/helloWorld 后,populateModel方法在helloWorld方法之前先被调用,它把abc
加入到一个名为attributeName的model属性中,在它执行后 helloWorld被调用,可以使用@ModelAttribute(value = “attributeName”)将数据拿出来。helloWorld被调用后返回视图名helloWorld和model已由@ModelAttribute方法生产好了。
这个例子中model属性名称和model属性对象有model.addAttribute()实现,不过前提是要在方法中加入一个Model类型的参数。
当URL或者post中不包含次参数时,会报错,其实不需要这个方法,完全可以把请求的方法写成,这样缺少此参数也不会出错
@RequestMapping(value = "/helloWorld")
public String helloWorld(String abc) {
return "helloWorld";
}
(2)@ModelAttribute注释返回具体类的方法
@ModelAttribute
public Account addAccount(@RequestParam String number) {
return accountManager.findAccount(number);
}
这种情况,model属性的名称没有指定,它由返回类型隐含表示,如这个方法返回Account类型,那么这个model属性的名称是account。
(3)@ModelAttribute(value="")注释返回具体类的方法
@Controller
public class HelloWorldController {
@ModelAttribute("attributeName")
public String addAccount(@RequestParam String abc) {
return abc;
}
@RequestMapping(value = "/helloWorld")
public String helloWorld() {
return "helloWorld";
}
}
这个例子中使用@ModelAttribute注释的value属性,来指定model属性的名称。model的attributeName属性的值就是方法的返回值。它无须要特定的参数。
(4)@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。
6.6.2 @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属性。
此时如果方法体没有标注@SessionAttributes(“user”),那么scope为request,如果标注了,那么scope为session
6.6.3 @ModelAttribute应用的例子
背景需求如下,当更新一个对象时,某个字段比如密码不能被修改。
常见解决思路有二:
① new 一个对象,form表单中密码域为隐藏域,该种方法有风险。
② new 一个对象,在更新的时候再次从数据库查询密码从而进行更新,该方法比较麻烦。
SpringMVC的解决思路:使用@ModelAttribute !
/该方法模拟根据id从数据库获取对象。
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false) Integer id, Map<String, Object> map){
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]
6.7 补充说明Model
对于@RequestMapping
和@ModelAttribute
注解的方法,方法里面可以写形参Model model
,这个model
代表是是request域对象
, 可以通过model.addAttribute()
来添加属性以及属性值。
@ModelAttribute
注解的方法返回值最终也是存放在Model
中。
Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap,该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类。
因此,对于@RequestMapping
和@ModelAttribute
注解的方法,方法里面可以写形参Model model
或者ModelMap modelMap
或者Map<String, Object> map
。
比如:
@Controller
public class HelloWorldController {
@ModelAttribute
public void populateModel(@RequestParam String abc, Model model) {
model.addAttribute("attributeName", abc);
}
@RequestMapping(value = "/helloWorld")
public String helloWorld(@ModelAttribute("attributeName") String str) {
System.out.println(str);
return "helloWorld";
}
}
等价于:
@Controller
public class HelloWorldController {
@ModelAttribute
public void populateModel(@RequestParam String abc, ModelMap modelMap) {
modelMap.addAttribute("attributeName", abc);
}
@RequestMapping(value = "/helloWorld")
public String helloWorld(@ModelAttribute("attributeName") String str) {
System.out.println(str);
return "helloWorld";
}
}
等价于
@Controller
public class HelloWorldController {
@ModelAttribute
public void populateModel(@RequestParam String abc, Map<String, Object> map) {
map.put("attributeName", abc);
}
@RequestMapping(value = "/helloWorld")
public String helloWorld(@ModelAttribute("attributeName") String str) {
System.out.println(str);
return "helloWorld";
}
}
另外,Model
类无法进行取值,如果在控制器中取出Model
的属性值,可以用其子类,ModelMap
, 用modelMap.get()
获取。
建议:
- 使用
ModelMap
,少使用Model 和 Map
。 - 取值的时候用
@ModelAttribute
或者ModelMap
6.8 @SessionAttribute
1. 作用:
* 用于多次执行控制器方法间的参数共享。 即多次请求间共享参数。
2. 位置:
* 只能注解于类上
3. 属性:
1. value:用于指定存入的属性名称
2. type:用于指定存入的数据类型。
* 说明:value一般为model(request)中的key,他会将model中的这个键值对复制到session域对象中,在jsp页面中使用。
* 清空session域的键值对:
方法参数用SessionStatus, 用 sessionStatus.setComplete(); 清空
案例: