SpringMVC了解

1.springMVC概述

        Spring MVC(Model-View-Controller)是基于 Java 的 Web 应用程序框架,用于开发 Web 应用程序。它通过将应用程序分为模型(Model)、视图(View)和控制器(Controller)三个部分来帮助开发人员实现清晰的代码结构和逻辑分离。概念本质:MVC思想,分层工作模式

  模型(Model)负责封装应用程序的业务逻辑和数据   由service、dao、entityJavaBean构成
  视图(View)负责展示用户界面        由jsp、html、ftl....等组成
  控制器(Controller)负责处理用户请求、调用业务逻辑并根据结果选择合适的视图进行展示。

        早期的servlet开发,不划分模块,代码堆积在少量的不同包下,学了SpringMVC,慢慢适应对功能等按不同规则划分模块,层次。

        SpringMVC设计本质:请求作为驱动。前端控制器/DispatcherServlet(核心)接收所有请求,并根据请求的信息将请求 路由/分发 到合适的 Controller 进行处理。根据返回数据DispatcherServlet 还负责调用其他组件 处理视图解析、异常处理、拦截器等功能。

2.SpringMVC使用方式

        现在流行SpringBoot,省去很多配置,但是是开发者对 application.yml中很多技术栈的配置项也并不是特别理解。大多数是复制 他人的配置,会用但不知道使用原因。这时有时间单独对Spring、SpringMVC、Mybatis、Shiro等了解下。

        2.1SpringMVC的核心配置文件

配置SpringMVC的核心文件: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"
       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
		http://www.springframework.org/schema/context/spring-context-4.3.xsd 
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
    <!-- 通过context:component-scan元素扫描指定包下的控制器-->
    <!-- 扫描com.xxx.xxx及子孙包下的控制器(扫描范围过大,耗时)-->
    <context:component-scan base-package="com.xxx.controller"/>
    
    <!-- ViewResolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- viewClass需要在pom中引入两个包:standard.jar and jstl.jar -->
        <property name="viewClass"
                  value="org.springframework.web.servlet.view.JstlView"></property>
<!--前缀-->       
 <property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
    
    <!-- 省略其他配置...... -->
</beans>

总结:1.配置包扫描—Controller类所在的路径 2.配置视图解析器

2.2web项目核心文件web.xml配置

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>WebTest</display-name>

  <!-- 再这里会添加一个SpringMVC的servlet配置项 -->
  <servlet>
  <!-- 首先指定SpringMVC核心控制器所在的位置 -->
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- DispatcherServlet启动时,springmvc配置文件加载路径
    此参数可以不配置,默认值为:/WEB-INF/springmvc-servlet.xml
    可以改为加载类路径下(resources目录),加上classpath:
     -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
     <!-- <param-value>/WEB-INF/springmvc-servlet.xml</param-value> -->
	    <param-value>classpath:springmvc.xml</param-value>
    </init-param>
	<!--
        DispatcherServlet对象创建时间问题
		  1)默认情况下,第一次访问该Servlet的创建对象,意味着在这个时间才去加载springMVC.xml
		  2)可以改变为在项目启动时候就创建该Servlet,提高用户访问体验。
		      <load-on-startup>1</load-on-startup>
		      数值越大,对象创建优先级越低! (数值越低,越先创建)
		-->
    <load-on-startup>1</load-on-startup>
    <!--web.xml 3.0的新特性,是否支持异步-->
    <!--<async-supported>true</async-supported>-->
  </servlet>
  <!-- 配置路由匹配规则,/ 代表匹配所有,类似于nginx的location规则 -->
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

总结:web.xml中针对SpringMVC做了一件事。加一个servlet配置。1.指定DispatcherServlet类的全路径 2.DispatcherServlet启动时,从哪个文件中加载组件的初始化信息 3.配置了路由规则  / 拦截请求的规则 此处除了.jsp都会拦截

        2.3配置Controller类

@RestController()
@Api(tags = "Test相关操作")
@Slf4j
public class TestController {

 @GetMapping("/v1/test")
 @ApiOperation(value = "test功能描述", produces = "application/x-www-form-urlencoded")
 public String testProcess (final String id) {
     System.out.println(id);
     retun id;
}

发送对应请求即可—— http://localhost:8080/v1/test

梳理:

  1. DispatcherServlet接收到URL请求/v1/test,结合@GetMapping(“/v1/test”)注解把该请求交给testProcess 业务方法进行处理
  2. 执行testProcess 业务方法,控制台打印日志,并且返回参数id字符串(逻辑视图). 
  3. 结合springmvc.xml中的视图解析器配置,找到目标资源:/id.jsp,即/WEB-INF/jsp/目录下的id.jsp文件,把该JSP资源返回给客户端完成响应。假设参数id为13,则13.jsp资源返给客户端

        一般都会将WEB应用打成war包,然后放入到Tomcat中运行,而当Tomcat启动时,首先会找到对应的WEB程序,紧接着会去加载web.xml,加载web.xml时,由于配置了DispatcherServlet,所以此时会先去加载DispatcherServlet,而加载这个类时,又会触发它的初始化方法,会调用initStrategies()方法对组件进行初始化,如下:

	/**
	 * This implementation calls {@link #initStrategies}.
	 */
	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	/**
	 *    初始化此 servlet 使用的策略对象。
     *    可以在子类中重写,以便初始化进一步的策略对象
     *    各大组件的初始化
	 */
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
    }
	

但是初始化的组件需要改东西,或者说加载一些配置信息,可由  <init-param> 中的  <param-value>classpath:springmvc.xml</param-value>,读取配置信息,对各大组件初始化。

        注意:通过配置 contextConfigLocation 参数,开发者可以灵活地指定 DispatcherServlet 的应用程序上下文配置文件,从而实现对 DispatcherServlet 的定制和配置。

3.SpringMVC工作原理

        3.1一些常用组件介绍:主为前五点

  1. DispatcherServlet前端控制器        统一处理接收请求,响应结果。是整个流程控制的中心,由它调用其它组件处理用户的请求   程序员不需要开发
  2. HandlerMapping处理映射器      框架提供,处理器映射器会对用户的请求进行处理,处理成Handler。并将其封装为处理器执行链 返回 (HandlerExecutionChain) 给前端控制器SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。 映射到对应、符合的Controller(处理器)   程序员不需要开发
  3. HandlerAdapter处理适配器      一个用于执行Handler处理器 的组件,将Handler处理成ModelAndView逻辑视图,并返给前端控制器。 调用具体的Controller(处理器)处理     程序员不需要开发
  4. Handler处理器       处理请求业务逻辑,在SpringMVC中会被包装成一个Handler对象。 默认为controller,其实还包括【HandlerInterceptor/拦截器、HandlerMethodReturnValueHandler /处理 Controller 方法的返回值】   等  程序员开发如controller
  5. ViewResolver视图解析器:   前端控制器会将ModelAndView交给视图解析器进行进一步解析,最终解析成视图进行渲染。比如controller方法执行完成之后,return的值是index,那么会对这个结果进行解析,将结果生成例如index.jsp这类的View视图。  程序员不需要开发
  6. View视图     ViewSpringMVC中是一个接口,实现类支持不同的类型,例如jsp、freemarker、ftl...现在一般都是前后端分离的项目,因此也很少再用到这块内容,视图。一般都成了html页面,数据结果的渲染工作也交给了前端完成    程序员开发jsp页面  

 3.2流程图例展示(图为截取其他)

         观察如上流程,SpringMVC中的其他组件几乎不存在太多的耦合关系,大部分的工作都是由DispatcherServlet来调度组件完成的,因此这也是它被称为“中央控制器”的原因,DispatcherServlet本质上并不会处理用户请求,它仅仅是作为请求统一的访问点,负责请求处理时的全局流程控制。

执行流程如下:(图为截取其他) 

4.为什么不用配置多数组件呢?—DispatcherServlet 的默认配置

大概解释:因为DispatcherServlet会读取属性文件——DispatcherServlet.properties 

 详细解释:以DispatcherServlet中初始化方法  initStrategies 中调用的  initHandlerMappings(context);作为案例

1.private List<HandlerMapping> handlerMappings; 没有配置就是为null,则关注getDefaultStrategies方法

 2.看图4.1

DispatcherServlet中有个静态属性  private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

图中  1.读取属性文件【DispatcherServlet.properties】得到      private static Properties defaultStrategies的具体值。
        2.3.通过参数strategyInterface的getName()方法 获取到全路径名  key="org.springframework.web.servlet.HandlerMapping";
        defaultStrategies.getProperty(key)得到读取的属性文件中对应的值 value。(下属第二张图4.2)
        4.创建集合 List<T>strategies,根据循环将 有value转换的String[]className解析到strategies中。(里面存的HandlerMapping类型

        5.返回集合strategies  结束。获取HandlerMapping的过程

图4.1

 图4.2

5.SpringMVC请求重定向和转发

  1. 请求重定向(Redirect):

    • 重定向是通过向客户端发送一个特殊的响应(HTTP 302 Found)来告诉客户端去请求另一个 URL。
    • 重定向会导致客户端发起一个新的请求,并且地址栏会显示跳转后的新 URL。
    • 重定向是一种完全的客户端行为,服务器收到请求后会返回一个重定向状态码,客户端会重新请求新的 URL。
    • Spring MVC 中,可以通过 redirect: 前缀来实现重定向,例如:return "redirect:/newUrl"
    • 原生的 Servlet 开发中,实现 response.sendRedirect("xxx.jsp")
  2. 请求转发(Forward):

    • 转发是在服务器端进行的操作,浏览器端 / 客户端  不会感知到地址的变化
    • Spring MVC 中,可以通过 forward: 前缀来实现请求转发,例如:return "forward:/newUrl"
    • 原生的 Servlet 开发中,实现request.getRequestDispatcher("xx.jsp").forward()

注意:1.对于请求转发的页面,可以是WEB-INF中页面【服务器访问】;而重定向的页面,是不能为WEB-INF 中页的。因为重定向相当于用户再次发出一次请求,而用户/浏览器是不能直接访问 WEB-INF 中资源的。【安全性高】

           2.指定的视图前添加 forward:,且此时的视图不再与视图解析器一同工作

在使用重定向和转发时,需要根据具体的需求和场景来选择合适的方式:

  • 如果需要跳转到一个完全不同的 URL 地址,或者需要避免表单重复提交等情况,通常会选择重定向。
  • 如果只是希望在服务器内部完成请求的转发,不想让客户端感知到地址的变化,通常会选择转发。

6.SpringMVC异常处理

  1. 使用 @ControllerAdvice 注解:图6.1

    • @ControllerAdvice 注解可以定义一个全局的异常处理类,用于处理 Controller 层中抛出的异常 。 【service抛出异常,controller调用了service,也能捕获处理】
    • 在这个类中,可以使用 @ExceptionHandler 注解定义多个方法,每个方法处理不同类型的异常。
    • 当 Controller 层中抛出异常时,Spring MVC 会自动寻找合适的异常处理方法,并执行该方法处理异常。
  2. 实现 HandlerExceptionResolver 接口:图6.2

    • HandlerExceptionResolver 接口是 Spring MVC 中的异常解析器,它可以用于处理所有的异常情况。
    • 实现这个接口需要重写其中的 resolveException 方法,根据具体的异常类型进行处理。
    • 在 Spring MVC 中,如果有多个异常解析器,则会按照顺序依次执行,直到找到一个能够处理异常的解析器为止。
  3. 在 Controller 层中使用 @ExceptionHandler 注解:图6.3

    • @ExceptionHandler 注解可以用于在 Controller 层中定义异常处理方法,用于处理当前 Controller 中抛出的异常。
    • 这种方式比较适合处理一些特定的异常,例如表单验证失败等。

 图6.1

图6.2 

图6.3 

7.SpringMVC拦截器

7.1拦截器介绍

         Interceptor 拦截器是非常重要的,它的主要作用是拦截指定的用户请求,并进行相应的预处理后处理
常见应用场景
1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等 预处理、后处理
2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;预处理
3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录)后处理 或 afterCompletion方法;

public class MyInterceptor implements HandlerInterceptor {

    @Override//预处理回调方法
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("进入controller前拦截 " + request.getRequestURI());
        return true; // 返回 true 表示继续执行后续流程,返回 false 表示终止执行后续流程
    }

    @Override//后处理回调方法
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Controller 方法调用之后被调用,但是会在视图返回被渲染之前被调用 " + request.getRequestURI());
//代码中在controller执行之后,但是返回modelAndView之前执行
    }

    @Override//整个请求处理完毕回调方法
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("视图渲染完毕时回调: " + request.getRequestURI());
//性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally
    }
}

注意:1.preHandle预处理方法返回true,才会放行,而执行postHandle、afterCompletion方法        2.拦截器就是实现HandlerInterceptor这个接口,然后去重写它里面preHandle,postHandle和afterCompletion这三个方法        3.afterCompletion 方法中,请求处理已经完成,响应已经返回给客户端。对 ModelAndView 再操作也对响应无济于事【在 DispatcherServlet 完全处理请求后被调用】        4.如果需要在拦截器中对 ModelAndView 进行修改,通常应该在 preHandlepostHandle 方法中进行。preHandle 方法中可以修改 ModelAndView 中的模型数据,而在 postHandle 方法中可以修改视图名称等信息。        5.当 preHandle()方法返回 false 时,使用 request 或 response 对请求进行响应 如:请求转发或重定向到登录页面,error错误信息页面。

图解7.1

总结:preHandle——》Handle(Controller)——》postHandle——》afterCompletion

7.2多个拦截器执行顺序

        当有多个拦截器时,形成拦截器链。拦截器链的执行顺序,与其注册顺序一致【从上往下看】。需要再次强调一点的是,当某一个拦截器的 preHandle()方法返回 true 并被执行到时,会向一个专门的方法栈中放入该拦截器的 afterCompletion()方法 

图解7.2       

注意:绿色为一个完整MyInterceptor,橙黄色为另一个完整MyInterceptor2。

重点关注:第一个拦截器的 preHandle 方法返回 true,而第二个拦截器的 preHandle 方法返回 false,整个拦截器链会被中断,目标处理器(Controller)的方法不会被执行但是,第一个拦截器的 afterCompletion 方法会被调用

总结:无论执行链执行情况怎样,只要方法栈中有方法,即执行链中只要有 preHandle()方法返回 true就会执行方法栈中的afterCompletion()方法

7.3执行流程图(截图其他)

8.过滤器和拦截器、servlet执行顺序

8.1大致图

 8.2细节图解

9.SpringMVC的执行流程

深度剖析SpringMVC的执行流程,看完帮你立即提升一个台阶! - 知乎

10.其余参考资料:
【SSM】Spring MVC 程序开发(重点:SpringMVC 工作流程) - 知乎 (zhihu.com)

Spring MVC详解(学习总结)_springmvc技能经验描述-CSDN博客

过滤器,拦截器,监听器的区别 - Rooker - 博客园 (cnblogs.com) 

  • 19
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值