SpringMvc二刷
b站视频:https://www.bilibili.com/video/BV1Ry4y1574R (92~95的dispatcherServlet源码解析不是很懂,太顶了)
-
MVC简介
- model:模型,模型层,指JavaBean
- 实体类Bean:用于存储数据的
- 业务处理Bean:指service和Dao对象,用于处理业务逻辑和数据访问
- view:视图层,指工程里面的html和lsp页面
- controller:控制层,指工程中的servlet,作用是接受请求和响应浏览器
MVC工作流程:
用户通过视图层(前端浏览器的html页面)发送请求到服务器,在服务器中请求 被Controller接受,Controller调用对应的Model(实体类Bean和业务处理Bean)层处理请求,处理完毕后将结果返回到Controller,Controller再根据请求处理的结果找到对应的View试图,渲染数据后最终响应到浏览器。
-
spirngmvc时候,控制层使用@controller仅为注册组件,还需要手动在resource下的springMVC.xml配置文件里面进行组件扫描(Component-scan base-package=“com.ws.mvc.controller”),相当于先要存在这个组件,然后再选择是否使用该组件。 -
MVC工作更详细流程:
浏览器发送请求,若请求地址符合前端控制器的url-pattren,该请求就会被前端控制器DispatchServlet处理,前端控制器会读取SpringMVC核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapperin注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法,处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成(工作流程见下面),通过Thymleaf对试图进行渲染,最终转发到试图所对应页面
-
视图名称被视图解析器解析流程:视图解析器(Thyleaf)也需要在springMvc.xml里面进行配置,并且还要配置前缀后缀,所以当控制层给dispatcherServlet返回该视图名称,会给手动拼接前缀(文件地址),后缀(。jsp),然后进入该页面
-
@RequestMapping("/test")
public String testServlet(HttpServletRequest request)(){}
关于上述接口传参为HttpServletRequest request()的时候,具体是如何处理的。
在理解了上面mvc工作流程之后,结合图片,就会知道,到这一步匹配传参的时候就已经经过了:请求-->dispatcherServlet-->HandlerMapping(找到接口地址)-->返回dispatcherServlet-->再进入接口处理的组件HandlerAdapter.
到这步之后,假如我们的接口传参为HttpServletRequest,就会将DispatcherServlet获取到的请求参数自动覆盖掉这个传参的HttpServletRequest,我们就可以使用这个request了。
(但是呀,我们的直接就能使用@RequestParm参数,不需要使用HttpServletRequest)
@Requestparam详解
-
@RequestParam()是将请求参数和控制器方法的形参创建映射关系
@RequestHeader(“Host”)String host; 是将请求头信息和控制器方法的形参创建映射关系
@CookieValue是将cookie数据和控制器方法形参创建映射关系
characterEncodingFlieter编码过滤器详解
- 出现乱码问题
- 原因:请求中的某个参数如:sex=男,到控制器的形参接受的时候可能会出现编码错误
- 乱码问题也分get请求和post请求
- get请求的乱码问题在Tomcat的配置文件里面设置,通常是被处理过的
- 所以说我们通常指的都是Post请求的乱码问题
- 所以这里我们要想:当请求来服务器的时候,是DisPatcherServlet接受请求在前,之后再是我们的控制层形参获取经由dispatcherServlet转发的请求,所以这里我们要在dispatcherServlet获取请求之前就进行编码处理
- 这里就要考虑服务器的三大组件:监听器,过滤器,Servlet
- 其中执行顺序为:ServletContextLinster–>过滤器–>Servlet
- 其中的ServletContextLinster是监听器,旨在监听Servlet的创建和销毁,只会执行一次
- 所以就要在过滤器里面配置
- 所以就要在springmvc.xml里面进行组件注册
tomcat自带的web.xml
@RestController底层研究—@ResonpseBody
JSON的作用!!!
-
!!!!!JSON到底为什么产生!!!!!!!!
-
方法返回值为实体类user的时候,在标注了@ResponseBody的情况下, 当user放到响应报文体里面去的时候,浏览器是获取不到这个的,(浏览器只能获取到简单的数据格式:字符串)会直接报错500(httpmessageNotwriterableException:no convert found for return value of type:com.ws.bean.User) 这个时候就需要一种固定格式 -能够完整的展示User的所有信息,而且还能被浏览器端访问----JSON
-
想要在上述问题解决返回值要为json格式需要几步
- 导入jackson的依赖
- web.xml中配置mvc注解驱动mvc:annotation-driven/(重点就是这步,此时会在HandlerAdapor中自动装配一个消息转换器:Mappingackson2HttpMessageConverter,可以将响应到浏览器的java对象转化为JSon格式的字符串)
- 处理器方法上加@ResponBody
- 将控制器方法返回值变为实体类,就会自动转化为JSON格式的字符串!!!(这里不是json对象哦,是json形式的字符串!!!,你要是直接传json到浏览器他还是展示不出来,只能是json的字符串)
(上面那么多步其实234都已经做过了,所以实际项目上只要加入jackson的包就可以直接实现实体类转json的过程了)
回顾json
json就是一种数据交互格式
xml其实也是数据交互格式,只不过xml更多的用户配置文件的编写
json编写方便,而且解析方便
dom4j解析xml文件,会将整个xml进行一层一层的解析,从根标签开始
ServletContext:servlet上下文
ServletContext官方叫servlet上下文。服务器会为每一个工程创建一个对象,这个对象就是ServletContext对象。这个对象全局唯一,而且工程内部的所有servlet都共享这个对象。所以叫全局应用程序共享对象。
springmvc进行文件上传
- maven依赖:commons-fileupload
- 前端传文件 type=file ,enctype=“multipart/form-data”
- 后端接受文件 MultipartFile file (注意这里不能直接将请求中的文件直接转化为multipart形式,需要配置文件上转解析器,才能转化)
- 配置文件上传解析器,将上传的文件封装为MultipartFile
拦截器Interceptor:拦截控制器方法的
过滤器是在disaptcherServlet之前的,过滤所有的请求
拦截器是在dispatcherServlet–>Controller的controller前后
? 分为preHandler,postHandler,afterHandler(Handler一直可以看成Controller)
请求–>filter过滤器(过滤所有请求)–>dispatcherServlet–>Controller
- preHandler:控制器方法之前执行
- Posthandler:控制器方法一起执行
- afterHandler:控制器方法执行完返回ModelAndView之后执行的
这里有个思想在这:
我们知道了拦截器的执行时间,想要模拟一个这个拦截器,怎么去源码里面看
!!!去dispatcherServlet源码里面去看,找到handlerMapper之后,handlerAdaptor附近的代码
- 双击shift,搜索dispatcherServlet
- alt+7找到所有方法,找到doDispath方法(源码1060行附近)
- 找到applyPreHandler,applyPostHandler
通过上面的拦截器去理解mybatis的pageInteceptor:分页插件拦截器
在写mybatis的时候,我们并没有写任何关于分页的代码,只是加载了分页插件(拦截器),当有控制器方法去使用这个插件提供的page方法的时候,就会自动执行这个拦截器 进行查询数据时候的分页功能
自定义拦截器
- 自己编写一个拦截器继承HandlerInteceptor,实现他的三个方法
- 然后去web.xml注册到组件里面(注册+扫描才行)
- 然后就去web.xml里面进行各种路径配置
- 被排除的就不会走拦截器,其他的都会走拦截器
- 并且/*之代表着一层关系
- 像/s /a /d 等等
- 但是不代表着/d/d /d/g这种两层的
- 假如拦截的是/**那么就相当于拦截所有的请求,此时就与过滤器相同意思了
多个拦截器怎么生效,什么顺序
先自定义配置两个拦截器: 先在web.xml配置firstInteceptor再配置secondIntecptor
执行的顺序为:
- preHandler是按照配置顺序来执行的
- PostHandler和afterhandler是配置的反顺序执行的
- 原理就是:首先获取所有的拦截器,然后for循环进行遍历,preHandler里面i++,剩下两个是i–执行
当有五个拦截器12345,3的preHandler返回的是false(即进行拦截),那么会执行哪些拦截器呢
preHandler会执行:123的
postHandler一个都不会执行
afterHandler会执行:2 1 的
最终顺序就是Pre1 pre2 pre3 after 2 after1这五个
异常处理解析器(包含@ControllerAdvice和@ExceptionHandler)
当页面出现某个指定的异常的时候,我们可以设置指定的跳转页面
这样在执行上述请求的时候,当执行到1/0的时候,发现了arithmeticException就会自动跳转到error.html页面里面
web.xml里面还能配置error页面里面具体输出的信息等等。。
自定义一个异常处理类:
@ControllerAdvice相当于@Component标注该类为组件
@ExceptionHandler相当于之前配置文件里面写的key ,value
当哪个控制器方法抛出这个异常的时候,那么返回的modelAndView全权由这个@Exceptionhandler来返回
SpringMvc配置文件配置了哪些东西(重点!!!!)
不仅要看是如何配置的,还要看配置的时候是用的还是mvc:,这个跟下面的webConfig配置类有很大关系!!
<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.atguigu.mvc"></context:component-scan>
<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>
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<mvc:default-servlet-handler />
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="UTF-8" />
<property name="supportedMediaTypes">
<list>
<value>text/html</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
<mvc:interceptors>
<ref bean="firstInterceptor"></ref>
<ref bean="secondInterceptor"></ref>
</mvc:interceptors>
</beans>
1 .扫描组件
2.视图解析器(跳转到success,自动寻找到success.html)
3.view-controller (初始时项目路径为“/”的时候,访问的页面)
4.default-servlet-handler(处理静态资源)
5.mvc注解驱动
6.文件上传解析器(multipartFile 形参接收文件类型)
7.异常处理
8。拦截器
public class webConfig implements WebMvcConfiguer到底啥意思
在看这个之前,一定要仔细了解以下springmvc里面的web.xml里面配置的各种东西
在Springmvc里面使用配置类代替web.xml
相当于用配置类代替配置文件
springmvc配置文件转配置类的时候,配置文件以标签注册的可以直接在配置类里面使用同样的注册,但是以注册的各种东西(主要是各种解析器)都需要通过实现webMvcConfigure接口来实现
如:使用webMvcConfigure接口实现拦截器:
如:使用webMvcConfigure接口实现defaultServletHandler
如:使用webMvcConfigure接口实现view-controller
如:使用webMvcConfigure接口实现异常处理
件
springmvc配置文件转配置类的时候,配置文件以标签注册的可以直接在配置类里面使用同样的注册,但是以注册的各种东西(主要是各种解析器)都需要通过实现webMvcConfigure接口来实现
如:使用webMvcConfigure接口实现拦截器:
[外链图片转存中…(img-AuDE87In-1648713497573)]
如:使用webMvcConfigure接口实现defaultServletHandler
[外链图片转存中…(img-Kzx53XVr-1648713497573)]
如:使用webMvcConfigure接口实现view-controller
[外链图片转存中…(img-CQpuAZI0-1648713497573)]
如:使用webMvcConfigure接口实现异常处理
[外链图片转存中…(img-UVI9UD5P-1648713497573)]
|