文章目录
- 第十一章 SpringMVC
- 11.1 什么是SpringMVC
- 11.2 快速入门
- 11.3 springmvc的工作流程
- 11.3 springmvc 控制器
- 11.4 springmvc请求映射
- 11.5 springmvc请求参数
- 11.6 解决中文乱码
- 11.7 控制器的方法返回值
- 11.8 springmvc域对象共享数据
- 11.9 视图与视图解析器
- 11.10 请求转发与重定向
- 11.11 RESTful风格
- 11.12 springmvc 类型转换
- 11.13 springmvc 格式化器
- 11.14 springmvc 转换Json格式
- 11.15 springmvc拦截器
- 11.16 异常处理
- 11.17 文件上传
- 11.18 注解配置
- 11.19 springmvc配置文件
- 11.20 总结
第十一章 SpringMVC
11.1 什么是SpringMVC
springmvc是 由spring框架加mvc 编程思想加吸收javaweb的思想结合的web框架。
11.2 快速入门
第一种 可以选择 java Enterprise 创建springmvc项目
第二种 选择maven 项目中的webapp模板
选择第一种创建好的项目目录如下
pom文件
<?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.example</groupId>
<artifactId>Springmvc</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Springmvc</name>
<!-- 打包方式war-->
<packaging>war</packaging>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<junit.version>5.7.0</junit.version>
</properties>
<dependencies>
<!-- javaweb servlet 的核心依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- 单元测试5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
该项目模板已配置好一个基础模板hello world,直接部署Tomcat启动
Tomcat启动成功之后,访问项目 出现如下页面代表部署成功
到此,javaweb项目已部署成功,接下来把javaweb改造成springmvc项目
11.2.1 javaweb转换为springmvc
加入依赖
1 加入springmvc依赖
<!-- springmvc 依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.20</version>
</dependency>
spring-webmvc jar包包含了spring框架的jar包
2 在web.xml 文件中配置springmvc的servlet
<?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">
<!-- dispatcherServlet是springmvc的核心servlet,它负责接收客户端发送来的所有请求-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
上面的配置跟javaweb是一样的,是一个普通的servlet,还没有达到springmvc的配置。
继续改进如下
<?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">
<!-- 配置springmvc的监听器 用于监听spring容器-->
<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>
<!-- dispatcherServlet是springmvc的核心servlet,它负责接收客户端发送来的所有请求-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置 dispatcherServlet 的初始化参数 contextConfigLocation 参数名称是固定的-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!-- servlet 的加载级别,数字越小级别越大,0 为按需加载-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- dispatcherServlet的请求映射路径-->
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- / 拦截所有请求,不包括 .jsp
/* 拦截所有请求,包括 .jsp 使用 会报404错误-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
dispatcherServlet 有一个参数contextConfigLocation 该参数的名称是固定的,值是spring-mvc.xml 配置文件所在的路径,如果不配置参数,就需要把配置文件按指定的命名格式与位置放置。
格式 {servletName}-servlet.xml
如: spring-mvc-servlet.xml
放置位置:WEB-INF目录及子目录下。
spring-mvc.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置springmvc 扫描路径,这里只扫描 控制器 controller的包-->
<context:component-scan base-package="com.example.Springmvc.controller"/>
</beans>
spring-ioc.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
</beans>
第一种方式,通过注解
创建一个controller包,并在该包下创建一个HelloController类
package com.example.Springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: lyf
* @CreateTime: 2022-12-03
* @description:
*/
@Controller // 标记为spring组件
public class HelloController {
/**
* @RequestMapping 表示请求映射注解 值为请求映射的值
* @return
*/
@RequestMapping("/hello")
public String hello(){
// 在控制台输出
System.out.println("hello world ");
// 返回到index.jsp 页面
return "index.jsp";
}
}
重启Tomcat服务器 访问 http://localhost:8080/Springmvc_war_exploded/hello
页面跳转到index首页
控制台输出
第二种方式
实现Controller接口 @Controller的类名小写加一个/
符号代表访问路径
@org.springframework.stereotype.Controller("/servlet")
public class ServletController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().write("<h1>hello world<h1>");
return null;
}
}
总结
到此,从javaweb转到springmvc配置已经结束,是不是特别简单,只需在web.xml文件中配置一个servlet,就可以使用javaweb中使用spring的ioc与aop了。
11.3 springmvc的工作流程
SpringMVC 的执行流程如下。
1 用户通过浏览器发起一个 HTTP 请求,该请求会被 DispatcherServlet(前端控制器)拦截;
2 DispatcherServlet 调用 HandlerMapping(处理器映射器)找到具体的处理器(Handler)及拦截器,最后以 HandlerExecutionChain 执行链的形式返回给 DispatcherServlet。
3 DispatcherServlet 将执行链返回的 Handler 信息发送给 HandlerAdapter(处理器适配器);
4 HandlerAdapter 根据 Handler 信息找到并执行相应的 Handler(即 Controller 控制器)对请求进行处理;
5 Handler 执行完毕后会返回给 HandlerAdapter 一个 ModelAndView 对象(Spring MVC 的底层对象,包括 Model 数据模型和 View 视图信息);
6 HandlerAdapter 接收到 ModelAndView 对象后,将其返回给 DispatcherServlet ;
7 DispatcherServlet 接收到 ModelAndView 对象后,会请求 ViewResolver(视图解析器)对视图进行解析;
8 ViewResolver 解析完成后,会将 View 视图并返回给 DispatcherServlet;
9 DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图);
10 视图负责将结果显示到浏览器(客户端)。
总结
以上的流程当中,我们只需要编写控制器 controller 与视图 view 即可,其他的spring框架已经提供了。
11.3 springmvc 控制器
11.3.1 什么是springmvc控制器
springmvc的控制器与servlet有着本质的区别,springmvc的控制器接收到的请求是靠dispatcherServlet对象拦截转发过来的。本质不是一个servlet对象。
11.3.2 控制器案例
注解 @Controller 表示为控制器注解。
@ResponseBody 注解表示 返回的数据以json形式返回到客户端。
@RestController 是 由@ResponseBoby与@Controller注解的复合注解,表示当前处理完的数据由json格式发送到客户端,不需要视图解析器处理。
@Controller // 标记为spring组件
public class HelloController {
/**
* @RequestMapping 表示请求映射注解 值为请求映射的值
* @return
*/
@ResponseBody // 加载类上与方法上都可以,
@RequestMapping("/hello")
public String hello(){
// 在控制台输出
System.out.println("hello world ");
// 返回到index.jsp 页面
return "index.jsp";
}
}
在hello方法上加入@ResponseBody注解,重启服务器,再次访问,没有跳转带index.jsp
11.4 springmvc请求映射
@RequestMapping 注解表示请求的映射路径,可以用在类上也可以用在方法上,用在类上表示是所有的方法映射的父映射,
请求路径为 /he/hello
package com.example.Springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: lyf
* @CreateTime: 2022-12-03
* @description:
*/
//@Controller // 标记为spring组件
@RestController
@RequestMapping("/he") // 父映射路径
public class HelloController {
/**
* @RequestMapping 表示请求映射注解 值为请求映射的值
* @return
*/
// @ResponseBody // 加载类上与方法上都可以,
@RequestMapping("/hello") // 子映射路径
public String hello(){
// 在控制台输出
System.out.println("hello world ");
// 返回到index.jsp 页面
return "index.jsp";
}
}
@RequestMapping 注解属性
package com.example.Springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: lyf
* @CreateTime: 2022-12-03
* @description:
*/
//@Controller // 标记为spring组件
@RestController
@RequestMapping("/he") // 父映射路径
public class HelloController {
/**
* @RequestMapping 表示请求映射注解 值为请求映射的值
* @return
*/
// @ResponseBody // 加载类上与方法上都可以,
@RequestMapping(
value = {"/hello","hello1"} //支持多个路径匹配
,name = ""
// ,path = {"/hello","hello1"} 路径映射,不能跟value属性同时存在
,method = {RequestMethod.GET,RequestMethod.POST} //支持的方法
, params = {"username","password"}// 请求参数,请求中有这个属性才接收请求
, headers = {"Host: localhost:8080"} //请求头中含有指定的请求头才接受请求
, consumes = {"Content-Type:text/html;charset=utf-8"}//指定处理请求的提交内容类型 (Content-Type),例如 application/json, text/html
, produces = {"Content-Type:text/html;charset=utf-8"}
) // 子映射路径
public String hello(){
// 在控制台输出
System.out.println("hello world ");
// 返回到index.jsp 页面
return "index.jsp";
}
}
请求映射通配符
11.5 springmvc请求参数
在Tomcat中修改上下文路径
11.5.1 接收基本参数
/**
* 第一种,请求参数,与方法形参一致
* @param username
* 请求地址 http://localhost:8080/he/hello1?username=admin
* @return
*/
@RequestMapping("/hello1")
public String hello1(String username){
String name= username;
return name;
}
/**
* 第二种,请求参数,与方法形参不一致,请求参数 user 方法形参 username 通过注解@RequestParam 注解绑定
* 请求地址 http://localhost:8080/he/hello2?user=admin
* @param username
* @return
*/
@RequestMapping("/hello2")
public String hello2(@RequestParam("user") String username){
String name= username;
return name;
}
/**
* 第三种,请求参数,与方法形参不一致,请求参数 user 方法形参 username 通过注解@PathVariable 注解绑定
* 保证请求路径中的user占位值与@PathVariable一致即可。
* @param username
*请求地址:http://localhost:8080/he/hello3/admin
* @return
*/
@RequestMapping("/hello3/{user}")
public String hello3(@PathVariable("user") String username){
String name= username;
return name;
}
11.5.2 接收对象参数
设置接收对象类型
package com.example.Springmvc.controller;
/**
* @Author: lyf
* @CreateTime: 2022-12-03
* @description:
*/
public class User {
private String username;
private String password;
private Integer age;
private Integer sex;
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}
第一种通过属性名获取
http://localhost:8080/he/user?username=admin&password=123
@RequestMapping( "/user")
@ResponseBody
public User getUser(User user){
return user;
}
第二种通过请求体方式
@RequestMapping( "/user")
@ResponseBody
public User getUser(@RequestBody User user){
return user;
}
11.5.3 接收集合类型
//属性名称获取
@RequestMapping("/param")
public void arrayParam(@RequestParam Arrays arrays){
System.out.println(arrays.toString());
}
// 请求体获取
@RequestMapping("/body")
public void arrayBody(@RequestBody Arrays arrays){
System.out.println(arrays.toString());
}
11.5.4 获取请求头参数
@RequestHeader 用于获取所有请求头,加参数获取指定请求头,不加,获取所有请求头
/**
* 获取请求头
* @param header
*/
@RequestMapping("/header")
public void header(@RequestHeader("Cookie")String header){
System.out.println(header);
}
/**
* 获取所有请求头
* @param header
*/
@RequestMapping("/header")
public void headerAll(@RequestHeader Map<String,String> header){
System.out.println(header);
}
11.5.5 获取cookie
@RequestMapping("/cookie")
public void getCookie(@CookieValue("cookieID") String cookieId){
System.out.println(cookieId);
}
11.5.6 获取HttpServletRequest
@RequestMapping("/http")
public void http(HttpServletRequest request){
//获取指定参数
String username = request.getParameter("username");
Enumeration<String> parameterNames = request.getParameterNames();
// 获取所有参数
while (parameterNames.hasMoreElements()){
String element = parameterNames.nextElement();
String value = request.getParameter(element);
System.out.println(element+":"+value);
}
}
11.5.7 @RequestMapping 子注解
@GetMapping
@PostMapping
@DeleteMapping
@PutMapping
public enum RequestMethod {
GET,
HEAD,
POST,
PUT,
PATCH,
DELETE,
OPTIONS,
TRACE;
private RequestMethod() {
}
}
11.6 解决中文乱码
在web中加入编码过滤器,
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
点击CharacterEncodingFilter类查看它的属性,根据属性赋值
完整编码过滤器配置
<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>
11.7 控制器的方法返回值
11.7.1 返回ModelAndView
ModelAndView 对象 表示返回模型与视图,如果一个请求需要返回数据与视图则就他作为返回值。
@RequestMapping("/mv")
public ModelAndView mv(){
ModelAndView mv = new ModelAndView();
mv.setViewName("index.jsp");
mv.addObject("username","admin");
return mv;
}
}
11.7.2 返回String
/**
* 如果没有加@ResponseBody 或者@RestController注解,则返回的是视图名称,
* 如果配置的有视图解析器,则返回的是逻辑视图,没有则返回物理地址视图
* @return
*/
@RequestMapping("/string")
public String string(){
return "String";
}
/**
* 如果需要返回数据,则在参数中加入Model
* @param model
* @return
*/
@RequestMapping("/string")
public String stringModel(Model model){
model.addAttribute("admin");
return "String";
}
11.7.3 返回void
/**
* 先把对象转换为Json对象
* 再通过Response对象通过流的方法把数据返回到客户端
* @param response
* @throws IOException
*/
@RequestMapping("/void")
public void aVoid(HttpServletResponse response) throws IOException {
response.getWriter().write("void 对象返回");
}
11.7.4 返回Object对象
返回Object对象,返回的数据是以json的形式返回的客户端,任何对象都是Object对象的子类,所以任何对象都可以返回。只需要加入@ResponseBody注解,或者使用复合注解@RestController
@ResponseBody
@RequestMapping("/string")
public String stringModel(Model model){
model.addAttribute("admin");
return "String";
}
11.8 springmvc域对象共享数据
在控制器处理完数据之后,需要将数据返回到共享的域当中,视图在从这个域中获取处理好的数据,渲染之后返回给客户端。
域对象是服务器在内存上创建的一块存储空间,主要用不同动态资源之间的数据传递和数据共享。在 Spring MVC 中,常用的域对象有 request 域对象、session 域对象、application 域对象等。
Spring MVC 提供了多种域对象共享数据的方式,其中最常用的方式如下:
使用 Servlet API 向 request 域对象中共享数据
使用 ModelAndView 向 request 域对象中共享数据
使用 Model 向 request 域对象中共享数据
使用 Map 向 request 域对象中共享数据
使用 ModelMap 向 request 域对象中共享数据
使用 Servlet API 向 session 域中共享数据
使用 Servlet API 向 application 域中共享数据
1 使用 Servlet API 向 request 域对象中共享数据
@RequestMapping("req")
public void request(HttpServletRequest request){
request.setAttribute("username","admin");
}
2 使用 ModelAndView 向 request 域对象中共享数据
@RequestMapping("req1")
public ModelAndView request1(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username","admin");
return modelAndView;
}
3 使用 Model 向 request 域对象中共享数据
@RequestMapping("req2")
public void request2(Model model){
model.addAttribute("username","admin");
}
4 使用 Map 向 request 域对象中共享数据
@RequestMapping("req3")
public void request3(Map<String ,String> map){
map.put("username","password");
}
5 使用 ModelMap 向 request 域对象中共享数据
@RequestMapping("req4")
public void request4(ModelMap modelMap){
modelMap.addAttribute("username","password");
}
6 使用 Servlet API 向 session 域中共享数据
@RequestMapping("/session")
public void session(HttpSession session){
session.setAttribute("username","admin");
}
7 使用 Servlet API 向 application 域中共享数据
@RequestMapping("/session")
public void application(HttpSession session){
ServletContext servletContext = session.getServletContext();
servletContext.setAttribute("username","admin");
}
11.9 视图与视图解析器
视图就是页面,控制器返回的都是视图的名称,是字符串类型,中间需要视图解析器去解析名称,才能获取到真正的视图,ModelAndView 对象是两个不同的对象组合到一起的,分别是Model与View,model代表数据模型,View代表视图,通过把他们两个进行解耦。
View
View 分为逻辑视图与非逻辑视图,逻辑视图代表的是字符串,需要视图解析器解析才能渲染数据并响应到客户端,非逻辑视图代表的是一个View对象,不需要视图解析器去解析,因为视图对象可以直接渲染数据。
常见的视图类
@RequestMapping("req1")
public ModelAndView request1(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username","admin");
// InternalResourceView对象
modelAndView.setView(new InternalResourceView());
return modelAndView;
}
Model
Model代表数据模型,用来封装控制器处理好的数据,放在共享域中,视图从共享域中获取数据,并渲染,再返回给客户端。
视图解析器
视图解析器(ViewResolver)是 Spring MVC 的重要组成部分,它提供了逻辑视图名称与实际视图之间的映射,负责将逻辑视图名解析为一个具体的视图对象。
在spring-mvc.xml 中配置
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--让springmvc 不处理静态资源-->
<mvc:default-servlet-handler/>
<!-- 开启mvc注解 使@RequestMapping 生效-->
<mvc:annotation-driven/>
视图控制器
第一种 通过控制器方法返回视图
@RequestMapping("/form")
public String form(){
return "form";
}
第二种 如果 Spring MVC 中设置了任意一个视图控制器(View-Controller),那么其他控制器中请求映射将全部失效,此时我们需要在 Spring MVC 的核心配置文件中开启 mvc 注解驱动标签。
<mvc:view-controller path="/form" view-name="form"/>
<!-- 注解驱动标签-->
<mvc:annotation-driven />
总结
在视图解析器当中,建议把所有的视图放在 /WEB-INF/
目录下,这样能保证视图安全,因为在该目录下的所有文件,客户端不能直接访问,需要警告控制器才能访问。
11.10 请求转发与重定向
在 Spring MVC 中,我们可以在逻辑视图名中通过“forward:”和“redirect:”两个关键字来表示转发和重定向。有这两个关键词的视图不会被视图解析器解析。
转发
@RequestMapping("forward")
public ModelAndView mv1(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:index");
return modelAndView;
}
@RequestMapping("/for")
public String forward(){
return "forward:index";
}
重定向
@RequestMapping("redirect")
public ModelAndView mv1(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("redirect:index");
return modelAndView;
}
@RequestMapping("/red")
public String forward(){
return "redirect:index";
}
11.11 RESTful风格
RESTful(REST 风格)是一种当前比较流行的互联网软件架构模式,它充分并正确地利用 HTTP 协议的特性,为我们规定了一套统一的资源获取方式,以实现不同终端之间(客户端与服务端)的数据访问与交互。
REST 实际上是 Resource Representational State Transfer 的缩写,翻译成中文就是“表现层资源表述状态转移”。
传统URL | REST URL |
---|---|
http://localhost:8080/user /add | http://localhost:8080/user/add |
http://localhost:8080/user /delete?id=1 | http://localhost:8080/user/delete/1 |
http://localhost:8080/user /update?id=1 | http://localhost:8080/user/update/1 |
http://localhost:8080/user /getUserByid?id=1 | http://localhost:8080/user/getUserById/1 |
// user 与password参数被设置在了请求url当中,里面的值会在参数传递的时候替换掉。
@RequestMapping("/hello3/{user}/{password}")
public String hello3(@PathVariable("user") String username,@PathVariable String password){
String name= username;
return name;
}
总结
传统的url请求路径,容易区分出请求类型,容易获取到参数,二REST风格的url,去掉了参数配置的格式,全部通过url路径的形式方式,把url中的?& = 这些符合去掉。使url路径更加简洁清晰。
11.12 springmvc 类型转换
通过springmvc的类型转换机制,使用注解,控制器方法就能获取到对应的参数类型。
内置基本数据转换类型
数组 集合 转换
自定义类型转换,实现其中一个接口,并配置到springmvc当中。
总结
Spring MVC 对于基本类型(例如 int、long、float、double、boolean 以及 char 等)已经做好了基本类型转换。因此,通常情况下 Spring MVC 提供的这些类型转换器可以满足开发人员大多数的类型转换需求的。
11.13 springmvc 格式化器
将时间或者数字类型按照指定的格式进行显示,就需要用到格式化器。
在 Spring MVC 的配置文件中配置一个 mvc:annotation-driven 标签,Spring MVC 在启动时就会自动初始化一个 FormattingConversionServiceFactoryBean 类型的实例:ConversionService。
也就是说,我们只要在 Spring MVC 配置文件中配置了 mvc:annotation-driven 标签,就可以直接在 Spring MVC 项目中使用 @NumberFormat 注解和 @DateTimeFormat 注解,对 Number 类型和 Date 类型数据进行格式化转换。
日期格式化
@DateTimeFormat 注解可对 java.util.Date、java.util.Calendar、java.long.Long 等时间类型的数据进行标注,以实现对日期类型的数据进行格式化处理。
@DateTimeFormat 注解主要包含以下 3 个属性。
数值格式化
@NumberFormat 注解可以用来格式化任何数字基本类型(如 int、long 等)或 java.lang.Number 类型的实例(如 BigDecimal、Integer 等)。
@NumberFormat 注解拥有两个互斥的属性,如下表。
11.14 springmvc 转换Json格式
如果处理好的数据不需要视图,则直接使用json返回到客户端,比如 Ajax请求。
json
JSON 支持 2 种数据结构,它们分别是对象结构和数组结构。
其中,key 必须为 String 类型,value 可以是 String、Number、Object、Array 等数据类型。
对象结构
{
key1:value1,
key2:value2,
...
}
{
"pname":"张三",
"password":"123456",
"page":40
}
数组
JSON 的数组结构以“[”开始、以“]”结束,中间部分由 0 个或多个以英文的逗号(即“,”)分隔的值列表组成。
[
"c语言中文网",
123456789,
true,
null
]
{
"sno":"201802228888",
"sname":"张三",
"hobby":[
"篮球",
"足球"
],
"college":{
"cname":"清华大学",
"city":"北京",
"code":100000
}
}
JSON 数据转换
为了实现浏览器与控制器类之间的 JSON 数据交互,Spring MVC 提供了一个默认的 MappingJackson2HttpMessageConverter 类,来处理 JSON 格式请求和响应。通过它,我们既可以将 Java 对象转换为 JSON 数据,也可以将 JSON 数据转换为 Java 对象。
引入依赖包
<!--导入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>
JSON 转换注解
注解 | 位置 | 说明 |
---|---|---|
@ResponseBody | 方法上 ,或者类上 | 该注解用于将控制器方法的返回值,直接作为响应报文的响应体响应到浏览器上。 |
@RequestBody | 方法的形参上 | 该注解用于将请求体中的数据绑定到控制器方法的形参上。 |
在 Spring MVC 的配置文件中,除了配置了组件扫描和视图解析器外,我们还配置如下两个元素:
<mvc:annotation-driven /> :Spring MVC 的注解驱动,配置会自动注册 RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter 两个组件,为读写 JSON 数据提供支持。
<mvc:resources /> :静态资源访问映射,用于配置静态资源的访问路径。
<mvc:resources /> 中包含两个重要的属性:location 和 mapping,关于这两个属性的说明如下表。
属性 | 说明 |
---|---|
location | 该属性用于设置需要访问的本地静态资源文件的路径。 |
mapping | 匹配静态资源全路径,其中“/**”表示文件夹及其子文文件夹下的某个具体文件。 |
静态资源过滤选择
这两个标签配置都可以实现静态资源的映射,我们可以根据自身的需求自行选择。
<mvc:resources />
<mvc:default-servlet-handler />
11.15 springmvc拦截器
拦截器(Interceptor)是 Spring MVC 提供的一种强大的功能组件。它可以对用户请求进行拦截,并在请求进入控制器(Controller)之前,servlet之后、控制器处理完请求后、甚至是渲染视图后,执行一些指定的操作。
在 Spring MVC 中,拦截器的作用与 Servlet 中的过滤器类似,它主要用于拦截用户请求并做相应的处理,例如通过拦截器,我们可以执行权限验证、记录请求信息日志、判断用户是否已登录等操作。
Spring MVC 拦截器使用的是可插拔式的设计,如果我们需要某一拦截器,只需在配置文件中启用该拦截器即可;如果不需要这个拦截器,则只要在配置文件中取消应用该拦截器即可。
拦截器只会拦截控制器的方法,如果访问的是 jsp HTML css image js 等不会拦截。
自定义拦截器
Spring MVC 在 org.springframework.web.servlet 包中提供了一个 HandlerInterceptor 接口,该接口包含 3 个方法,如下表。
public class MyHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<!--拦截器 1-->
<mvc:interceptor>
<!--配置拦截器拦截的请求路径-->
<mvc:mapping path="/**"/>
<!--配置拦截器不需要拦截的请求路径-->
<mvc:exclude-mapping path="/login"/>
<mvc:exclude-mapping path="/"/>
<!--定义在 <mvc:interceptors> 下,表示拦截器只对指定路径的请求进行拦截-->
<bean class="com.example.Springmvc.controller.MyHandlerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
执行流程
拦截器处理流程的步骤如下:
1当请求的路径与拦截器拦截的路径相匹配时,程序会先执行拦截器类(MyInterceptor)的 preHandl() 方法。若该方法返回值为 true,则继续向下执行 Controller(控制器)中的方法,否则将不再向下执行;
2 控制器方法对请求进行处理;
3 调用拦截器的 postHandl() 方法,此时我们可以对请求域中的模型(Model)数据和视图做出进一步的修改;
4 通过 DispatcherServlet 的 render() 方法对视图进行渲染;
5 调用拦截器的 afterCompletion () 方法,完成资源清理、日志记录等工作。
多个拦截器的执行流程
在程序运行期间,拦截器的执行是有一定的顺序的,该顺序与拦截器在配置文件中定义的顺序有关。
假设一个项目中包含两个不同的拦截器:Interceptor1 和 Interceptor2,它们在配置文件中定义的顺序为:Interceptor1 → Interceptor2。下面我们就通过一个拦截器流程图来描述下多个拦截器的执行流程。
11.16 异常处理
Spring MVC 提供了一个名为 HandlerExceptionResolver 的异常处理器接口,它可以对控制器方法执行过程中出现的各种异常进行处理。
Srping MVC 为 HandlerExceptionResolver 接口提供了多个不同的实现类,其中最常用的实现类如下。
DefaultHandlerExceptionResolver
ResponseStatusExceptionResolver
ExceptionHandlerExceptionResolver
SimpleMappingExceptionResolver
DefaultHandlerExceptionResolver
DefaultHandlerExceptionResolver 是 HandlerExceptionResolver 接口的常用实现类之一,更是 Spring MVC 提供的默认异常处理器之一,Spring MVC 默认通过它对控制器处理请求时出现的异常进行处理。
下表中列举了 Spring MVC 中一些常见异常的默认状态码。
ExceptionHandlerExceptionResolver
ExceptionHandlerExceptionResolver 是 HandlerExceptionResolver 接口的实现类之一,它也是 Spring MVC 提供的默认异常处理器之一。
ExceptionHandlerExceptionResolver 可以在控制器方法出现异常时,调用相应的 @ExceptionHandler 方法(即使用了 @ExceptionHandler 注解的方法)对异常进行处理。
@ExceptionHandler 注解
@ExceptionHandler 注解中包含了一个 value 属性,我们可以通过该属性来声明一个指定的异常。如果在程序运行过程中,这个 Controller 类中的方法发生了这个指定的异常,那么 ExceptionHandlerExceptionResolver 就会调用这个 @ExceptionHandler 方法对异常进行处理。
案例
@RequestMapping("/exception")
public String exception(){
System.out.println(1/0);
return "form";
}
@ExceptionHandler(ArithmeticException.class)
public String error(ArithmeticException e, Model model){
model.addAttribute("ex",e);
return "error";
}
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2022-12-4 0004
Time: 20:32
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
出错信息:
${ex}
</body>
</html>
@ExceptionHandler 方法的优先级
根据异常的继承关系,调用继承深度最浅的异常处理方法对异常进行处理。
@ExceptionHandler(ArithmeticException.class) // 3
@ExceptionHandler(RuntimeException.class) //2
@ExceptionHandler(Exception.class) //1
注意
定义在某个控制器类中的 @ExceptionHandler 方法只在当前的控制器中有效,它只能处理其所在控制器类中发生的异常。
全局异常处理
我们还可以将 @ExceptionHandler 方法定义在一个使用了 @ControllerAdvice 注解的类中。使用 @ControllerAdvice 注解的类可以包含多个不同的带有 @ExceptionHandler 注解的方法,这些方法可以应用在不同控制器 中所有带有 @RequestMapping 注解的控制器方法中,实现全局异常处理。
@ControllerAdvice //控制器增强,给控制器增加异常处理功能
public class ExceptionController {
@ExceptionHandler //没有属性值,表示处理所有的异常
public String exception(Exception e, Model model){
model.addAttribute("ex",e);
return "error";
}
@ExceptionHandler(Exception.class) // 有值 表示处理指定类型的异常
public String exception1(Exception e, Model model){
model.addAttribute("ex",e);
return "error";
}
}
11.17 文件上传
编写 form 表单
当 form 表单的 enctype 属性为 multipart/form-data 时,浏览器会以二进制流的方式对表单数据进行处理,由服务端
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="photo" multiple="multiple"/>
<input type="submit" value="上传">
</form>
标签中还增加一个 multiple 属性。该属性可以选择对个文件进行上传,即实现多文件上传功能。
<!--文件上传相关依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
文件上传的方法
MultipartFile 对象的方法
@Controller
public class FIleController {
@RequestMapping(value = "/toUpload", method = RequestMethod.POST)
@ResponseBody
public String uploadPhoto(MultipartFile photo, HttpServletRequest request) {
if (!photo.isEmpty()) {
// 文件存放目录
String catalog = "/fileUpload/";
System.out.println(catalog);
// 文件存放路径
String path = request.getServletContext().getRealPath(catalog);
// 文件存放名称
String name = String.valueOf(new Date().getTime() + "_" + photo.getOriginalFilename());
File destFile = new File(path, name);
// 文件保存操作
try {
photo.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!";
}
}
}
11.18 注解配置
- 使用初始化类代替 web.xml
Spring 提供了一个 DispatcherServelt 的快速配置类 org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer,它就是 WebApplicationInitializer 的实现类之一 ,其常用方法如下表。
- 使用配置类代替 Spring 的配置文件
使用 @Configuration与@Bean 注解的 Java 类(通常被称为“配置类”),来代替 Spring 的配置文件。
- 使用配置类代替 Spring MVC 的配置文件
我们知道,Spring MVC 的配置项繁多,例如组件扫描、视图解析器、拦截器、类型转换器、异常解析器、文件上传解析器等。它们在配置类中的配置方式也不尽相同,大致可以被分为 3 种方式:
实现 WebMvcConfigurer 接口
使用 @EnableWebMvc、@ComponentScan 等注解
使用 @Bean 注解
WebMvcConfigurer 是一个基于 Java 8 的接口,该接口定义了许多与 Spring MVC 相关的方法,其中大部分方法都是 default 类型的且都是空实现。因此我们只需要定义一个配置类实现 WebMvcConfigurer 接口,并重写相应的方法便可以实现对 Spring MVC 的配置。
示例
springioc 配置类
@Configuration
public class SpringIOC {
@Bean
public HelloController helloController(){
return new HelloController();
}
}
springmvc 配置类
@Configuration
@ComponentScan
@EnableWebMvc // 开启spring注解支持 等同 <mvc:annotation-driven/>
public class WebMVC implements WebMvcConfigurer {
/**
* 开启静态资源过滤
* 等同 <mvc:default-servlet-handler/>
* @param configurer
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
/**
* 添加拦截器
* 等同 <mvc:interceptors/> 标签
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/he").excludePathPatterns("/hello");
}
/**
* 视图控制器
* 等同 <mvc:view-controller path="/upload" view-name="file"/>
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/upload").setViewName("file");
}
/**
* 视图解析器
*
* @return
*/
@Bean
public InternalResourceViewResolver viewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
web.xml 配置类
//初始化类,代替 web.xml
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* //设置 Spring 的配置类
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringIOC.class};
}
//设置 Spring MVC 的配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebMVC.class};
}
//为 DispatcherServlet 指定映射规则,相当于 web.xml 中配置的 url-pattern
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
//添加过滤器
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceRequestEncoding(true);
encodingFilter.setForceResponseEncoding(true);
HiddenHttpMethodFilter httpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[] {encodingFilter,httpMethodFilter};
}
}
测试
注释掉 web.xml 文件代码,重启Tomcat访问,访问路径成功。
11.19 springmvc配置文件
11.19.1 xml配置
pom依赖
<?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.example</groupId>
<artifactId>Springmvc</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Springmvc</name>
<!-- 打包方式war-->
<packaging>war</packaging>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<junit.version>5.7.0</junit.version>
</properties>
<dependencies>
<!-- javaweb servlet 的核心依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- 单元测试5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- springmvc 依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.20</version>
</dependency>
<!--导入JSON处理工具包 给springmvc提供返回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>
<!--文件上传相关依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<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>
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">
<!-- 配置springmvc的监听器 用于监听spring容器-->
<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>
<!-- dispatcherServlet是springmvc的核心servlet,它负责接收客户端发送来的所有请求-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置 dispatcherServlet 的初始化参数 contextConfigLocation 参数名称是固定的-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!-- servlet 的加载级别,数字越小级别越大,0 为按需加载-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- dispatcherServlet的请求映射路径-->
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- / 拦截所有请求,不包括 .jsp
/* 拦截所有请求,包括 .jsp 使用 会报404错误
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
</web-app>
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置springmvc 扫描路径,这里只扫描 控制器 controller的包-->
<context:component-scan base-package="com.example.Springmvc.controller"/>
<!-- 开启mvc注解 使@RequestMapping 生效-->
<mvc:annotation-driven/>
<!--让springmvc 过滤静态资源-->
<mvc:default-servlet-handler/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="1"/>
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--配置拦截器-->
<mvc:interceptors>
<!--拦截器 1-->
<mvc:interceptor>
<!--配置拦截器拦截的请求路径-->
<mvc:mapping path="/**"/>
<!--配置拦截器不需要拦截的请求路径-->
<mvc:exclude-mapping path="/login"/>
<mvc:exclude-mapping path="/"/>
<!--定义在 <mvc:interceptors> 下,表示拦截器只对指定路径的请求进行拦截-->
<bean class="com.example.Springmvc.controller.MyHandlerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<!-- 视图标签-->
<mvc:view-controller path="/form" view-name="form"/>
<mvc:view-controller path="/upload" view-name="file"/>
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSize" value="1024000"/>
</bean>
</beans>
spring-ioc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 如果不开启注解方式配置ioc,则在该文件定义bean对象-->
<!-- 开启组件扫描-->
<context:component-scan base-package="com.example.Springmvc">
<!-- 排除控制器@Controller组件不扫描-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
11.19.2 注解配置
pom
<?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.example</groupId>
<artifactId>Springmvc</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Springmvc</name>
<!-- 打包方式war-->
<packaging>war</packaging>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<junit.version>5.7.0</junit.version>
</properties>
<dependencies>
<!-- javaweb servlet 的核心依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- 单元测试5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- springmvc 依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.20</version>
</dependency>
<!--导入JSON处理工具包 给springmvc提供返回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>
<!--文件上传相关依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<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>
配置类 替换 web.xml
//初始化类,代替 web.xml
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* //设置 Spring ioc 的配置类
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringIOC.class};
}
//设置 Spring MVC 的配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebMVC.class};
}
//为 DispatcherServlet 指定映射规则,相当于 web.xml 中配置的 url-pattern
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
//添加过滤器
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceRequestEncoding(true);
encodingFilter.setForceResponseEncoding(true);
HiddenHttpMethodFilter httpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[] {encodingFilter,httpMethodFilter};
}
}
配置类 替换 springmvc.xml
@Configuration
@ComponentScan
@EnableWebMvc // 开启spring注解支持 等同 <mvc:annotation-driven/>
public class WebMVC implements WebMvcConfigurer {
/**
* 开启静态资源过滤
* 等同 <mvc:default-servlet-handler/>
* @param configurer
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
/**
* 添加拦截器
* 等同 <mvc:interceptors/> 标签
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/he").excludePathPatterns("/hello");
}
/**
* 视图控制器
* 等同 <mvc:view-controller path="/upload" view-name="file"/>
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/upload").setViewName("file");
}
/**
* 视图解析器
*
* @return
*/
@Bean
public InternalResourceViewResolver viewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
配置类 替换 springioc.xml
@Configuration
public class SpringIOC {
@Bean
public HelloController helloController(){
return new HelloController();
}
}
11.20 总结
springmvc的由来是吸收了javaee中的servlet的技术,并把它与自身的技术框架相融合。
springmvc最核心的是DispatcherServlet这个类,它负责springmvc项目的所有请求,所有的请求都会经过它,并通过它调用相应的处理器进行处理。
springmvc的优点
** 与javaweb的servlet相比**
1 springmvc的一个控制器类,能处理多个请求(增删改查);
2 与ioc、aop无缝融合,脱离复杂类关系的管理烦恼;
3 支持RESTful风格的URL路径;
4 支持不同类型的数据格式返回,如 返回json格式;
5 视图与模型解耦;
6 支持自定义异常处理;
7 提供请求参数类型自动转换并绑定到控制器方法参数上;
8 内部拦截器对控制器方法进行预处理。