SpringMVC简介
什么是MVC
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分
- M:Model,模型层,指工程中的JavaBean,作用是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据和对数据的处理JavaBean分为两类:
- 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
- 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
- V:View,视图层,是应用程序中处理数据的显示部分(比如工程中的html或jsp等页面),作用是与用户进行交互,展示数据 通常视图是依据模型数据创建的。
- C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器,是应用程序中处理用户交互的部分
- MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收
- Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller
- Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器
什么是SpringMVC
官方的描述
Spring Web MVC is the original web framework built on the Servlet API and has beenincluded in the Spring Framework from the very beginning. The formal name, “Spring WebMVC,” comes from the name of its source module (spring-webmvc), but it is more commonlyknown as “Spring MVC”.
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来自其源模块的名称(Spring-webmvc),但它通常被称为“SpringMVC”
从上述定义我们可以得出两个关键信息:
- Spring MVC 是一个 Web 框架。
- Spring MVC 是基于 Servlet API 构建的
SpringMVC是Spring的一个后续产品,是Spring的一个子项目
-
SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了
SpringMVC 作为 Java EE 项目表示层开发的首选方案。
-
业务逻辑层普遍选择SpringFramework,因为它强大的IOC容器功能为基础,能轻松整合其他框架
-
数据访问层可以选择Mybatis框架
三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为:界面层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data access layer)。区分层次的目的即为了“[高内聚低耦合]的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。微软推荐的分层式结构一般分为三层,从下至上分别为:数据访问层、业务逻辑层(又或称为领域层)、表示层(表述层表示前台页面和后台servlet )。
MVC与三层架构的区别和联系
SpringMVC的特点
- Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
- 基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
- 代码清新简洁,大幅度提升开发效率
- 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
- 性能卓著,尤其适合现代大型、超大型互联网项目要求
SpringMVC入门案例
创建maven工程
设置打包方式为war包
<packaging>war</packaging>
导入对应的依赖
<dependencies>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
注:由于 Maven 的传递性,我们不必将所有需要的包全部配置依赖,而是配置最顶端的依赖,其他靠传递性导入。
配置web.xml
注册SpringMVC的前端控制器DispatcherServlet
默认配置方式
此配置作用下,SpringMVC的配置文件默认位于WEB-INF下,默认名称为<servlet-name>-servlet.xml
,例如,以下配置所对应SpringMVC的配置文件位于WEB-INF下,文件名为SpringMVCservlet.xml
<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!--
设置springMVC的核心控制器所能处理的请求的请求路径
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径
但是/不能匹配.jsp请求路径的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
扩展配置方式
可通过init-param标签设置SpringMVC配置文件的位置和名称,通过load-on-startup标签设置SpringMVC前端控制器DispatcherServlet的初始化时间
<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servletclass>
<!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
<init-param>
<!-- contextConfigLocation为固定值 -->
<param-name>contextConfigLocation</param-name>
<!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的src/main/resources -->
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!--
作为框架的核心组件,在启动过程中有大量的初始化操作要做
而这些操作放在第一次请求时才执行会严重影响访问速度
因此需要通过此标签将启动控制DispatcherServlet的初始化时间提前到服务器启动时
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<!--
设置springMVC的核心控制器所能处理的请求的请求路径
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径
但是/不能匹配.jsp请求路径的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<url-pattern>
标签中使用/和/*的区别:- / 所匹配的请求可以是/login或.html或.js或.css方式的请求路径,但是/不能匹配.jsp请求路径的请求
- 因此就可以避免在访问jsp页面时,该请求被DispatcherServlet处理,从而找不到相应的页面
/*
则能够匹配所有请求,例如在使用过滤器时,若需要对所有请求进行过滤,就需要使用/*的写法
创建请求控制器
@Controller
public class HelloWorldController {
}
由于前端控制器(本质是一个Servlet)对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器中每一个处理请求的方法成为控制器方法
- 因为SpringMVC的控制器由一个POJO(普通的Java类)担任,因此需要通过@Controller注解将其标识为一个控制层组件,交给Spring的IoC容器管理,此时SpringMVC才能够识别控制器的存在
创建SpringMVC的配置文件
对应web.xml配置发不同分为默认配置方式和拓展配置方式
<!-- 自动扫描包 -->
<context:component-scan base-package="com.lsc.springmvc.controller"/>
<!-- 配置Thymeleaf视图解析器 -->
<bean id="viewResolver"
class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean
class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
<mvc:default-servlet-handler/>
<!-- 开启mvc注解驱动 -->
<mvc:annotation-driven>
<mvc:message-converters>
<!-- 处理响应中文内容乱码 -->
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="UTF-8" />
<property name="supportedMediaTypes">
<list>
<value>text/html</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
测试
@Controller
public class HelloWorldController {
@RequestMapping("/")
public String index(){
return "index";
}
@RequestMapping("/hello")
public String target(){
return "target";//通过DispatchServlet控制经过thymeleaf的转发和渲染,到达我们的对应的资源
}
}
- @RequestMapping注解:处理请求和控制器方法之间的映射关系
- @RequestMapping注解的value属性可以通过请求地址匹配请求,/表示的当前工程的上下文路径 localhost:8080/springMVC/
- 因为我们这个/是在服务器进行解析的,/解析为web应用的根目录(服务器根目录+应用程序上下文路径)
- @RequestMapping注解的value属性可以通过请求地址匹配请求,/表示的当前工程的上下文路径 localhost:8080/springMVC/
对应index的html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
<a th:href="@{/hello}">HelloWorld</a><br/>
<a href="/hello">HelloWorld</a>
</body>
</html>
- 因为超链接是我们的浏览器进行解析,解析为我们的服务器的根目录
- 而我们thymeleaf的@{}能够自动帮我们获得我们的应用程序上下文的路径,也就是/springmvc
总结
- 浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理
- 前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法
- 处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面
RequestMapping注解
@RequestMapping注解的功能
- 从上面的案例中我们能看出来,@RequestMapping注解的作用就是将浏览器发送的请求和处理请求的控制器方法关联起来,建立映射关系,SpringMVC接收到指定的请求,就会来找到映射关系中对应的控制器方法来解决这个请求
@RequestMapping注解的位置
- RequestMapping标注在类上面,设置映射请求的请求路径的初始信息
- RequestMapping标注在方法上面,设置映射请求请求路径的具体信息
@Controller
@RequestMapping("/demo1")
public class demo1 {
//此时请求映射所映射的请求的请求路径为:/demo1/index1
@RequestMapping("/index1")
public String index1(){
return "index";
}
//此时请求映射所映射的请求的请求路径为:/demo1/index2
@RequestMapping("/index2")
public String index2(){
return "index";
}
}
@RequestMapping注解的value属性
- @RequestMapping注解的value属性通过请求的请求地址匹配请求映射
- @RequestMapping注解的value属性是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求
- @RequestMapping注解的value属性必须设置,至少通过请求地址匹配请求映射
前端页面
<a th:href="@{/test1}">测试@RequestMapping的value属性</a><br>
<a th:href="@{/test2}">测试@RequestMapping的value属性</a><br>
@Controller
public class demo1 {
@RequestMapping(
value = {"test1","test2"}
)
public String test(){
return "test";
}
- 通过/test1或者test2的请求路径都能访问到对应的test方法上
@RequestMapping注解的method属性
- @RequestMapping注解的method属性通过请求的请求方式(get或post)匹配请求映射
- 我们的http协议有很多种请求方式,get和post比较常用
- @RequestMapping注解的method属性是一个RequestMethod类型的数组,表示该请求映射能够匹配多种请求方式的请求
- 若当前请求的请求地址满足请求映射的value属性,但是请求方式不满足method属性,则浏览器报错405:Request method ‘POST’ not supported
前端页面
<a th:href="@{/test}">测试@RequestMapping的method属性之通过get请求方法</a><br>
<form th:action="@{/test}" method="post">
<input type="submit" value="测试@RequestMapping的method属性之通过post请求方法"></input>
</form>
@RequestMapping(
value = "test",
method = {RequestMethod.GET,RequestMethod.POST}
)
public String test(){
return "test";
}
对于处理指定请求方式的控制器方法,SpringMVC派生出来对应的注解
- 处理get请求的映射–>@GetMapping
- 处理post请求的映射–>@PostMapping
- 处理put请求的映射–>@PutMapping
- 处理delete请求的映射–>@DeleteMapping
@PostMapping("test1")
public String test1(){
return "test";
}
- 这样只能处理post的http请求
@RequestMapping注解的params属性
-
@RequestMapping注解的params属性通过请求的请求参数匹配请求映射
-
@RequestMapping注解的params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系
-
“param”:要求请求映射所匹配的请求必须携带param请求参数
-
“!param”:要求请求映射所匹配的请求必须不能携带param请求参数
-
“param=value”:要求请求映射所匹配的请求必须携带param请求参数且param=value
-
“param!=value”:要求请求映射所匹配的请求必须携带param请求参数但是param!=value
-
@RequestMapping(
value = {"test1","test2"},
method = {RequestMethod.GET,RequestMethod.POST},
params = {"username","password!=123","!gender","age=22"}
)
public String test(){
return "test";
}
注:若当前请求满足@RequestMapping注解的value和method属性,但是不满足params属性,此时页面回报错
- HTTP Status 400 - Parameter conditions “username, password!=123, !gender, age=22” not met for actual request parameters: username={lsc}, password={123456}, age={2}
@RequestMapping注解的headers属性
@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射
@RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系
- “header”:要求请求映射所匹配的请求必须携带header请求头信息
- “!header”:要求请求映射所匹配的请求必须不能携带header请求头信息
- “header=value”:要求请求映射所匹配的请求必须携带header请求头信息且header=value
- “header!=value”:要求请求映射所匹配的请求必须携带header请求头信息且header!=value
@RequestMapping(
value = {"test1","test2"},
method = {RequestMethod.GET,RequestMethod.POST},
headers = {"referer"}
)
public String test(){
return "test";
}
- 若当前请求满足@RequestMapping注解的value和method属性,但是不满足headers属性,此时页面显示404错误,即资源未找到
- referer是请求头中的一个属性,表示从那个其他页面跳转过来
SpringMVC支持ant风格的路径
- ?:表示任意的单个字符
- *:表示任意的0个或多个字符
- **:表示任意层数的任意目录
- 注意:在使用
**
时,只能使用/**/xxx的方式
@RequestMapping(
value = "ant?",
method = {RequestMethod.GET,RequestMethod.POST}
)
public String ant(){
return "test";
}
- 可以使用/ant1,/ant2,都是可以正常的进行访问,但是/ant11不能正常访问
- 但是不包括?
@RequestMapping(
value = "ant*",
method = {RequestMethod.GET,RequestMethod.POST}
)
public String ant(){
return "test";
}
- 可以使用/ant,/ant1,/ant2,/ant33都可以正常访问
- 但是不包括?和/
@RequestMapping(
value = "**/ant",
method = {RequestMethod.GET,RequestMethod.POST}
)
public String ant(){
return "test";
}
- 可以使用/a1/ant, /a1/a2/ant 都可以正常的访问
- 注意使用方式只能**写在双斜线中,前后不能有任何的其他字符
SpringMVC支持路径中的占位符
- 原始方式:/deleteUser?id=1
- rest方式:/user/delete/1
SpringMVC路径中的占位符常用于RESTful风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping注解的value属性中通过占位符{xxx}表示传输的数据,在通过@PathVariable注解,将占位符所表示的数据赋值给控制器方法的形参
@RequestMapping(
value = "/rest/{username}/{pwd}/test",
method = {RequestMethod.GET,RequestMethod.POST}
)
public String rest(@PathVariable String username,@PathVariable("pwd") String password){
System.out.println("username="+username);
System.out.println("password="+password);
return "test";
}
// 通过http://localhost:8080/springmvc/rest/lsc/123456/test进行访问
//输出结果
username=lsc
password=123456
SpringMVC获取请求参数
获取请求参数
通过servlet的原生API进行获取
对应前端的超链接
<a th:href="@{/param/servletAPI?username=lsc&password=123456}">测试通过原生ServletAPI来获得参数</a>
@Controller
@RequestMapping("param")
public class GetParamTest {
@RequestMapping("/servletAPI")
public String getParamByServletAPI(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "test";
}
}
//输出结果
username:lsc,password:123456
- 虽然可以通过原生的ServletAPI来获得对应的请求参数,但是我们是SpringMVC是在原生的Servlet上进行封装,所以肯定有更简单的方法进行获取
通过控制器方法的形参获取请求参数
在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参
前端对应的超链接
<a th:href="@{/param/servletAPI?username=lsc&password=123456}">测试通过控制器方法的形参获取请求参数</a>
@Controller
@RequestMapping("param")
public class GetParamTest {
@RequestMapping("/testParam")
public String testParam(String username, String password){
System.out.println("username:"+username+",password:"+password);
return "test";
}
}
//输出结果
username:lsc,password:123456
- 若请求所传输的请求参数中
有多个同名的请求参数
,此时可以在控制器方法的形参中设置字符串数组或者字符串类型的形参接收此请求参数- 若使用字符串数组类型的形参,此参数的数组中包含了每一个数据
- 若使用字符串类型的形参,此参数的值为每个数据中间使用逗号拼接的结果
@Controller
@RequestMapping("param")
public class GetParamTest {
@RequestMapping("/servletAPI")
public String getParamByServletAPI(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "test";
}
@RequestMapping("/testParam")
public String testParam(String username, String password){
System.out.println("username:"+username);
System.out.println("password:"+password);
return "test";
}
}
//<a th:href="@{/param/testParam?username=lsc&username=lkx&password=123456}"></a><br>
//输出结果
username:lsc,lkx
password:123456
@RequestMapping("/testParam")
public String testParam(String username[], String password){
for (int i = 0; i < username.length; i++) {
System.out.println("username="+i+username[i]);
}
System.out.println("password:"+password);
return "test";
}
//<a th:href="@{/param/testParam?username=lsc&username=lkx&password=123456}"></a><br>
//输出结果
username0=lsc
username1=lkx
password:123456
@RequestParam
- @RequestParam是将请求参数和控制器方法的形参创建映射关系
- @RequestParam注解一共有三个属性:
- value:指定为形参赋值的请求参数的参数名
- required:设置是否必须传输此请求参数,默认值为true
- 若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter ‘xxx’ is not present
- 若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null;
- defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为""时,则使用默认值为形参赋值
@Controller
@RequestMapping("param")
public class GetParamTest {
@RequestMapping("testRequestParam")
public String testRequestParam(
@RequestParam(value = "username",required = true,defaultValue = "lkx") String userName
){
System.out.println("userName="+userName);
return "test";
}
}
<!--对应的超链接-->
<a th:href="@{/param/testRequestParam?username=lsc}">测试RequestParam</a>
<!--输出结果-->
userName=lsc
<!--对应的超链接-->
<a th:href="@{/param/testRequestParam}">测试RequestParam</a>
<!--输出结果-->
userName=lkx
通过POJO获取请求参数
可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值
对应的POJO对象
public class User {
private String username;
private String password;
private Integer age;
private String gender;
//还有对应属性的setter getter toString方法
}
前端提交表单
<form th:action="@{/param/testpojo}" method="post">
用户名:<input type="text" name="username" value="lsc"><br>
密码:<input type="password" name="password" value="123456"><br>
性别:<input type="radio" name="gender" value="man">男
<input type="radio" name="gender" value="woman">女<br>
年龄:<input type="text" name="age" value="22"><br>
<input type="submit">
</form>
@Controller
@RequestMapping("param")
public class GetParamTest {
@RequestMapping("/testpojo")
public String testPojo(User user){
System.out.println(user);
return "test";
}
}
//输出结果
User{username='lkx', password='123456', age=22, gender='woman'}
获取请求头参数
@RequestHeader
- @RequestHeader是将请求头信息和控制器方法的形参创建映射关系
- @RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
@Controller
@RequestMapping("param")
public class GetParamTest {
@RequestMapping("testRequestHeader")
public String testRequestHeader(
@RequestHeader(value="referer",required = true,defaultValue ="直接访问,没有通过跳转") String referer
){
System.out.println("referer="+referer);
return "test";
}
}
获取对应的Cookie数据
- 之前我们原生的API获取Cookie,只能一次获取全部的Cookie,然后通过getName获取对应Cookie的键,再通过name获取对应的值
@CookieValue
@CookieValue是将cookie数据和控制器方法的形参创建映射关系
@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
在访问index时设置对应的Cookie
@Controller
public class demo1 {
@RequestMapping("/index")
public String index1(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession();
Cookie cookie1=new Cookie("OneCookie","cookie1");
response.addCookie(cookie1);
return "index";
}
}
index对应的超链接
<a th:href="@{/param/testCookieValue}">测试CookieValue</a>
@Controller
@RequestMapping("param")
public class GetParamTest {
@RequestMapping("testCookieValue")
public String testCookieValue(
@CookieValue(value ="OneCookie",required = true,defaultValue = "不存在对应的Cookie")String cookie){
System.out.println("OneCookie="+cookie);
return "test";
}
}
//通过index点击超链接进行访问
//输出结果
OneCookie=cookie1
//直接通过浏览器访问
//输出结果
OneCookie=不存在对应的Cookie
域对象共享数据
对于SpringMVC有三种域,请求域,会话域,应用域,关于详细信息,参考JavaWeb下的第七章Servlet的知识
向request域共享数据
使用ServletAPI向request域对象共享数据
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request){
request.setAttribute("testScope", "hello,servletAPI");
return "test";
}
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
/**
* ModelAndView有Model和View的功能
* Model用于向请求域共享数据
* View主要用于设置视图,实现页面跳转
*/
ModelAndView mav = new ModelAndView();
//向请求域共享数据
mav.addObject("testScope", "hello,ModelAndView");
//设置视图,实现页面跳转
mav.setViewName("test");
return mav;
}
- 注意返回参数的变化,对于使用了ModelAndView,我们的方法返回值值必须是ModelAndViem,不然没有对应的效果
- 使用Model向请求域共享数据,也只能是请求域
- 使用View功能设置逻辑视图,但是控制器方法一定要将ModelAndView作为方法的返回值
- 我们的SpringMVC的DispatchServlet的返回值就是ModeAndViem
使用Model向request域对象共享数据
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testScope", "hello,Model");
return "test";
}
使用map向request域对象共享数据
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
map.put("testScope", "hello,Map");
return "test";
}
使用ModelMap向request域对象共享数据
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testScope", "hello,ModelMap");
return "test";
}
Model、ModelMap、Map的关系
- Model、ModelMap、Map类型的参数其实在底层中,这些类型的形参最终都是通过BindingAwareModelMap创建
public class BindingAwareModelMap extends ExtendedModelMap {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class ModelMap extends LinkedHashMap<String, Object> {}
// LinkedHashMap<String, Object>实现了Map接口
public interface Model{}
- BindingAwareModelMap可以向上转型变成对应的Model,ModelMap,Map类型
向session域共享数据
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSessionScope", "hello,session");
return "test";
}
向application域共享数据
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
ServletContext application = session.getServletContext();
application.setAttribute("testApplicationScope", "hello,application");
return "test";
}
解决获取请求参数的乱码问题
解决获取请求参数的乱码问题,可以使用SpringMVC提供的编码过滤器CharacterEncodingFilter,但是必须在web.xml中进行注册
<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中处理编码的过滤器一定要配置到其他过滤器之前,否则无效
- 而且我们的关于编码的处理必须要在SpringMVC处理request之前
SpringMVC的视图
- SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户
- SpringMVC视图的种类很多,默认有转发视图和重定向视图
- 当工程引入jstl的依赖,转发视图会自动转换为JstlView,若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视
图解析器解析之后所得到的是ThymeleafView
ThymeleafView
当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀
和视图 后缀
所得到的最终路径,会通过转发的方式实现跳转
@Controller
@RequestMapping("/test/view")
public class viewController {
@GetMapping("/thymeleaf")
public String thymeleafViewTest(){
System.out.println("测试ThymeleafView");
return "index";
}
}
转发视图
- SpringMVC中默认的转发视图是
InternalResourceView
- SpringMVC中创建转发视图的情况:
- 当控制器方法中所设置的视图名称以"forward:"为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"forward:"去掉,剩余部分作为最终路径通过转发的方式实现跳转
- 例如"forward:/",“forward:/employee”
- 当控制器方法中所设置的视图名称以"forward:"为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"forward:"去掉,剩余部分作为最终路径通过转发的方式实现跳转
@Controller
@RequestMapping("/test/view")
public class viewController {@GetMapping("forward")
public String forwardViewTest(){
System.out.println("测试forward");
return "forward:/success.html";
}
}
重定向视图
- SpringMVC中默认的重定向视图是
RedirectView
- 当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:"去掉,剩余部分作为最终路径通过重定向的方式实现跳转
- 例如"redirect:/",“redirect:/employee”
- 当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:"去掉,剩余部分作为最终路径通过重定向的方式实现跳转
@Controller
@RequestMapping("/test/view")
public class viewController {
@GetMapping("redirect")
public String redirectViewTest(){
System.out.println("测试redirect");
return "redirect:/success.html";
}
}
重定向视图在解析时,会先将redirect:前缀去掉,然后会判断剩余部分是否以/开头,若是则会自动拼接上下文路径
- 对于重定向,我们的浏览器的url会变化
- 从
http://localhost:8080/springmvc/test/view/redirect
- 变成
http://localhost:8080/springmvc/success.html
视图控制器view-controller
当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用viewcontroller标签进行表示
<!--
path:设置处理的请求地址
view-name:设置请求地址所对应的视图名称
-->
<mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>
当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:<mvc:annotation-driven />