2024-11-21-Thu-T-SpringMVC
SpringMVC
1 SpringMVC 简介
MVC是一种软件架构思想, 将软件按照模型、视图、控制器来划分
M: Model : 模型层, 指工程中的Java Bean, 作用是处理数据
Java Bean分为两类:
- 实体类Bean: 专门存储业务数据的, 比如User, Student
- 业务处理Bean: 指Service或者Dao, 专门用于处理业务逻辑和数据访问
V: View :视图层, 指工程中html或sp等页面, 作用是与用户进行交互, 展示数据
C: Controller : 控制层, 指工程中的servlet, 作用是接受请求和响应浏览器
SpringMVC是一个Spring的子项目, SpringMVC有如下特点:
- Spring系列原生产品, 与IOC容器等基础设施无缝对接
- 基于原生的Servlet, 通过功能强大的前端控制器DispatcherServlet, 对请求和响应进行统一处理
- 表述层各细分领域需要解决的问题全方面覆盖, 提供全面解决方案
- 代码清晰简洁、组件化程度高、可插拔式组件即插即用、性能卓越..
2. HelloWorld
2.1准备工作
- 添加模块
- 打包方式war
- 引入依赖
<!--SpringMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.1.13</version>
</dependency>
<!--日志-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.12</version>
</dependency>
<!--ServletAPI Tomcat中会自带此包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
<!--依赖由运行环境(例如容器或框架)提供的库,比如 servlet-api(在 Servlet 容器中运行时由容器提供)。-->
</dependency>
<!--Spring5和Thymeleaf整合包-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring6</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
- 在main目录下创建
webapp目录 - 载project structure中的module中添加web.xml(注意路径应该在webapp目录下)
2.2 配置web.xml
注册SpringMVC的前端控制器DispatcherServlet,
- 默认配置方式
此配置作用下, SpringMVC的配置文件默认位于WEB-INF下, 默认名为<servlet-name>-servlet.xml, 例如, 以下配置对应的SpringMVC的配置文件位于WEB-INF下, 文件名为springMVC-servlet.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>
<url-pattern>/</url-pattern>
<!--"/"包括除了.jsp之外的所有请求(.jsp本质是一个servlet, 需要由特定的servlet处理器处理-->
</servlet-mapping>
- 扩展配置方式(常用)
可通过init-param标签设置SpringMVC配置文件的位置和名称, 通过load-on-startup标签设置SpringMVC前端控制器DispatcherServlet
<!-- 前端控制器 -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 选择spring容器管理文件 管理mvc-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!-- 加载方式 程序运行时-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!-- 访问请求 / 接受所有请求 不包括.jps请求拒接 /* 接受所有请求 包括.jsp-->
<url-pattern>/</url-pattern>
</servlet-mapping>
2.3 创建请求控制器
由于前端控制器对浏览器发出的请求进行了统一的处理, 但是具体的请求有不同的处理过程, 因此需要创建处理具体请求的类, 即请求控制器
请求控制器中每一个处理请求的方法都成为控制器方法.
因为SpringMVC的控制器由一个POJO(普通的java类plain old java object)担任, 因此需要通过@Controller注解将其标识为一个控制层组件, 交给Spring ioc容器进行管理. 此时SpringMVC才能识别出控制器的存在.
@Controller
public void HelloWorld(){
@RequestMapping(value = "/")
public String index(){
//返回视图名称
return "index";
}
}
2.4 创建springMVC.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
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 上下文包 组件 扫描-->
<context:component-scan base-package="com.learning.mvc.controller"/>
<!-- 视图解析器-->
<bean id="springResourceTemplateResolver" class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring6.SpringTemplateEngine">
<property name="templateResolver" ref="springResourceTemplateResolver"/>
</bean>
<bean id="viewResolver" class="org.thymeleaf.spring6.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine" ref="templateEngine"/>
</bean>
</beans>
2.5 配置tomcat
tomcat10

3. 核心内容
3.1 @RequestMapping注解
@RequestMapping的作用就是将请求和处理请求的控制器关联起来, 建立映射关系
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
@Reflective({ControllerMappingReflectiveProcessor.class})
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
3.1.1 @RequestMapping注解的位置
- 标识一个类: 设置请求路径的主路径
- 标识一个方法: 设置请求路径的子路径
3.1.2 @RequestMapping注解的value属性
-
value属性通过请求地址匹配请求映射
-
value属性是一个字符串数组, 标识其可以进行多个路径匹配
-
value属性必须设置, 不能缺少
3.1.3 @RequestMapping注解的method属性
@RequestMapping注解的method属性通过请求的请求方式(get、post等)匹配请求路径
@RequestMapping的method属性是一个RequestMethod类型的数组
对于处理指定请求方式的控制器方法, SpringMVC提供了@Request Mapping的派生注解:
- @GetMapping
- @PostMapping
- @PutMapping
- @DeleteMapping
3.1.4 @RequestMapping的params属性
@RequestMapping的params参数是一个字符串数组, 可以通过四种表达式设置请求和请求映射的匹配关系
param: 必须携带参数param!param: 只要不携带参数param即可param=value: 必须要参数param等于valueparam!=value: 只要参数param不等于value即可
# 例子
params = {username} # 必须携带username
params = {!username} # 只要不携带username即可
params = {username=zhangsan} # 必须username = zhangsan
params = {username!=zhangsan} # 只要username不等于zhangsan即可
3.1.5 SpringMVC支持ant风格的路径
?: 表示任意的单个字符*: 标识任意的0个或多个字符**: 表示任意的一层或多层目录- 注意: 使用
**时, 只能使用/**/xxx的方式
3.1.6 SpringMVC支持路径中的占位符(重点)
- 原始方式:
/deleteUser?id=1(面向操作) - Restful方式:
/deleteUser/1(面向资源, 更易理解)
@RequestMapping("/test/{id}/{username}")
public User getUser(@PathVariable("id") String id, @PathVariable String username){
return new User(id, username);
}
3.2 SpringMVC获取请求参数
3.2.1 @RequestParam
//一般不使用此方式
@RequestMapping("/test")
public User getUser(HttpServletRequest request){
String name = request.getParameter("username");
String password = request.getParameter("id");
return new User(name,password);
}
//SpringMVC方式
// 1. 默认情况
//保证形参名与请求参数中的名字一样, 比如此案例中应该为 /testParam?username=zs&password=123
//对于多个相同的参数名, 可以使用数组接收
@RequestMapping(value = "/testParam")
public String testParam(String username, String password){
return "success";
}
//2. 使用@RequestParam注解
@RequestMapping(value = "/testParam")
public String testParam(@RequestParam("username") String username, @RequestParam("password") String password){
return "success";
}
3.2.2 @RequestHeader
@RequestHeader是将请求头信息和控制器方法的形参创建映射关系
@RequestHeader注解一共有三个属性: value, required, defaultValue, 用法与@RequestParam一样
3.2.3 @CookieValue
@CookieValue是将cookie数据和控制器方法的形参创建映射关系
三个属性与@RequestParam一样
3.2.4 通过POJO获取请求参数
在控制器方法的形参位置设置一个实体的类型的形参, 浏览器请求的参数与该实体内属性一致, 则参数会自动赋值
3.3 域对象共享数据
域对象 作用范围 生命周期 应用场景
ServletContext: 全局范围 Web 应用启动到销毁 应用配置、全局统计信息HttpSession: 会话范围 用户访问到会话超时或销毁 登录信息、购物车ServletRequest: 请求范围 单个 HTTP 请求处理期间 请求数据、转发共享数据PageContext: 单个 JSP 页面 从 JSP 页面开始执行到处理完成 当前 JSP 页面内部 存储 JSP 页面的临时变量
3.3.1 使用servletAPI向Request域对象共享数据
@RequestMapping("/test")
public String test(HttpServletRequest request){
request.setAttribute("testScope", "Hello");
return "success";
}
3.3.2 使用ModelAndView向request域对象添加数据
@RequestMapping("/testModleAndView")
public ModelAndView testModelAndView(){
/**
* ModelAndView包含model和view功能
* model主要用于向请求域中共享数据
* view主要用于设置视图, 实现页面跳转
*/
ModelAndView modelAndView = new ModelAndView();
//向请求域中共享数据
modelAndView.addObject("msg111", "testModelAndView + " + modelAndView);
//设置视图, 实现页面跳转
modelAndView.setViewName("success");
return modelAndView;
}
3.3.3 使用Model向request域对象共享数据
@RequestMapping("/testModle")
public String testModel(Model model){
model.setAttribute("testScope", "hello");
return "success"
}
3.3.4 使用Map向request域对象共享数据
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
map.put("testScope", "hello");
return "success"
}
3.3.5 使用ModelMap向request域对象共享数据
@RequestMapping("/testModleMap")
public String testModelMap(ModelMap model){
model.setAttribute("testScope", "hello");
return "success"
}
3.3.6 向Session域共享数据
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSession", "hello, session");
return "success";
}
3.3.6 向application域中共享数据
@RequestMapping("/testApp")
public String testApp(HttpSession session){
ServletContext application = session.getServletContext();
application.setAttribute("testApp", "hellp application domain");
return "success";
}
3.4 SpringMVC的视图
SpringMVC的视图是View接口, 视图的作用是渲染数据, 将模型Model中的数据展示给用户
SpringMVC视图的种类有很多, 默认有转发视图InternalResourceView和重定向视图RedirectView
当工程引入jstl的依赖, 转发视图会自动转化为JstlView
3.4.1 ThymeleafView
若使用的视图为Thymeleaf, 在SpringMVC的配置文件中配置了Thymeleaf的视图解析器, 由此视图解析器解析之后所得到的是ThymeleafView
3.4.2 InternalResourceView
SpringMVC中默认的转发视图是InternalResourceView
当控制器方法中所设置的视图名称以“forward:/“为前缀时, 会创建InternalResourceView视图, 此时视图名称不会被SpringMVC配置文件中的所配置的视图解析器解析. 而是通过转发的方式跳转
3.4.3 RedirectView

3.4.4 视图控制器view-controller
当控制器中的方法, 仅仅用来实现页面跳转, 即只需要设置视图名称时, 可以将处理器方法使用view-controller标签进行表示
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<!--配置了view- controller后注解驱动会失效, 需要重新开启-->
<mvc:annotation-driven/>
4. RESTful
REST: Representational State Transfer 表现层资源状态转移
-
资源
处于服务器上一切可以访问的数据都可称为资源 -
资源的表述
资源的表述是一段对于资源在某个特定时刻的状态的描述. 可以理解为数据的格式 -
状态转移
状态转移是系统从一个状态变化到另一个状态的过程。状态(State)是系统在某一时刻的特定条件或配置,而转移(Transition)是由某种事件或条件触发的状态变化。例如: 用户已登陆, 用户未登录
3.1 RESTful的实现
HTTP协议中, 有四个表示对资源的操作动词:
GET:获取资源POST: 新建资源PUT: 更新资源DELETE: 删除资源
RESTful风格提倡URL地址使用统一的风格设计, 从前到后各个单词使用斜杠分开, 不使用问号键值对的方式携带请求参数, 而是将要发送给服务器的数据作为url的一部分, 保证风格一致性

3.2 通过过滤器处理delete和put请求
<!--配置过滤器HiddenHttpMethodFilter-->
<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>
5. SpringMVC执行流程
5.1 SpringMVC常用组件
- DispatcherServlet: 前端控制器, 框架提供,不需要工程师开发. 整个流程控制的中心, 统一处理请求和响应. 由它调用其他组件处理用户的请求
- HandlerMapping: 处理器映射器, 框架提供, 不需要工程师开发. 根据请求的url,method等信息查找Handler, 即控制器方法
- Handler: 处理器,即控制器Controller, 需要工程师开发. 在DispatcherServlet的控制下, Handler对具体的用户请求进行处理
- HandlerAdapter: 处理器适配器, 由框架提供, 不需要工程师开发. 通过HandlerAdapter对控制器方法(处理器)进行执行
- ViewResolver: 视图解析器, 由框架提供, 不需要工程师开发. 进行视图解析, 得到对应的视图
- View: 视图, 不需要工程师开发, 由框架或视图技术提供. 将模型数据通过页面展示给用户
5.2 DispatcherServlet初始化过程
DispatcherServlet本质上是一个Servlet, 所以遵循Servlet的生命周期,
Servlet生命周期
- Servlet 初始化后调用 init () 方法。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 销毁前调用 destroy() 方法。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
5.3 SpringMVC执行流程
- 用户向服务器发起请求, 请求被SpringMVC前端控制器DispatcherServlet捕获
- DispatcherServlet对URL进行解析, 得到请求资源定位符URI, 判断请求URI对应的映射:
- 不存在URI对应映射
- 再判断是否配置了
mvc:default-servlet-handler- 如果没配置, 控制台报映射查找不到, 客户端显示404错误
- 有配置, 则访问目标资源(一般是静态资源, html, js, css). 找不到式客户端会显示404
- 再判断是否配置了
- 存在URI对应映射
- 根据URI, 调用HandlerMapping得到该Handler配置的所有有关对象, 包括控制器和拦截器, 最后以HandlerExecutionChain执行链对象的形式返回
- DispatcherServlet根据的到的Handler, 选择一个合适的HandlerAdapter
- 如果成功或得HandlerAdapter, 开始执行拦截器的preHandler方法
- 提取Request中的模型数据, 填充Handler入参, 开始执行Handler(Controller)方法, 处理请求. 在填充Handler的入参过程中, 根据个人配置, Spring将完成一些额外的工作:
- HttpMessageConvert: 将请求信息(json, xml等)转化为一个对象, 或者将对象转化为对应的响应信息
- 数据转换: 比如String转化为Integer
- 数据格式化: 比如String转化为数字或者日期
- 数据验证: 验证数据有效性(长度, 格式等)
- Handler执行完成后, 向DispatcherServlet返回一个ModleAndView对象
- 此时将开始执行拦截器postHandler()方法
- 根据ModelAndView(如果有异常, 执行Handler ExceptionResolver进行异常处理), 选择一个合适的ViewResovler(普通、forward、redirect)进行视图解析, 根据model和view来渲染视图
- 将渲染结果返回给客户端
- 不存在URI对应映射
6. 注解配置SpringMVC
使用配置类和注解代替web.xml和SpringMVC配置文件功能
6.1 创建初始化类, 代替web.xml
在Servlet3.0中, 容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类, 如果找到的话就用它来配置Servlet容器
Spring提供了这个接口的实现, 名为SpringServletContainerInitializer. 这个类还会查找实现WebApplicationInitializer的类, 并将配置的任务交给他们完成, Spring3.2引入了一个WebApplicationInitializer的实现类, AbstractAnnotationConfigDispatcherServletInitializer.
当我们继承了AbstractAnnotationConfigDispatcherServletInitializer并且将其部署到了Servlet3的容器中时, 容器会自动发现它, 并用它来配置Servlet上下文.
package com.learning.mvc.anno.config;
import jakarta.servlet.Filter;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* Author fei
* Version 1.0
* Description Web工程的初始化类
* 用来代替web.xml
* DATA 2024/11/22 19:04
*/
public class WebXML extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 指定Spring配置类
*
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
/**
* 指定SpringMVC配置类
*
* @return
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
/**
* 指定DispatcherServlet的url- patter
* 指定SpringMVC的映射规则,即url-pattern
*
* @return
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
/**
* 注册过滤器
* @return
*/
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
}
}
6.2 创建SpringMVC配置, 代替SpringMVC.xml
package com.learning.mvc.anno.config;
import com.learning.mvc.anno.controller.TestController;
import com.learning.mvc.anno.interceptor.TestInterceptor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring6.view.ThymeleafViewResolver;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* Author fei
* Version 1.0
* Description 代替SpringMVC配置文件
* 1. 扫描组件
* 2. 视图解析器、3. view-controller, 4. default- servlet-handler: WebMvcConfigurer
* 5. mvc注解驱动 6. 文件上传解析器。7. 异常处理。8. 拦截器
* DATA 2024/11/22 18:52
*/
@Configuration
@ComponentScan("com.learning.mvc.anno")
@EnableWebMvc //5. 开启MVC注解驱动
public class WebConfig implements WebMvcConfigurer {
/**
* 配置default- servlet-handler:
* @param configurer
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
/**
* 8 添加拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**"); //拦截所有
WebMvcConfigurer.super.addInterceptors(registry);
}
/**
* 3. view-controller,
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.html");
}
/**
* 6. 文件上传解析器
* @return
*/
@Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
/**
* 。7. 异常处理。
* @param resolvers
*/
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("java.lang.ArithmeticException", "error");
exceptionResolver.setExceptionMappings(properties);
exceptionResolver.setExceptionAttribute("exception"); // 方便从请求域中获取异常信息
resolvers.add(exceptionResolver);
}
/**
* 配置 thymeleaf视图解析器
* @param templateEngine
* @return
*/
@Bean
public ThymeleafViewResolver thymeleafViewResolver(@Qualifier("springTemplateEngine") SpringTemplateEngine templateEngine) {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setOrder(1);
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
@Bean("springTemplateEngine")
public SpringTemplateEngine templateEngine(@Qualifier("templateResolver") SpringResourceTemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(templateResolver);
return templateEngine;
}
@Bean("templateResolver")
public SpringResourceTemplateResolver springResourceTemplateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
//视图前缀
templateResolver.setPrefix("classpath:/WEB-INF/templates/");
//视图后缀
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
7. 扩展功能
7.1 HttpMessageConverter
HttpMessageConverter, 报文信息转换器, 将请求报文转化为Java对象, 或将java对象转化为响应报文
HttpMessageConverter提供了两个注解和两个类型:
注解:
@RequestBody: 在控制器中设置一个形参, 并使用此注解标识控制器@ResponseBody:标识控制器方法, 可以将该控制器的返回值作为响应体返回给浏览器
类型:RequestEntity: 放入控制器方法的形参中, 当有请求匹配到此控制器中, 则请求体信息会自动注入该形参中ResponseEntity: 用于控制器返回值类型, 就是响应到浏览器的响应报文
@ResponseBody处理json对象需要引入注解才可以让java对象自动转化为json对象
<!--引入json依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.0</version>
</dependency>
@RestController = @Controller + @ResponseBody
@RestController加载控制器的类上, 相当于为类添加了@Controller, 同时为类中每个控制器添加了@ResponseBody
7.2 文件上传和下载
@Controller
public class FileController {
@RequestMapping("/testDown")
public ResponseEntity<byte[]> testDown(HttpSession session) throws IOException {
ServletContext servletContext = session.getServletContext();
String realPath = servletContext.getRealPath("/static/img/a.png");
FileInputStream fileInputStream = new FileInputStream(realPath);
byte[] bytes = new byte[fileInputStream.available()];
fileInputStream.read(bytes);
MultiValueMap<String, String> httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Disposition", "attachment; filename=a.png");
HttpStatus httpStatus = HttpStatus.OK;
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, httpHeaders, httpStatus);
fileInputStream.close();
return responseEntity;
}
}
文件上传需要先引入相关依赖:
<!--文件上传需要的依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
配置bean
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"></bean>
配置解析器
<!-- 前端控制器 -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 选择spring容器管理文件 管理mvc-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!-- 加载方式 程序运行时-->
<load-on-startup>1</load-on-startup>
<multipart-config>
<!-- 上传文件最大为多少 -->
<max-file-size>10485760</max-file-size>
<!-- 最大的请求大小 -->
<max-request-size>10485760</max-request-size>
<!-- 多大以上的文件可以上传 -->
<file-size-threshold>0</file-size-threshold>
</multipart-config>
</servlet>
表单
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form th:action="@{/testUp}" method="post" enctype="multipart/form-data">
图片上传: <input type="file" name="photo">
<input type="submit" value="上传">
</form>
</body>
</html>
控制器
@RequestMapping(value = "/testUp", method = RequestMethod.POST)
public String testUp(@RequestParam("photo") MultipartFile photo, HttpSession session) throws IOException {
System.out.println(photo.getOriginalFilename());
System.out.println(photo.getName());
ServletContext servletContext = session.getServletContext();
String realPath = servletContext.getRealPath("photo");
File file = new File(realPath);
if (!file.exists()) {
file.mkdirs();
}
String finalPath = realPath + File.separator + photo.getOriginalFilename();
photo.transferTo(new File(finalPath));
return "testUP 成功";
}
7.3 拦截器

编写拦截器方法
@Component
public class FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor preHandle");
return false ;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
编写控制器
@Controller
public class HandlerController {
@RequestMapping("/testInterceptor")
public String testInterceptor() {
return "interceptor";
}
}
配置SpringMVC
<!--配置拦截器-->
<mvc:interceptors>
<!--<bean class="com.learning.mvc.rest.interceptor.FirstInterceptor"></bean>-->
<mvc:interceptor>
<mvc:mapping path="/testInterceptor"/>
<ref bean="firstInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
有多个拦截器时

7.4 异常处理器
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口: HandlerExceptionResolver
HandlerExceptionResolver的实现类有:
- DefaultHandlerExceptionResolver SpringMVC默认使用的异常处理器
- SimpleHandlerExceptionResolver: 留给开发人员自定义处理异常
基于配置的异常处理
<!--配置异常处理-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props >
<prop key="java.lang.ArithmeticException">error</prop>
<!-- 将会自动跳转到error的页面 -->
</props>
</property>
</bean>
基于注解的异常处理
@ControllerAdvice
public class ExceptionCatchController2 {
//如果出现相应的异常, 那么就会调用这个controller
@ExceptionHandler(value = {ArithmeticException.class, NullPointerException.class})
public String testExceptionHandler(Exception e) {
return "error";
}
}

浙公网安备 33010602011771号