- 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 的启动流程主要分为以下几个步骤:
- 加载配置文件:Spring 应用程序的配置通常使用 XML、JavaConfig 或注解来定义。在启动时,Spring 首先会加载这些配置文件。
- 创建 IoC 容器:Spring 的核心是 IoC(Inversion of Control)容器,它负责管理 JavaBean 对象的生命周期和依赖注入。在加载配置文件后,Spring 会创建一个 IoC 容器。
- 扫描组件:Spring 会扫描应用程序中的组件,如 Controller、Service、Repository 等,并将它们注册到 IoC 容器中。
- 实例化 Bean:Spring IoC 容器会根据配置文件中的定义,实例化 JavaBean 对象,并将它们添加到容器中。
- 注入依赖:Spring IoC 容器会自动注入 JavaBean 对象之间的依赖关系,以及与其他资源(如数据库连接、JMS、JNDI 等)的依赖关系。
- 初始化 Bean:在实例化和注入依赖后,Spring IoC 容器会调用 Bean 的初始化方法,如实现 InitializingBean 接口的 afterPropertiesSet() 方法、@PostConstruct 注解等。
- 提供 Bean:Spring IoC 容器将实例化和初始化后的 Bean 提供给应用程序使用,应用程序可以通过容器获取需要的 Bean,并调用它们的方法。
- 启动应用程序:最后,Spring IoC 容器会启动应用程序,使其可以响应请求、处理业务逻辑等。
Spring IoC容器如何管理JavaBean对象的生命周期?
- 实例化:当 Spring IoC 容器启动时,它会根据配置文件中的定义,创建 JavaBean 对象的实例。
- 属性赋值:在实例化之后,Spring IoC 容器会自动注入 JavaBean 对象之间的依赖关系,以及与其他资源(如数据库连接、JMS、JNDI 等)的依赖关系。
- 初始化:在属性赋值之后,Spring IoC 容器会调用 Bean 的初始化方法,如实现 InitializingBean 接口的 afterPropertiesSet() 方法、@PostConstruct 注解等。
- 使用:初始化之后,JavaBean 对象就可以被应用程序使用了。
- 销毁:当应用程序关闭时,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 生命周期来进行调度。