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:

  1. 创建WebApplicationContext对象,读取配置文件,进而创建控制器对象
  2. 它是一个Servlet,接收用户请求,显示处理结果

接收对象参数:当方法的参数过多时,难免会用到用一个对象,当这个对象是标准的JavaBean格式时,框架会自动把提交的参数构建成对象,前提是,对象的属性名跟参数名一致,框架调的是set方法给对象属性赋值。

控制器中方法返回值类型:

  1. ModelAndView:有视图和数据,对视图执行forward

  2. String:表示视图,可以是逻辑名称,也可以是完整视图路径

  3. void:不能表示数据,也不能表示视图。在处理ajax的时候可以使用void返回值,通过HttpServletResponse输出数据。响应ajax请求。

  4. Object:对象属性就是数据,和视图无关。主要是返回json格式数据,

    做法:

    1. 加入json工具库依赖,Spring MVC默认使用jackson。
    2. 配置文件中加入<mvc:annotation-driven>注解驱动
    3. 方法加上@ResponseBody

    原理:

    1. <mvc:annotation-driven>注解驱动。注解驱动实现的功能是完成json、xml、text、二进制等数据格式的转换。相关接口时:HTTPMessageConverter:消息转换器,它的功能是定义了Java转为json,xml等数据格式的方法。这个接口有多个实现类。这些实现类完成了Java对象到json、到xml、到二进制数据的转换。

    2. HTTPMessageConverter拥有众多的实现类来完成Java对象对不同格式数据的转换,其中比较常用的有:StringHttpMessageConverterMappingJackson2HttpMessageConverter

      注解驱动在容器启动时会创建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类作为全局异常处理类,

  1. 在类上加入@ControllerAdvice
  2. 在方法上加入@ExceptionHandler
  3. 在配置文件中申明组件扫描器,申明注解驱动

异常类注解用法:

@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执行流程

  1. 浏览器发起请求`

  2. DispatcherServlet接受请求

  3. 中央调度器把请求转交给处理器映射器HandlerMapping

    HandlerMapping是一个接口,它有一个方法:

    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
    

    就是把请求存入HandlerExecutionChain这个类中保存

  4. 中央调度器把处理器对象交给处理器适配器HandlerAdapter对象

    HandlerAdapter的作用是执行Controller中的方法

  5. Controller如果返回的是ModelAndView对象,中央调度器就把ModelAndView对象交给视图解析器

  6. 视图解析器会创建View对象,中央调度器根据View对象生成具体视图。

DispatcherServlet的核心方法:doDispatch

posted @   yfhu  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
点击右上角即可分享
微信分享提示