Spring MVC
1. Servlet
Servlet(Server Applet)
Servlet是SUN公司提供的一门用于开发动态WEB资源的技术。Servlet是一个接口,用户若想开发一个根浏览器交互的程序,那么服务端的Java类需要实现Servlet接口。通常情况下,我们说的Servlet是实现了Servlet接口的Java类。
JavaWeb三大核心组件:Servlet(拦截器)、Filter(过滤器)、Listener(监听器)。
1.1. Servlet
Servlet是用来处理客户端请求的动态资源,它的任务有:接收请求、处理请求、完成响应。
Servlet的生命周期:Servlet可以在第一次接收请求时被创建,也可以在在服务器启动时就被创建,在web.xml中配置<load-on-startup>1</load-on-startup>
,即可做到随容器启动时被创建。
生命周期方法:init()
、service()
、destroy()
。在HttpServlet中,在service()
方法里对请求类型做了判断,根据不同请求类型,交给具体Servlet的具体方法,比如doGet还是doPost。
1.2. Filter
Filter与Servlet在很多的方面极其相似,例如Filter和Servlet一样都又三个生命周期方法,同时他们在web.xml中的配置文件也是差不多的;但是两者目的不同,Servlet主要负责处理请求,而Filter主要负责拦截请求。Filter的拦截方式可以分为两大类:请求路径拦截(URL),和请求方式(DispatcherType)拦截。当然请求方式要配合请求路径。
经典用途:过滤字符编码(org.Springframework.web.filter.CharacterEncodingFilter)
1.3. Listener
事件源:被监听的对象 ----- 三个域对象 request(ServletRequest
,请求)、 session(HttpSession
,对象感知)、servletContext(ServletContext
,生命周期)。
生命周期监听器ServletContextListener
:实现了javax.servlet.ServletContextListener
接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。项目启动时,先启动监听器,再启动过滤器。
1.4. 拦截器
拦截器是在面向切面编程中的一种应用。
在Spring MVC中,定义拦截器要实现HandlerInterceptor
接口
过滤器和拦截器的区别:
1、拦截器是基于Java的反射机制的,而过滤器是基于函数回调
2、过滤器依赖与Servlet容器,而拦截器不依赖与Servlet容器
3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能
5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
2. Spring MVC
2.1. DispacherServlet
它是一个普通的Servlet,继承自
HttpServlet
。但它又有特殊作用,它负责接收用户的请求,并将请求交给具体的控制器处理,因此它叫做中央调度器,也叫前端控制器。
DispatcherServlet
为何要配置成随服务器启动时加载?
因为DispatcherServlet
在创建的过程中,会同时创建 Spring MVC 容器对象,读取 Spring MVC 配置文件,把配置文件中的配置都创建好,这样当用户发起请求时就可以直接使用对象了。
在web.xml中注册DispatcherServlet
时要注意指定DispatcherServlet
要读取的配置的目录,因为它默认的读取目录是\WEB-INF\<servlet-name>-servlet.xml
的文件,这种方式不够灵活,可以自定义配置文件目录:
<init-param>
<param>contextConfigLocation</param>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
url-pattern的配置方式有两种,扩展名和斜杠。
比如:1. *.do; *.action等等;2. "/"
2.2. Spring MVC 请求流程
浏览器请求 -> tomcat -> DispacherServlet (读取Spring MVC配置文件)- > 前端控制器将请求转发给具体Controller。
视图解析器:InternalResourceViewResolver
接受用户提交的参数:HttpServletRequest
, HttpServletResponse
DispacherServlet
:
- 创建
WebApplicationContext
对象,读取配置文件,进而创建控制器对象 - 它是一个Servlet,接收用户请求,显示处理结果
接收对象参数:当方法的参数过多时,难免会用到用一个对象,当这个对象是标准的JavaBean格式时,框架会自动把提交的参数构建成对象,前提是,对象的属性名跟参数名一致,框架调的是set方法给对象属性赋值。
控制器中方法返回值类型:
-
ModelAndView
:有视图和数据,对视图执行forward -
String
:表示视图,可以是逻辑名称,也可以是完整视图路径 -
void
:不能表示数据,也不能表示视图。在处理ajax的时候可以使用void返回值,通过HttpServletResponse
输出数据。响应ajax请求。 -
Object
:对象属性就是数据,和视图无关。主要是返回json格式数据,做法:
- 加入json工具库依赖,Spring MVC默认使用jackson。
- 配置文件中加入
<mvc:annotation-driven>
注解驱动 - 方法加上
@ResponseBody
原理:
-
<mvc:annotation-driven>
注解驱动。注解驱动实现的功能是完成json、xml、text、二进制等数据格式的转换。相关接口时:HTTPMessageConverter:消息转换器,它的功能是定义了Java转为json,xml等数据格式的方法。这个接口有多个实现类。这些实现类完成了Java对象到json、到xml、到二进制数据的转换。 -
HTTPMessageConverter拥有众多的实现类来完成Java对象对不同格式数据的转换,其中比较常用的有:
StringHttpMessageConverter
、MappingJackson2HttpMessageConverter
。注解驱动在容器启动时会创建HTTPMessageConverter的多个实现类,包括上面说的两个。
2.3. 关于静态资源访问的问题
我们访问服务器上的任何资源,都是通过请求来实现的,请求就是一个URL,对于Tomcat而言最终都会交给servlet来处理。我们访问服务器上的静态资源的时候,它有一个默认的servlet:DefaultServlet
,它就是用来处理静态资源的,它的url-pattern配置的是“/”,它是用来处理任何没被映射到的请求。
这也是中央调度器的url-pattern是不能配置成“/”的原因,因为中央调度器没有处理静态资源的能力。
处理方案一:<mvc: default-servlet-handler/>
配置文件加入标签:
<mvc: default-servlet-handler/>
原理是,框架会帮我们创建一个servlet,她可以把接受的请求转发给Tomcat的DefaultServlet.
处理方案二:<mvc: resources/>
Spring专门定义了用于处理静态资源的处理器:ResourceHttpRequestHandler
。
<mvc:resources location="/images/" mapping="/images/**" />
这种方式的好处是不依赖于Tomcat。
2.4. 框架整合
Spring MVC容器是Spring容器的子容器,类似Java中的继承,在子容器中的Controller可以访问父容器中的Service对象,就可以实现Controller使用Service对象。
Spring MVC核心技术:拦截器、异常处理器、请求重定向和转发
1.异常处理
Spring MVC区全局异常捕获有两种方式,一种是实现HandlerExceptionResolver
,一种是用注解。
Spring MVC框架的处理异常的常用方式:@ExceptionHandler
Spring MVC将Controller中的所有异常统一在一个类中处理,思想就是AOP,叫统一全局异常处理。
相关注解:@ExceptionHandler
,@ControllerAdvice
做法:创建一个Java类作为全局异常处理类,
- 在类上加入
@ControllerAdvice
; - 在方法上加入
@ExceptionHandler
- 在配置文件中申明组件扫描器,申明注解驱动
异常类注解用法:
@ControllerAdvice
public class GlobalExceptionResolver {
/**
* 处理所有不可知异常
* @param e 异常
* @return json结果
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public ApiResult handleException(Exception e) {
LOG.error(e.getMessage(), e);
return ApiResult.of(ResultCode.UNKNOWN_ERROR);
}
/**
* 处理所有业务异常
* @param e 业务异常
* @return json结果
*/
@ExceptionHandler(BusinessRuntimeException.class)
@ResponseBody
public ApiResult handleOpdRuntimeException(BusinessRuntimeException e) {
LOG.error(e.getMsg());
return ApiResult.of(e.getResultCode());
}
}
缺点就是,针对不同的异常要用不同的方法
2.拦截器
需要实现HandlerInterceptor接口。
拦截器和过滤器类似,功能侧重点不同。过滤器用来过滤请求参数,设置编码字符集等工作;拦截器是拦截用户请求,做请求的判断。拦截器是全局的,可以对多个Controller做拦截,拦截器常用在用户登录、权限检查,记录日志。
使用:实现HandlerInterceptor接口;在配置文件中注入拦截器,并申明拦截的URL
/代表跟路径,/**代表所有请求都会被拦截。
可以申明多个拦截器,这些拦截器在解析时会被存入一个ArrayLsit,执行顺序是申明的顺序。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean classs="com.test.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
拦截器主要执行preHandle方法,通过preHandle的返回值决定请求是否继续执行。
多个拦截器问题
拦截器会依次执行
2.5. Spring MVC执行流程
-
浏览器发起请求`
-
DispatcherServlet接受请求
-
中央调度器把请求转交给处理器映射器HandlerMapping
HandlerMapping是一个接口,它有一个方法:
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
就是把请求存入
HandlerExecutionChain
这个类中保存 -
中央调度器把处理器对象交给处理器适配器HandlerAdapter对象
HandlerAdapter的作用是执行Controller中的方法
-
Controller如果返回的是ModelAndView对象,中央调度器就把ModelAndView对象交给视图解析器
-
视图解析器会创建View对象,中央调度器根据View对象生成具体视图。
DispatcherServlet
的核心方法:doDispatch
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验