目录
- 第一章 SpringMVC的概述
- 第二章 SpringMVC的原理
- 第三章 SpringMVC的入门
-
- 3.1、项目创建
- 3.2、环境准备
- 第四章 SpringMVC的控制器对象
- 第五章 SpringMVC的请求映射
-
- 5.1、位置
- 5.2、属性
-
- 5.2.1、value
- 5.2.2、method
- 5.2.3、params
- 5.2.4、headers
- 5.2.5、consumes
- 5.2.6、produces
- 第六章 SpringMVC的控制器方法
-
- 6.1、控制器方法的参数
-
- 6.1.1、接收单个参数
- 6.1.2、接收多个参数
- 6.1.3、接收对象数据类型
- 6.1.4、接收集合数据类型
-
- 6.1.4.1、array数组
- 6.1.4.2、list集合
- 6.1.4.3、set集合
- 6.1.4.4、map集合
- 6.1.5、接收请求头的参数
-
- 6.1.5.1、获取指定请求头
- 6.1.5.2、获取所有请求头
- 6.1.6、接收Cookie的参数
- 6.1.7、接收矩阵变量参数
- 6.1.8、解决中文乱码问题
- 6.2、控制器方法的返回值
-
- 6.2.1、返回值为 ModeAndView
- 6.2.2、返回值为 String
- 6.2.3、返回值为 Void
- 6.2.4、返回值为 Object
- 第七章 SpringMVC的页面跳转
-
- 7.1、请求转发
- 7.2、重定向
- 第八章 SpringMVC的拦截器
-
- 8.1、拦截器概述
- 8.2、拦截器定义
- 8.3、拦截器注册
- 8.4、单个拦截器执行顺序
- 8.5、多个拦截器执行顺序
- 第九章 SpringMVC的国际化
- 第十章 SpringMVC的异常处理
-
- 10.1、异常处理概述
- 10.2、自定义异常类
- 10.3、定义全局异常处理
- 10.4、定义全局错误页面
- 10.5、配置组件扫描异常
- 10.6、定义错误方法测试
- 第十一章 SpringMVC的文件上传
- 第十二章 SpringMVC的跨域解决
- 第十三章 SpringMVC的细节处理
-
- 13.1、提交表单中有日期
- 13.2、返回数据中有日期
- 13.3、视图快捷导航标签
- 13.4、url-pattern的写法
配套资料,免费下载
链接:https://pan.baidu.com/s/14AOFoYKdu-QDAFf_3GvwqQ
提取码:7hqi
复制这段内容后打开百度网盘手机App,操作更方便哦
第一章 SpringMVC的概述
三层架构
三层架构的介绍:
我们的开发架构一般都是基于两种形式,一种是C/S架构,也就是客户端/服务器,另一种是B/S架构,也就是浏览器/服务器。在JavaEE开发中,几乎全都是基于B/S架构的开发。那么在B/S架构中,系统标准的三层架构包括:用户界面层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data access layer)。区分层次的目的就是为了解除各个模块之间的耦合关系,提高代码复用性。
三层架构的优势:
- 结构清晰,耦合度低
- 可维护性高,可扩展性高
- 利于开发任务同步进行,容易适应需求变化
三层架构的劣势:
- 降低了系统的性能
- 有时会导致级联的修改
- 增加了代码量,增加了工作量
各层之间的方案:
- 用户界面层: Spring MVC、Struts 2
- 业务逻辑层: Spring
- 数据访问层: Hibernate、MyBatis、JdbcTemplate
MVC
MVC最开始是存在于桌面程序中的,全名是Model View Controller,是数据模型(model)-用户界面(view)-控制器(controller)的缩写,它是一种软件设计模式。使用MVC的目的在于将M(数据模型)和V(用户界面)的实现代码分离,从而使同一个程序可以使用不同的表现形式。C(控制器)存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
我用Windows的计算器小程序为例,解释一下MVC模式,虽然它不一定使用这个模式编写。
在这个计算器程序中,外部的那些按钮和最上面的显示条,就是"视图层",那些需要运算的数字就是"数据层",执行加减乘除的那些内部运算步骤就是"控制层",每一层执行不同的功能,整个程序的结构非常清楚。
Spring MVC
“ Spring Web MVC”通常简称为“ Spring MVC”,他是基于Servlet API构建的原始Web框架,从一开始就已包含在Spring框架中,专门是做Web 开发的,Spring MVC内部也维护了一个容器,被称为Spring MVC容器,他是IOC容器的一个子类,既然是子类,Spring MVC容器是可以访问IOC中管理的对象的。
第二章 SpringMVC的原理
请求流程:
父子容器:
第三章 SpringMVC的入门
3.1、项目创建
修改 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"></web-app>
修改 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.caochenlei</groupId><artifactId>springmvc-demo-01</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include><include>**/*.conf</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include><include>**/*.conf</include></includes><filtering>false</filtering></resource></resources></build>
</project>
3.2、环境准备
导入依赖:
<!--导入SpringMVC依赖-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.2</version>
</dependency>
<!--导入JSON处理工具包-->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.12.0</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.0</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.12.0</version>
</dependency>
<!--Servlet、JSP相关依赖-->
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope>
</dependency>
<dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.3</version><scope>provided</scope>
</dependency>
<!--JSP相关标签依赖-->
<dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version>
</dependency>
<dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version>
</dependency>
创建容器:
<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-ioc.xml</param-value>
</context-param><servlet><servlet-name>spring-mvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>spring-mvc</servlet-name><url-pattern>/*.do</url-pattern>
</servlet-mapping>
添加类包:
- com.caocheneli.spring5.pojo
- com.caocheneli.spring5.dao
- com.caocheneli.spring5.service
- com.caocheneli.spring5.controller
添加配置: spring-ioc.xml
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
<!--开启组件扫描-->
<context:component-scan base-package="com.caocheneli.spring5"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
添加配置: spring-mvc.xml
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
<!--开启组件扫描-->
<context:component-scan base-package="com.caocheneli.spring5.controller"></context:component-scan>
创建控制器: HelloController
@Controller
public class HelloController {
@RequestMapping("/hello.do")public void hello() {
System.out.println("Hello SpringMVC");}
}
打开浏览器: http://localhost:8080/hello.do
打开控制台:
第四章 SpringMVC的控制器对象
Spring MVC提供了一个基于注解的编程模型,使用 @Controller
组件来标识当前类为控制器类。
@Controller
public class HelloController {
@RequestMapping("/hello.do")public void hello() {
System.out.println("Hello SpringMVC");}
}
第五章 SpringMVC的请求映射
@RequestMapping
是一个用来处理请求地址映射的注解,可用于类或方法上。
5.1、位置
用在控制器类上面: 表示类中的所有响应请求的方法都是以该地址作为父路径
@Controller
@RequestMapping("/hello")
public class HelloController {
}
用在控制器方法上: 提供进一步的细分映射信息,他跟控制器类上的请求路径组成一个完整的请求路径,如果类上没有使用 @RequestMapping
注解,则父路径就是为空("")。
@Controller
@RequestMapping("/hello")
public class HelloController {
//完整请求地址:localhost:8080/hello/world.do@RequestMapping("/world.do")public void world() {
System.out.println("Hello World");}//完整请求地址:localhost:8080/hello/spring.do@RequestMapping("/spring.do")public void spring() {
System.out.println("Hello Spring");}
}
5.2、属性
5.2.1、value
说明: 指定请求的实际地址。
示例:
第一种形式: 单个请求地址
@RequestMapping(value = "/world.do")
public void todo1() {
System.out.println("Hello World");
}
第二种形式: 多个请求地址
@RequestMapping(value = {
"/world.do","/spring.do","/mybatis.do"
})
public void todo2() {
System.out.println("Hello World");System.out.println("Hello Spring");System.out.println("Hello MyBatis");
}
第三种形式: 地址路径含有变量
@RequestMapping(value = "/spring/{content}.do")
public void todo2(@PathVariable String content) {
System.out.println("Hello Spring " + content);
}
第四种形式: 地址路径含有正则表达式
@RequestMapping(value = "/spring/{content:[a-z]+}.do")
public void todo3(@PathVariable String content) {
System.out.println("Hello Spring " + content);
}
5.2.2、method
说明: 指定请求的method类型, GET、POST、PUT、DELETE等。
示例:
只接收GET请求:
@RequestMapping(value = "/get.do", method = RequestMethod.GET)
public void get() {
System.out.println("get ...");
}
<form action="/hello/get.do" method="get"><input type="submit" value="get请求">
</form>
只接收POST请求:
@RequestMapping(value = "/post.do", method = RequestMethod.POST)
public void post() {
System.out.println("post ...");
}
<form action="/hello/post.do" method="post"><input type="submit" value="post请求">
</form>
只接收PUT请求:
<!--用于处理PUT、DELETE请求-->
<filter><filter-name>HiddenHttpMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping><filter-name>HiddenHttpMethodFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
@RequestMapping(value = "/put.do", method = RequestMethod.PUT)
public void put() {
System.out.println("put ...");
}
<form action="/hello/put.do" method="post"><input type="hidden" name="_method" value="put"><input type="submit" value="put请求">
</form>
只接收DELETE请求:
<!--用于处理PUT、DELETE请求-->
<filter><filter-name>HiddenHttpMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping><filter-name>HiddenHttpMethodFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
@RequestMapping(value = "/delete.do", method = RequestMethod.DELETE)
public void delete() {
System.out.println("delete ...");
}
<form action="/hello/delete.do" method="post"><input type="hidden" name="_method" value="delete"><input type="submit" value="delete请求">
</form>
GET请求简写形式:
@GetMapping("/get.do")
public void get() {
System.out.println("get ...");
}
POST请求简写形式:
@PostMapping("/post.do")
public void post() {
System.out.println("post ...");
}
PUT请求简写形式:
@PutMapping("/put.do")
public void put() {
System.out.println("put ...");
}
DELETE请求简写形式:
@DeleteMapping("/delete.do")
public void delete() {
System.out.println("delete ...");
}
5.2.3、params
说明: 指定请求中必须包含某些参数值时,才让该方法处理。
示例:
//设定必须包含username和age两个参数,且age参数不为10(可以有多个参数)
@RequestMapping(value = "/params.do", method = RequestMethod.GET, params = {
"username", "age!=10"})
public void params() {
System.out.println("params ...");
}
5.2.4、headers
说明: 指定请求中必须包含某些指定的header值,才能让该方法处理请求。
示例:
@RequestMapping(value = "/headers.do", method = RequestMethod.GET, headers = "Host=localhost:8080")
public void headers() {
System.out.println("headers ...");
}
5.2.5、consumes
说明: 指定处理请求的提交内容类型 (Content-Type),例如 application/json, text/html。
示例:
@RequestMapping(value = "/consumes.do", method = RequestMethod.POST, consumes = "application/json")
public void consumes() {
System.out.println("consumes ...");
}
$.ajax({
url: "/hello/consumes.do",type: "post",headers: {
"Content-Type": "application/json"}
});
5.2.6、produces
说明: 指定请求响应返回的内容类型(Accept),例如 application/json, text/html。
示例:
@RequestMapping(value = "/produces.do", method = RequestMethod.POST, produces = "application/json")
public void produces() {
System.out.println("produces ...");
}
$.ajax({
url: "/hello/produces.do",type: "post",headers: {
"Accept": "application/json"}
});
第六章 SpringMVC的控制器方法
6.1、控制器方法的参数
核心原理
SpringMVC的控制器方法能接收多少种参数类型,完全取决于参数解析器,我们只讲解常用部分,其余部分可以自己探索。
参数解析器:HandlerMethodArgumentResolver
6.1.1、接收单个参数
第一种形式: 通过参数名称,只要保证请求参数名与该请求处理方法的参数名相同即可。
请求地址:http://localhost:8080/hello/getParam1.do?username=zhangsan
@RequestMapping("/getParam1.do")
public void getParam1(String username) {
System.out.println("getParam1 " + username);
}
第二种形式: 通过注解获取,只要保证请求参数名与 @RequestParam
注解的参数名相同即可。
请求地址:http://localhost:8080/hello/getParam1.do?username=zhangsan
@RequestMapping("/getParam1.do")
public void getParam1(@RequestParam("username") String name) {
System.out.println("getParam1 " + name);
}
第三种形式: 通过路径变量,只要保证在路径中的变量名和 @PathVariable
注解的参数名相同即可。
请求地址:http://localhost:8080/hello/zhangsan.do
@RequestMapping("/{username}.do")
public void getParam1(@PathVariable("username") String name) {
System.out.println("getParam1 " + name);
}
6.1.2、接收多个参数
第一种形式: 通过参数名称,只要保证请求参数名与该请求处理方法的参数名相同即可。
请求地址:http://localhost:8080/hello/getParam2.do?username=zhangsan&password=123546
@RequestMapping("/getParam2.do")
public void getParam2(String username, String password) {
System.out.println("getParam2 " + username + " " + password);
}
第二种形式: 通过注解获取,只要保证请求参数名与 @RequestParam
注解的参数名相同即可。
请求地址:http://localhost:8080/hello/getParam2.do?username=zhangsan&password=123546
@RequestMapping("/getParam2.do")
public void getParam2(@RequestParam("username") String name, @RequestParam("password") String pwd) {
System.out.println("getParam2 " + name + " " + pwd);
}
第三种形式: 通过路径变量,只要保证在路径中的变量名和 @PathVariable
注解的参数名相同即可。
请求地址:http://localhost:8080/hello/zhangsan/123456.do
@RequestMapping("/{username}/{password}.do")
public void getParam2(@PathVariable("username") String name, @PathVariable("password") String pwd) {
System.out.println("getParam2 " + name + " " + pwd);
}
6.1.3、接收对象数据类型
public class User {
private String name;private String age;public String getName() {
return name;}public void setName(String name) {
this.name = name;}public String getAge() {
return age;}public void setAge(String age) {
this.age = age;}@Overridepublic String toString() {
return "User{" +"name='" + name + '\'' +", age='" + age + '\'' +'}';}
}
第一种形式: 通过属性名获取
请求地址:http://localhost:8080/hello/getParam3.do?name=zhangsan&age=18
@RequestMapping(value = "/getParam3.do", method = RequestMethod.GET)
public void getParam3(User user) {
System.out.println("getParam3 " + user);
}
第二种形式: 通过请求体获取
xmlns:mvc="http://www.springframework.org/schema/mvc"
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
<!--开启MVC注解-->
<mvc:annotation-driven/>
@RequestMapping(value = "/getParam3.do", method = RequestMethod.POST)
public void getParam3(@RequestBody User user) {
System.out.println("getParam3 " + user);
}
let user = {
name: "zhangsan",age: 18
};
$.ajax({
url: "/hello/getParam3.do",type: "post",contentType: "application/json",data: JSON.stringify(user)
});
6.1.4、接收集合数据类型
6.1.4.1、array数组
第一种形式: 通过属性名获取
请求地址:http://localhost:8080/hello/getParam4.do?array=zhangsan&array=lisi
@RequestMapping(value = "/getParam4.do", method = RequestMethod.GET)
public void getParam4(@RequestParam("array") String[] array) {
System.out.println("getParam4 " + Arrays.toString(array));
}
第二种形式: 通过数组名获取
@RequestMapping(value = "/getParam4.do", method = RequestMethod.POST)
public void getParam4(@RequestParam("array[]") String[] array) {
System.out.println("getParam4 " + Arrays.toString(array));
}
let arr = ["zhangsan", "lisi"];
$.ajax({
url: "/hello/getParam4.do",type: "post",data: {
array: arr}
});
第三种形式: 通过请求体获取
@RequestMapping(value = "/getParam4.do", method = RequestMethod.POST)
public void getParam4(@RequestBody String[] array) {
System.out.println("getParam4 " + Arrays.toString(array));
}
let arr = ["zhangsan", "lisi"];
$.ajax({
url: "/hello/getParam4.do",type: "post",contentType: "application/json",data: JSON.stringify(arr)
});
6.1.4.2、list集合
第一种形式: 通过属性名获取
请求地址:http://localhost:8080/hello/getParam5.do?list=zhangsan&list=lisi
@RequestMapping(value = "/getParam5.do", method = RequestMethod.GET)
public void getParam5(@RequestParam("list") List<String> list) {
System.out.println("getParam5 " + list);
}
第二种形式: 通过数组名获取
@RequestMapping(value = "/getParam5.do", method = RequestMethod.POST)
public void getParam5(@RequestParam("list[]") List<String> list) {
System.out.println("getParam5 " + list);
}
let list = ["zhangsan", "lisi"];
$.ajax({
url: "/hello/getParam5.do",type: "post",data: {
list: list}
});
第三种形式: 通过请求体获取
@RequestMapping(value = "/getParam5.do", method = RequestMethod.POST)
public void getParam5(@RequestBody List<String> list) {
System.out.println("getParam5 " + list);
}
let list = ["zhangsan", "lisi"];
$.ajax({
url: "/hello/getParam5.do",type: "post",contentType: "application/json",data: JSON.stringify(list)
});
6.1.4.3、set集合
第一种形式: 通过属性名获取
请求地址:http://localhost:8080/hello/getParam6.do?set=zhangsan&set=lisi
@RequestMapping(value = "/getParam6.do", method = RequestMethod.GET)
public void getParam6(@RequestParam("set") Set<String> set) {
System.out.println("getParam6 " + set);
}
第二种形式: 通过集合名获取
@RequestMapping(value = "/getParam6.do", method = RequestMethod.POST)
public void getParam6(@RequestParam("set[]") Set<String> set) {
System.out.println("getParam6 " + set);
}
let set = ["zhangsan", "lisi"];
$.ajax({
url: "/hello/getParam6.do",type: "post",data: {
set: set}
});
第三种形式: 通过请求体获取
@RequestMapping(value = "/getParam6.do", method = RequestMethod.POST)
public void getParam6(@RequestBody Set<String> set) {
System.out.println("getParam6 " + set);
}
let set = ["zhangsan", "lisi"];
$.ajax({
url: "/hello/getParam6.do",type: "post",contentType: "application/json",data: JSON.stringify(set)
});
6.1.4.4、map集合
第一种形式: 通过键值对获取
请求地址:http://localhost:8080/hello/getParam7.do?name1=zhangsan&name2=lisi
@RequestMapping(value = "/getParam7.do", method = RequestMethod.GET)
public void getParam7(@RequestParam Map<String, String> map) {
System.out.println("getParam7 " + map);
}
第二种形式: 通过键值对获取
@RequestMapping(value = "/getParam7.do", method = RequestMethod.POST)
public void getParam7(@RequestParam Map<String, String> map) {
System.out.println("getParam7 " + map);
}
let map = {
"name1": "zhangsan","name2": "lisi"
};
$.ajax({
url: "/hello/getParam7.do",type: "post",data: map
});
第三种形式: 通过请求体获取
@RequestMapping(value = "/getParam7.do", method = RequestMethod.POST)
public void getParam7(@RequestBody Map<String, String> map) {
System.out.println("getParam7 " + map);
}
let map = {
"name1": "zhangsan","name2": "lisi"
};
$.ajax({
url: "/hello/getParam7.do",type: "post",contentType: "application/json",data: JSON.stringify(map)
});
6.1.5、接收请求头的参数
6.1.5.1、获取指定请求头
请求地址:http://localhost:8080/hello/getHeaderValue.do
@RequestMapping("/getHeaderValue.do")
public void getHeaderValue(@RequestHeader("User-Agent") String userAgent) {
System.out.println("getHeaderValue " + userAgent);
}
6.1.5.2、获取所有请求头
请求地址:http://localhost:8080/hello/getHeaderValue.do
@RequestMapping("/getHeaderValue.do")
public void getHeaderValue(@RequestHeader Map<String,String> header) {
System.out.println("getHeaderValue " + header);
}
6.1.6、接收Cookie的参数
请求地址:http://localhost:8080/hello/getCookieValue.do
@RequestMapping("/getCookieValue.do")
public void getCookieValue(@CookieValue("JSESSIONID") String jsessionid) {
System.out.println("getCookieValue " + jsessionid);
}
请求地址:http://localhost:8080/hello/getCookieValue.do
@RequestMapping("/getCookieValue.do")
public void getCookieValue(@CookieValue("JSESSIONID") Cookie cookie) {
System.out.println("getCookieValue " + cookie.getValue());
}
6.1.7、接收矩阵变量参数
修改 web.xml
<servlet><servlet-name>spring-mvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>spring-mvc</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>
修改 spring-mvc.xml
<mvc:annotation-driven enable-matrix-variables="true">...
</mvc:annotation-driven>
请求地址:http://localhost:8080/hello/sellCar;low=34;brand=bm,audi,yd
@RequestMapping("/{path}")
public void getHeaderValue(@MatrixVariable("low") Integer low,@MatrixVariable("brand") List<String> brand,@PathVariable("path") String path) {
System.out.println("low " + low);System.out.println("brand " + brand);System.out.println("path " + path);
}
请求地址:http://localhost:8080/hello/boss1;age=20/emp1;age=10
@RequestMapping("/{bossId}/{empId}")
public void getHeaderValue(@MatrixVariable(value = "age", pathVar = "bossId") Integer bossAge,@MatrixVariable(value = "age", pathVar = "empId") Integer empAge,@PathVariable("bossId") String bossId,@PathVariable("empId") String empId) {
System.out.println(bossId + " age " + bossAge);System.out.println(empId + " age " + empAge);
}
恢复 spring-mvc.xml
<mvc:annotation-driven>...
</mvc:annotation-driven>
恢复 web.xml
<servlet><servlet-name>spring-mvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>spring-mvc</servlet-name><url-pattern>*.do</url-pattern>
</servlet-mapping>
6.1.8、解决中文乱码问题
<!--注册字符集过滤器-->
<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><!--强制Request使用字符集encoding--><init-param><param-name>forceRequestEncoding</param-name><param-value>true</param-value></init-param><!--强制Response使用字符集encoding--><init-param><param-name>forceResponseEncoding</param-name><param-value>true</param-value></init-param>
</filter>
<filter-mapping><filter-name>characterEncodingFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
6.2、控制器方法的返回值
核心原理
SpringMVC的控制器方法能返回多少种返回值类型,完全取决于返回值处理器,我们只讲解常用部分,其余部分可以自己探索。
返回值处理器:HandlerMethodReturnValueHandler
6.2.1、返回值为 ModeAndView
若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回 ModelAndView 比较好。当然,若要返回 ModelAndView,则处理器方法中需要定义 ModelAndView 对象。
在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何资源跳转(如对页面的 AJAX 异步响应),此时若返回 ModelAndView,则将总是有一部分多余:要么 Model 多余,要么 View 多余,即此时返回 ModelAndView 将不合适。
请求地址:http://localhost:8080/hello/page.do
@RequestMapping("/page.do")
public ModelAndView page() {
ModelAndView mv = new ModelAndView();mv.addObject("msg", "Hello World");mv.setViewName("/page.jsp");return mv;
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title></title>
</head>
<body>
<h1>${msg}</h1>
</body>
</html>
但是,细心的你如果注意到,在浏览器地址输入:http://localhost:8080/page.jsp,他也能访问 page.jsp
这是很不安全的,因此,我们建议把所有的 jsp
放到 WEB-INF
文件夹中,这样一来,外部直接输入 http://localhost:8080/page.jsp 就访问不到了,那这时候,我们的视图名称该如何写呢,请参考以下示例:
@RequestMapping("/page.do")
public ModelAndView page() {
ModelAndView mv = new ModelAndView();mv.addObject("msg", "Hello World");mv.setViewName("/WEB-INF/page.jsp");return mv;
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title></title>
</head>
<body>
<h1>${msg}</h1>
</body>
</html>
我们会觉得,每次都要是写上要跳转视图的物理视图地址,会感觉很麻烦,而且,万一我的所有 jsp
界面都移动到了 WEB-INF/aaa
文件夹中,那我还得需要手动来修改源码中的视图名称,这是不可取的,我们希望,在代码中,只写返回视图的名称,而不是一个物理视图地址,这时候,我们可以使用Spring给我们提供的视图解析器,此时视图名称这个字符串与视图解析器中的 prefix、suffix 相结合,即可形成要访问的 URI。
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/"/><property name="suffix" value=".jsp"/>
</bean>
@RequestMapping("/page.do")
public ModelAndView page() {
ModelAndView mv = new ModelAndView();mv.addObject("msg", "Hello World");mv.setViewName("page");return mv;
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title></title>
</head>
<body>
<h1>${msg}</h1>
</body>
</html>
6.2.2、返回值为 String
处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址。
如果我们想要携带数据,可以直接在参数中指明数据模型 Model model
。
@RequestMapping("/page.do")
public String page(Model model) {
model.addAttribute("msg", "Hello World");return "page";
}
当然,也可以直接返回资源的物理视图名。不过,此时就不需要再在视图解析器中再配置前辍与后辍了。
@RequestMapping("/page.do")
public String page(Model model) {
model.addAttribute("msg", "Hello World");return "/WEB-INF/page.jsp";
}
6.2.3、返回值为 Void
对于处理器方法返回 void 的应用场景,主要用于服务端直接向浏览器发回数据,所以也就无需视图页面了。使用此种方式可以进行 AJAX 响应。处理器对于 AJAX 请求中所提交的参数,可以使用逐个接收的方式,也可以以对象的方式整体接收。只要保证 AJAX 请求参数与接收的对象类型属性同名。为了方便模拟,我们直接使用GET请求来进行演示,浏览器地址:http://localhost:8080/hello/myVoid.do?name=zhangsan&age=18
@RequestMapping("/myVoid.do")
public void myVoid(String name, String age, HttpServletResponse response) throws IOException {
//创建用户User user = new User();user.setName(name);user.setAge(age);//转为JSONObjectMapper om = new ObjectMapper();String json = om.writeValueAsString(user);//写到页面PrintWriter pw = response.getWriter();pw.write(json);pw.flush();pw.close();
}
6.2.4、返回值为 Object
处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer,String,自定义对象, Map,List 等。但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的。 返回对象,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。
第一步:需要导入相关依赖,之前我们已经导入过了。
<!--导入JSON处理工具包-->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.12.0</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.0</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.12.0</version>
</dependency>
第二步:将 Object 数据转化为 JSON 数据,需要由消息转换器 HttpMessageConverter 完成。而转换器的开启,需要由<mvc:annotation-driven/>
来完成。 SpringMVC 使用消息转换器实现请求数据和对象,处理器方法返回对象和响应输出之间的自动转换。
<!--开启MVC注解-->
<mvc:annotation-driven/>
第三步:返回自定义类型对象时,不能以对象的形式直接返回给客户端浏览器,而是使用 @ResponseBody
注解将对象转换为 JSON 格式的数据发送给浏览器的。 由于转换器底层使用了 Jackson 转换方式将对象转换为 JSON 数据,所以需要导入 Jackson 的相关 Jar 包。
请求地址:http://localhost:8080/hello/myObject.do?name=zhangsan&age=18
@RequestMapping("/myObject.do")
@ResponseBody
public User myObject(String name, String age) {
//创建对象User user = new User();user.setName(name);user.setAge(age);//返回对象return user;
}
如果说,我们当前控制器中的所有方法均是返回 JSON 字符串,我们不必在每一个方法上都写一遍 @ResponseBody
,而是直接在类上写,这样就代表了,当前类下所有的方法都是返回的 JSON 字符串。
@Controller
@RequestMapping("/hello")
@ResponseBody
public class HelloController {
}
当然了,SpringMVC给我们提供了一个复合注解叫做 @RestController
,它是由 @Controller
和 @ResponseBody
复合组成的,目的就是为了简化书写,提高程序阅读。
@RestController
@RequestMapping("/hello")
public class HelloController {
}
第七章 SpringMVC的页面跳转
当处理器对请求处理完毕后,向其它资源进行跳转时,有两种跳转方式:请求转发与重定向。而根据所要跳转的资源类型,又可分为两类:跳转到页面与跳转到其它处理器。 注意,对于请求转发的页面,可以是 WEB-INF 中页面;而重定向的页面,是不能为 WEB-INF 中的页面。因为重定向相当于用户再次发出一次请求,而用户是不能直接访问 WEB-INF 中资源的。
SpringMVC 框架把原来 Servlet 中的请求转发和重定向操作进行了封装。现在可以使用简单的方式实现转发和重定向。
- forward:表示转发,实现 request.getRequestDispatcher(“xx.jsp”).forward()
- redirect:表示重定向,实现 response.sendRedirect(“xxx.jsp”)
7.1、请求转发
处理器方法返回 ModelAndView 时,需在 setViewName() 指定的视图前添加 forward:
,且此时的视图不再与视图解析器一同工作,这样可以在配置了解析器时指定不同位置的视图。视图页面必须写出相对于项目根的路径。forward 操作不需要视图解析器。处理器方法如果返回 String,在视图路径前面加入 forward:
加上视图完整路径。
请求地址:http://localhost:8080/hello/forward.do
返回值为 ModelAndView :
@RequestMapping("/forward.do")
public ModelAndView forward() {
ModelAndView mv = new ModelAndView();mv.addObject("msg", "forward ...");mv.setViewName("forward:/WEB-INF/page.jsp");return mv;
}
返回值为 String :
@RequestMapping("/forward.do")
public String forward(Model model) {
model.addAttribute("msg", "forward ...");return "forward:/WEB-INF/page.jsp";
}
7.2、重定向
处理器方法返回 ModelAndView 时,需在 setViewName() 指定的视图前添加 redirect:
,且此时的视图不再与视图解析器一同工作,这样可以在配置了解析器时指定不同位置的视图。视图页面必须写出相对于项目根的路径。redirect 操作不需要视图解析器。处理器方法如果返回 String,在视图路径前面加入 redirect:
加上视图完整路径。
请求地址:http://localhost:8080/hello/redirect.do
返回值为 ModelAndView :
@RequestMapping("/redirect.do")
public ModelAndView redirect() {
ModelAndView mv = new ModelAndView();System.out.println("redirect ...");mv.setViewName("redirect:/page.jsp");return mv;
}
返回值为 String :
@RequestMapping("/redirect.do")
public String redirect() {
System.out.println("redirect ...");return "redirect:/page.jsp";
}
第八章 SpringMVC的拦截器
8.1、拦截器概述
SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。其拦截的时间点在“处理器映射器根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器, 在处理器适配器执行处理器之前”。当然,在处理器映射器映射出所要执行的处理器类时, 已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。
8.2、拦截器定义
public class MyInterceptor implements HandlerInterceptor {
@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
System.out.println("MyInterceptor preHandle ...");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {
System.out.println("MyInterceptor postHandle ...");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
System.out.println("MyInterceptor afterCompletion ...");}
}
自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中含有三个方法:
- preHandle(request,response, Object handler):该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。
- postHandle(request,response, Object handler,modelAndView):该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。 由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。
- afterCompletion(request,response, Object handler, Exception ex):当 preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView 再操作也对响应无济于事。afterCompletion 是最后执行的方法,主要用于清除资源。
8.3、拦截器注册
<!--注册拦截器-->
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.caocheneli.spring5.interceptor.MyInterceptor"/></mvc:interceptor>
</mvc:interceptors>
8.4、单个拦截器执行顺序
单个拦截器中方法与处理器方法的执行顺序如下图:
8.5、多个拦截器执行顺序
多个拦截器中方法与处理器方法的执行顺序如下图:
第九章 SpringMVC的国际化
第一步:编写国际化资源文件集合,在 resources
目录下,分别建立以下文件
i18n.properties
i18n.username=username:
i18n.password=password:
i18n_zh_CN.properties
i18n.username=账户:
i18n.password=密码:
i18n_en_US.properties
i18n.username=username:
i18n.password=password:
第二步:配置国际化资源文件
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"><property name="defaultEncoding" value="UTF-8"/><property name="useCodeAsDefaultMessage" value="true"/><property name="basenames"><list><value>classpath:i18n</value></list></property>
</bean>
第三步:配置默认区域信息解析器
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"><property name="defaultLocale" value="zh_CN"/>
</bean>
第四步:配置区域设置更改拦截器
<mvc:interceptors>...<!--配置区域设置更改拦截器--><bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"><property name="paramName" value="lang"/></bean>
</mvc:interceptors>
第五步:编写页面跳转控制方法
@RequestMapping("/loginPage.do")
public String loginPage() {
return "login";
}
第六步:编写需要国际化的页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head><title></title>
</head>
<body>
<form action="/login.do" method="post"><p><spring:message code="i18n.username"/><input type="text" name="username"></p><p><spring:message code="i18n.password"/><input type="text" name="password"></p>
</form>
<p><a href="/hello/loginPage.do?lang=zh_CN">切换为中文</a><a href="/hello/loginPage.do?lang=en_US">切换为英文</a>
</p>
</body>
</html>
第七步:在浏览器地址栏输入http://localhost:8080/hello/loginPage.do进行访问
第十章 SpringMVC的异常处理
10.1、异常处理概述
SpringMVC 框架常使用 @ExceptionHandler 注解处理异常。使用注解 @ExceptionHandler 可以将一个方法指定为异常处理方法。该注解只有一个可选属性 value,为一个 Class 数组,用于指定该注解的方法所要处理的异常类,即所要匹配的异常。而被注解的方法,其返回值可以是 ModelAndView、String、void、自定义Object,方法名随意,方法参数可以是 Exception 及其子类对象、HttpServletRequest、HttpServletResponse 等。系统会自动为这些方法参数赋值。对于异常处理注解的用法,也可以直接将异常处理方法注解于 Controller 之中。
10.2、自定义异常类
UserException
public class UserException extends Exception {
public UserException() {
super();}public UserException(String message) {
super(message);}
}
UserNameException
public class UserNameException extends UserException {
public UserNameException() {
super();}public UserNameException(String message) {
super(message);}
}
UserAgeException
public class UserAgeException extends UserException {
public UserAgeException() {
super();}public UserAgeException(String message) {
super(message);}
}
10.3、定义全局异常处理
GlobalExceptionHandler
//@ControllerAdvice:控制器增强(也就是给控制器类增加异常处理功能)
@ControllerAdvice
public class GlobalExceptionHandler {
//@ExceptionHandler(异常的class):表示异常的类型,当发生此类型异常时,由当前方法处理@ExceptionHandler(value = UserNameException.class)public ModelAndView doNameException(Exception exception) {
ModelAndView mv = new ModelAndView();mv.addObject("msg", "姓名不能为空!");mv.addObject("ex", exception);mv.setViewName("error");return mv;}//@ExceptionHandler(异常的class):表示异常的类型,当发生此类型异常时,由当前方法处理@ExceptionHandler(value = UserAgeException.class)public ModelAndView doAgeException(Exception exception) {
ModelAndView mv = new ModelAndView();mv.addObject("msg", "年龄必须在18-60岁之间!");mv.addObject("ex", exception);mv.setViewName("error");return mv;}//处理其它异常,UserNameException、UserAgeException之外的异常@ExceptionHandlerpublic ModelAndView doOtherException(Exception exception) {
ModelAndView mv = new ModelAndView();mv.addObject("msg", "系统发生错误,请通知管理员!");mv.addObject("ex", exception);mv.setViewName("error");return mv;}
}
10.4、定义全局错误页面
error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>error page</title>
</head>
<body>
<p>异常信息:${ex.message}</p>
<p>异常提示:${msg}</p>
</body>
</html>
10.5、配置组件扫描异常
<!--开启组件扫描-->
<context:component-scan base-package="com.caocheneli.spring5.controller"></context:component-scan>
<context:component-scan base-package="com.caocheneli.spring5.interceptor"></context:component-scan><!--开启MVC注解-->
<mvc:annotation-driven/>
10.6、定义错误方法测试
@RequestMapping("/error.do")
public String error(String name, Integer age) throws UserException {
if (name == null) {
throw new UserNameException("姓名不正确");}if (age == null || (age < 18 && age > 60)) {
throw new UserAgeException("年龄不正确");}return "login";
}
请求地址:http://localhost:8080/hello/error.do?name=%E5%BC%A0%E4%B8%89&age=20
请求地址:http://localhost:8080/hello/error.do?age=20
请求地址:http://localhost:8080/hello/error.do?name=%E5%BC%A0%E4%B8%89age=90
第十一章 SpringMVC的文件上传
第一步:创建表单上传页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>upload page</title>
</head>
<body>
<form action="/hello/upload.do" method="post" enctype="multipart/form-data">文件上传:<input type="file" name="file"><input type="submit" value="上传">
</form>
</body>
</html>
第二步:配置多媒体解析器
<!--配置多媒体解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!--设定文件默认编码--><property name="defaultEncoding" value="UTF-8"></property><!--设定文件的最大值(5*1024*1024=5M)--><property name="maxUploadSize" value="5242880"></property><!--设定文件上传时写入内存的最大值,如果小于这个参数不会生成临时文件,默认为10240--><property name="maxInMemorySize" value="40960"></property><!--上传文件的临时路径,目录需要自己手动创建--><property name="uploadTempDir" value="fileUpload/temp"></property><!--是否延迟文件解析--><property name="resolveLazily" value="true"/>
</bean>
第三步:导入文件上传依赖
<!--文件上传相关依赖-->
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version>
</dependency>
第四步:创建文件上传方法
@RequestMapping(value = "/upload.do", method = RequestMethod.POST)
@ResponseBody
public String upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
// 文件不为空if (!file.isEmpty()) {
// 文件存放目录String catalog = "/fileUpload/";// 文件存放路径String path = request.getServletContext().getRealPath(catalog);// 文件存放名称String name = String.valueOf(new Date().getTime() + "_" + file.getOriginalFilename());File destFile = new File(path, name);// 文件保存操作try {
file.transferTo(destFile);} catch (IllegalStateException | IOException e) {
e.printStackTrace();}// 文件访问地址String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + catalog + name;// 返回文件地址return "success, the file url is : " + url;} else {
return "error!";}
}
第五步:测试文件上传是否可用
请求地址:http://localhost:8080/upload.jsp
第十二章 SpringMVC的跨域解决
Spring MVC使您可以处理CORS(跨源资源共享)。出于安全原因,浏览器禁止AJAX调用当前来源以外的资源。例如,您可以在一个标签页中拥有您的银行帐户,而在另一个标签页中拥有evil.com。来自evil.com的脚本不应使用您的凭据向您的银行API发出AJAX请求,例如从您的帐户中提取资金!跨域资源共享(CORS)是由大多数浏览器实施的W3C规范,可让您指定授权哪种类型的跨域请求,而不是使用基于IFRAME或JSONP的安全性较低且功能较弱的变通办法。
该 @CrossOrigin 注释能够对带注释的控制器方法跨域请求,如下面的示例所示:
@CrossOrigin
@GetMapping("/getUserInfo.do")
@ResponseBody
public User getUserInfo(){
User user = new User();user.setName("张三");user.setAge("18");return user;
}
除了细粒度的控制器方法级别配置外,您可能还想定义一些全局CORS配置。
<mvc:cors><mvc:mapping path="/api/**"allowed-origins="https://domain1.com, https://domain2.com"allowed-methods="GET, PUT"allowed-headers="header1, header2, header3"exposed-headers="header1, header2"allow-credentials="true"max-age="3600"/><!--Add more mappings...-->
</mvc:cors>
第十三章 SpringMVC的细节处理
13.1、提交表单中有日期
当form表单中的数据是基本类型的时,直接请求action中的url,一点问题都没有。但是当form表单中有时间类型的数据时,且对应的controller是用一个java对象来绑定对应form提交的数据时,就会出现问题,无法提交成功。解决办法就是在对应的controller中新增下面的方法:
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");dateFormat.setLenient(false);binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
13.2、返回数据中有日期
我们经常会返回JSON类型的字符串,有时候,难免会包含一些日期类型,但是我们想要在转换为JSON字符串的时候,就将日期的格式给固定了,那我们可以参考以下做法:
<mvc:annotation-driven><!--处理@ResponseBody里面日期类型--><mvc:message-converters><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"><property name="objectMapper"><bean class="com.fasterxml.jackson.databind.ObjectMapper"><property name="dateFormat"><bean class="java.text.SimpleDateFormat"><constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss"/></bean></property></bean></property></bean></mvc:message-converters>
</mvc:annotation-driven>
13.3、视图快捷导航标签
当我们为了确保系统安全而把所有的 jsp
页面放到 WEB-INF
目录下时,外界是不能直接进行访问的,我们必需先要定义一个视图跳转的方法,跳转到相对应的界面,但是这样做你不觉得太麻烦了吗,那么,SpringMVC又提供了一种便捷的配置方式来进行访问:
<mvc:view-controller path="/loginPage.do" view-name="login"/>
13.4、url-pattern的写法
-
*.do
在没有特殊要求的情况下,SpringMVC 的中央调度器 DispatcherServlet 常使用后辍匹配方式,如写为*.do 或者 *.action, *.mvc 等。
-
/
可以写为
/
,如果访问静态资源,这时 DispatcherServlet 会将例如 .css、.js、.jpg 等资源的获取请求,当作是一个普通的控制器请求。中央调度器会调用处理器映射器为其查找相应的处理器。当然也是找不到的,所以在这种情况下,所有的静态资源获取请求也均会报 404 错误。<url-pattern/>
的值并不是说写为/后,静态资源就无法访问了。经过一些配置后,该问题也是可以解决的。第一种解决方法:声明
<mvc:default-servlet-handler/>
后 , SpringMVC 框架会在容器中创建 DefaultServletHttpRequestHandler 处理器对象。它会像一个检查员,对进入 DispatcherServlet 的 URL 进行筛查,如果发现是静态资源的请求,就将该请求转由 Web 应用服务器默认的Servlet处理。一般的服务器都有默认的Servlet, 在Tomcat中,有一个专门用于处理静态资源访问的 Servlet 名叫 DefaultServlet。第二种解决方法:在 Spring3.0 版本后,Spring 定义了专门用于处理静态资源访问请求的处理器 ResourceHttpRequestHandler。并且添加了标签,专门用于解决静态资源无法访问问题。需要在 springmvc 配置文件中添加如下形式的配置:
<mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/images/**" location="/images/"/>
-
/*
/ 会拦截所有的请求但是不包括
*.jsp*
,/* 则是真正会拦截所有请求包括*.jsp