• scope 设置为provide则服务器提供jar包,打包的时候不会一起被打包
  • MVC中设定post编码为utf-8的方法:

    在web.xml中加入: ps 这个设置编码的过滤器得放在最上层,如果其他过滤器提取过参数,设置编码就无效了

    <!--设置过滤器处理所有请求-->
    <filter>
            <filter-name>CharacterEncodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <!--由源码可知,只设置了request的编码-->
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
            <!--强制所有转换,即respond的编码也被设置了-->
            <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>
    
  • @RequestMapping(value={"/"},method={RequestMethod.GET}) 映射请求匹配

    • ps method不匹配报405,params不匹配报400,header不匹配报404
    • @RequestParam("xx")写在参数左边作为传入的别名

      • 无论required的值,其中的参数defaultValue为在其传入空字符串或空时的默认值
    • @RequestHeader 参数和@RequestParam一样,设置传入参数的别名
    • @RequestBody 获取请求体
    • @CookieValue("JSESSIOND")获取cookie值
  • @ResponseBody当该方法返回类型为String时,声明该方法返回值为Respose中的body值;若返回为一个java的对象,则可以通过jackson的依赖返回一个json格式的字符串
  • @PathVariable("xx") 配合@RequestMapping中的"{xx}"获取占位符的参数,实现restful
  • 原生的ServletApi中的Request获取多个同名参数时只能获取第一个(比如复选框check有多个的时候)
  • @ControllerAdvice 是@Controller的扩展

    • @ExceptionHandler 拦截器,修饰的方法可以通过(Exception e)为其申明的错误类出现时执行的方法
  • modelandview 中专门有个model属性拿来存和浏览器交互的数据的

forward和direct区别

  • forward在服务器内部进行跳转,直接将返回信息再发送给服务器一次,会保留会话的request和respond,但是服务器的内部跳转依旧会经过过滤器
  • direct则是让浏览器自己去访问对应的值,会建立一次新的连接
  • 两者的呈现效果相同

Thymeleaf

  • 标签中的 th:href="@{/target}“ 能自动增加上下文路径

    • PS上下文路径指的是设置Tomcat中Artifact时候的路径

jsp与Thymeleaf配置的区别

 <!--配置thymeleaf的视图解析器-->
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">

                        <!-- 视图前缀 -->
                        <property name="prefix" value="/WEB-INF/templates/"/>

                        <!-- 视图后缀 -->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8" />
                    </bean>
                </property>
            </bean>
        </property>
    </bean>


<!--jsp中只需要配置InternalResourceViewResolver视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/templates/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

RESTFul

关于vue.js

在这小节里的delete使用了vue.js要使其能够访问,需要在springMVC.xml中添加

    <!--开放对静态资源的访问-->
    <mvc:default-servlet-handler />

    <!--开启mvc注解驱动-->
    <mvc:annotation-driven />

来开启静态资源的访问,原理是先用dispature找对应资源,若是找不到就交给默认default-servlet-handler处理,而默认的servlet可以访问静态目录,就可以访问到vue.js了

而且一定要开启mvc注解驱动,否则所有请求都会被默认servlet处理

关于路径

?:表示任意的单个字符

*:表示任意的0个或多个字符

**:表示任意的一层或多层目录

注意:在使用*时,只能使用/*/xxx的方式

运行流程

服务器启动

启动mvc组件后,首先是初始化DispatcherServlet

DispatcherServlet继承FrameworkServlet,而它的本质又是一个Servlet

其中的initServletBean()方法首先调用initWebApplicationContext(),初始化了webApplicationContext

在FrameworkServlet通过反射创建了IOC容器后,通过onRefresh(wac)方法中的initStrategies依次建立模板解析器、处理配置器等的组件

        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);

最后判断有没有初始化参数,有就通过setAttribute加入到wac中去。

至此initWebApplicationContext()执行完毕,bean对象创建

运行时接受请求的运行过程

re:https://blog.csdn.net/weixin_66716478/article/details/123880401

服务器接收到请求后,首先通过FrameworkServlet中的service接收Request和Response

service中继续调用processRequest方法,其中有doService,doDispatch

在DispatcherServlet重写的doService中设置attributesSnapshot = new HashMap();

在doDispatch中:

doDispatch中首先通过getHandler通过资源指示字符URI获取handler(控制器)

doDispatch中的getHandlerAdapter则获取到一个handle对应的adapt(适配器)

然后到达applyPreHandle,在这之后处理过滤器的preHandler方法

接着通过HandlerAdapter.handle方法,产生ModelandView,这里运行了写在服务器中的control方法;在这之后运行applyPostHandle方法

最后到达applyDefaultViewName方法,在这里会根据对应的ModelandView生成对应的view,在这才进行视图的渲染;这之后到applyPostHandle方法

处理完成后放入respond中返回

复习

什么是MVC

MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分

M:Model,模型层,指工程中的JavaBean,作用是处理数据

JavaBean分为两类:

  • 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
  • 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。

V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据

C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器

启动时的参数设定

<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
    <init-param>
        <!-- contextConfigLocation为固定值 -->
        <param-name>contextConfigLocation</param-name>
        <!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的src/main/resources -->
        <param-value>classpath:springMVC.xml</param-value>
    </init-param>
    <!-- 
         作为框架的核心组件,在启动过程中有大量的初始化操作要做
        而这些操作放在第一次请求时才执行会严重影响访问速度
        因此需要通过此标签将启动控制DispatcherServlet的初始化时间提前到服务器启动时
    -->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <!--
        设置springMVC的核心控制器所能处理的请求的请求路径
        /所匹配的请求可以是/login或.html或.js或.css方式的请求路径
        但是/不能匹配.jsp请求路径的请求
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

Spring Framework 的启动流程主要分为以下几个步骤:

  1. 加载配置文件:Spring 应用程序的配置通常使用 XML、JavaConfig 或注解来定义。在启动时,Spring 首先会加载这些配置文件。
  2. 创建 IoC 容器:Spring 的核心是 IoC(Inversion of Control)容器,它负责管理 JavaBean 对象的生命周期和依赖注入。在加载配置文件后,Spring 会创建一个 IoC 容器。
  3. 扫描组件:Spring 会扫描应用程序中的组件,如 Controller、Service、Repository 等,并将它们注册到 IoC 容器中。
  4. 实例化 Bean:Spring IoC 容器会根据配置文件中的定义,实例化 JavaBean 对象,并将它们添加到容器中。
  5. 注入依赖:Spring IoC 容器会自动注入 JavaBean 对象之间的依赖关系,以及与其他资源(如数据库连接、JMS、JNDI 等)的依赖关系。
  6. 初始化 Bean:在实例化和注入依赖后,Spring IoC 容器会调用 Bean 的初始化方法,如实现 InitializingBean 接口的 afterPropertiesSet() 方法、@PostConstruct 注解等。
  7. 提供 Bean:Spring IoC 容器将实例化和初始化后的 Bean 提供给应用程序使用,应用程序可以通过容器获取需要的 Bean,并调用它们的方法。
  8. 启动应用程序:最后,Spring IoC 容器会启动应用程序,使其可以响应请求、处理业务逻辑等。

Spring IoC容器如何管理JavaBean对象的生命周期?

  1. 实例化:当 Spring IoC 容器启动时,它会根据配置文件中的定义,创建 JavaBean 对象的实例。
  2. 属性赋值:在实例化之后,Spring IoC 容器会自动注入 JavaBean 对象之间的依赖关系,以及与其他资源(如数据库连接、JMS、JNDI 等)的依赖关系。
  3. 初始化:在属性赋值之后,Spring IoC 容器会调用 Bean 的初始化方法,如实现 InitializingBean 接口的 afterPropertiesSet() 方法、@PostConstruct 注解等。
  4. 使用:初始化之后,JavaBean 对象就可以被应用程序使用了。
  5. 销毁:当应用程序关闭时,Spring IoC 容器会销毁 JavaBean 对象,释放资源,如实现 DisposableBean 接口的 destroy() 方法、@PreDestroy 注解等。

需要注意的是,Spring IoC 容器对 JavaBean 对象的生命周期管理是基于 BeanDefinition 的。BeanDefinition 是 Spring IoC 容器中的一个对象,它包含了 JavaBean 对象的类名、属性值、依赖关系、初始化方法、销毁方法等元数据信息。Spring IoC 容器根据 BeanDefinition 来创建、初始化、配置和销毁 JavaBean 对象,从而实现对对象生命周期的管理。

总的来说,Spring IoC 容器通过 BeanDefinition 和一系列生命周期回调方法,实现了对 JavaBean 对象的生命周期管理,为应用程序提供了方便、灵活、可扩展的对象管理机制。

DispatcherServlet的结构及执行过程

https://blog.csdn.net/qq_38262266/article/details/108918959

  • DispatcherServlet继承FrameworkServlet,FrameworkServlet继承HttpServletBean,HttpServletBean继承HttpServlet(其实就是继承了servlet)
  • doService方法被重写,其中有个doDispatch(request,response)方法,是springmvc处理整个请求流程的关键。

    • HandlerMappings:doDispatch中mappedHandler =getHandler(processedRequest)负责找到对应的handler(也就是在里面找到匹配的url或者controller),返回的是HandlerExecutionChain,这里包含了拦截器和处理器(handler)。其中传入的RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则。

      • getHandler(processedRequest)中会从this.handlerMappings循环获取对应的handle
    • HandlerAdapter:HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());

      返回合适的Adapter适配器

      Handle适配器 不做定义的话默认装配下面三种Adapter

      HttpRequestHandlerAdapter :处理静态资源用

      SimpleControllerHandlerAdapter: 处理Controller接口或Controller接口子类的处理器

      AnnotationMethodHandlerAdapter:适配注解类处理器,注解类处理器就是我们经常使用的@Controller的这类处理器

      HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler())执行的时候会根据传过来的Handler匹配对应的Adapter

      比如这里返回的就是根据@RequestMapping匹配的Adapter:

      (在springboot2中是下面四种选一)

    • 这里会执行Interceptor中的preHandle
    • mv = ha.handle(processedRequest, response, mappedHandler.getHandler())

      返回的是ModelAndView

      • 这里会使用上面获得的Adapter开始处理HandlerExecutionChain
      • 通过ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);装载要执行的方法(比如Controller)
      • 使用this.argumentResolvers寻找输入参数对应的转换数据

      • 使用this.returnValueHandlers寻找对应的返回数据

        • 通过getMethodArgumentValues遍历所有输入参数,在上面说的this.argumentResolvers中给每个输入参数(比如request,person这些输入类)匹配到合适的转换方法Resolve

          • 每个参数都是通过HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);来获取解析器Resolver的

            • WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);中可以利用Converter中存在的类型装入数据到target

        • invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);中会反射方法和装配返回值,还有决定是作为返回数据还是作为视图处理

          • this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);

            会在此处设定返回类型,根据handl,如果是返回视图就给mavContainer.view变量赋值,如果返回数据,则view设为null

            • // 例如handle是RequestResponseBodyMethodProcessor时:
              // 此时相当于返回数据
              // 每个handle处理方法都不一样
          • 这里会调用MessageConverters寻找返回的数据类型
        • 处理完的结果会放在ModelAndViewContainer mavContainer
      • 这里会执行Interceptor中的PostHandle

        • ViewResolver接着来到this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException)方法里面有个

          • render(mv, request, response)方法,此时如果mv中的view有数据,就能根据mv的视图名字获得对应的View解析器
          • resolveViewName原理和上面的getHandler一样,根据名字利用循环this.viewResolvers来获得对应的view

          viewResolver可以在xml中配置,指定视图的前后缀以及解析器(比如Thymeleaf)

        • 这里会执行Interceptor中的PostHandle的afterCompletion

DispatcherServlet初始化过程

DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet 生命周期来进行调度。

如果对你有帮助就太好了)))