springMVC+前端请求"/>
springMVC+前端请求
=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-0&spm=1001.2101.3001.4242
=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control
MVC模型概述
Model(模型)
:数据模型,提供要展示的数据。数据Dao+服务层Service
View(视图)
:进行模型展示
Controller(控制器)
:接收用户请求,委托给模型进行处理,处理完毕后将返回的模型数据给视图进行展示。其实就是一个调度员
的工作。控制器本身不输出任何东西和做任何处理
。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。
下图中就是SpringMvc较为完整的流程图。其中需要我们实现的是Handler(Controller)中,我们需要做的业务处理。
- 用户点击某个请求路径,发起一个
request
请求,此请求会被前端控制器(DispatchServlet
)处理。 DispatchServlet
调用请求处理器映射器(HandleMapping
),HandleMapping根据请求的url去查找Handler。- HandleMapping根据配置找到相应的Handler(可能包含若干个
Interceptor拦截器
),返回给DispatchServlet。 DispatchServlet
请求处理器适配器(HandlerAdapter
)去执行相应的Handler处理器(常称为Controller)。- 处理器适配器执行Handler处理器。
Handler
处理器执行完毕之后会返回给处理器适配器一个ModelAndView
对象(SpringMVC底层对象,包括Model数据模型和View视图信息)。- 处理器适配器接收到Handler处理器返回的ModelAndView后,将其返回给前端控制器(Controller调用业务逻辑处理)。
- 前端控制器接收到ModelAndView后,会请求视图解析器(ViewResolver)对视图进行解析。
- 视图解析器根据View信息匹配到相应的视图结果,反馈给前端控制器。
- 前端控制器收到View具体视图后,进行视图渲染,将Model中的模型数据填充到View视图中的request域,生成最终的视图(View)。
- 前端控制器向用户返回请求结果。
主要涉及组件
前端控制器 DispatcherServlet
:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
处理器映射器 HandlerMapping
:根据请求的URL来查找Handler。用于存放编程时写的@RequestMapping的值及对应的handler处理器。当请求的url过来时,从此映射中找到对应的handler处理器。
处理器适配器 HandlerAdapter
:负责执行Handler
处理器 Handler
:即我们常说的Controller,需要程序员开发
视图解析器 ViewResolver
:进行视图的解析,根据视图逻辑名将ModelAndView解析成真正的视图(view)
视图View:View
是一个接口, 它的实现类支持不同的视图类型,如jsp,freemarker,pdf等等
用户向服务器发送请求,请求会到DispatcherServlet,DispatcherServlet 对请求URL进行解析,得到请求资源标识符(URI
),然后根据该URI,调用HandlerMapping
获得该Handler配置的所有相关的对象(包括一个Handler处理器对象、多个HandlerInterceptor拦截器对象
),最后以HandlerExecutionChain对象的形式返回。
DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
- HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
- 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等 数据格式化:对请求消息进行数据格式化。
- 如将字符串转换成格式化数字或格式化日期等 数据验证:
- 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
拦截器、过滤器
什么是过滤器
过滤器使用filter实现,拦截的是request请求,基于回调,基于servlect规范
依赖容器,拦截的是地址,粒度很大
过滤器Filter:过滤器通过实现Filter接口,实现了过滤器的三个方法,分别是init
方法,dofilter
方法和destory
方法,随着容器的启动和销毁而初始化和销毁,依赖于servlet容器,过滤器拦截的是地址栏请求,过滤器实在进入容器后执行的servlet之前后执行,针对的在处理业务之前的操作。
chain.doFilter(request, response);这个方法的调用作为分水岭。事实上调用Servlet的doService()方法是在这个方法中进行的。
什么是拦截器
基于Java的jdk动态代实现的,实现HandlerInterceptor接口。不依赖于servlet容器,
拦截器针对于controller方法,并且能获取到所有的类,对类里面所有的方法实现拦截,粒度更小,拦截器中可以注入service,也可以调用业务逻辑。拦截器是实现了 HandlerInterceptor 的三个方法:preHandle
、postHandle
、afterCompletion
拦截器、过滤器使用
两者都是AOP编程思想的实现,都能够实现权限控制和日志记录等问题的处理,但是两者粒度不同拦截对象不一样
适用范围不同
:Filter是servlet的规范,只能用于web程序,但是拦截器可以用于application等程序。
规范不同
:Filter是servlet的规范。但是Interceptor是spring容器支撑,有spring框架支持
使用资源不同
:spring的拦截器由于依赖spring,也是spring的一个组件,因此能够在拦截器中使用spring的任何资源和对象。例如service对象,数据源,事务管理等,通过ioc注入拦截器即可,而filter不能
粒度不同
:Filter只能在servlet的前后起作用,而拦截器能在方法前后异常前后执行,更加灵活,粒度更小,spring框架程序优先使用拦截器。
拦截器、过滤器的区别
①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
②拦截器不依赖与servlet容器,过滤器依赖与servlet
容器。
③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
过滤器和拦截器之间的关系如下图,Filter包裹Servlet,Servlet包裹Interceptor
过滤器的触发时机是容器后,servlet之前,所以过滤器的 doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) 的入参是ServletRequest,而不是HttpServletRequest,因为过滤器在HttpServlet之前
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("before...");chain.doFilter(request, response);System.out.println("after...");
}
这个chain.doFilter(request, response) 作用是将请求转发给过滤器链上下一个对象,下一个对象是指filter,如果没有filter那就是你请求的资源
拦截器是被包裹在过滤器之中
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle");return true;
}@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle");
}@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion");
}
-
preHandle 这个方法是在过滤器的 chain.doFilter( request, response ) 方法的前一步执行,且在调用Controller之前调用,当返回false后,会跳过之后的拦截器,并且不会执行所有的拦截器 postHandle ,并且调用返回true的拦截器的 afterCompletion 方法
-
postHandle 是调用 Controller 之后被调用,但是在渲染 View 页面之前
-
afterCompletion 是调用完 Controller 接口,渲染 View 完页面后调用,返回true的拦截器都会调用该拦截器的 afterCompletion 方法,顺序相反。
具体流程图:
HandlerInterceptor 接口
在HandlerInterceptor接口中,定义了 3 个方法,分别为preHandle()、postHandle()和afterCompletion(),我们就是通过复写这 3 个方法来对用户的请求进行拦截处理的。因此,我们可以通过直接实现HandlerInterceptor接口来实现拦截器的功能。不过在 Spring 框架之中,其还提供了另外一个接口和一个抽象类,实现了对HandlerInterceptor接口的功能扩展,分别为:AsyncHandlerInterceptor和HandlerInterceptorAdapter.
对于AsyncHandlerInterceptor接口,其在继承HandlerInterceptor接口的同时,又声明了一个新的方法afterConcurrentHandlingStarted();而HandlerInterceptorAdapter抽象类,则是更进一步,在其继承AsyncHandlerInterceptor接口的同时,又复写了preHandle方法。因此,AsyncHandlerInterceptor更像是一个过渡的接口。
在实际应用中,我们一般都是通过实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter抽象类,复写preHandle()、postHandle()和afterCompletion()这 3 个方法来对用户的请求进行拦截处理的。
下面,我们就详细介绍这个 3 个方法。
preHandle
(HttpServletRequest request, HttpServletResponse response, Object handle)方法,该方法在请求处理之前进行调用。Spring MVC 中的Interceptor是链式调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor中的preHandle方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求做一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔(Boolean)类型的,当它返回为false时,表示请求结束,后续的Interceptor和控制器(Controller)都不会再执行;当返回值为true时,就会继续调用下一个Interceptor的preHandle方法,如果已经是最后一个Interceptor的时候,就会是调用当前请求的控制器中的方法。postHandle
(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)方法,通过preHandle方法的解释,我们知道这个方法包括后面要说到的afterCompletion方法都只能在当前所属的Interceptor的preHandle方法的返回值为true的时候,才能被调用。postHandle方法在当前请求进行处理之后,也就是在控制器中的方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对控制器处理之后的ModelAndView对象进行操作。postHandle方法被调用的方向跟preHandle是相反的,也就是说,先声明的Interceptor的postHandle方法反而会后执行。这和 Struts2 里面的Interceptor的执行过程有点类似,Struts2 里面的Interceptor的执行过程也是链式的,只是在 Struts2 里面需要手动调用ActionInvocation的invoke方法来触发对下一个Interceptor或者是action的调用,然后每一个Interceptor中在invoke方法调用之前的内容都是按照声明顺序执行的,而invoke方法之后的内容就是反向的。afterCompletion
(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法,也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。因此,该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行,这个方法的主要作用是用于进行资源清理
的工作。
多个拦截器顺序
springmvc的拦截器实现HandlerInterceptor接口后,会有三个抽象方法需要实现,分别为方法前执行preHandle,方法后postHandle,页面渲染后afterCompletion。
1、当俩个拦截器都实现放行操作时,顺序为preHandle 1,preHandle 2,postHandle 2,postHandle 1,afterCompletion 2,afterCompletion 1
2、当第一个拦截器preHandle返回false,也就是对其进行拦截时,第二个拦截器是完全不执行的,第一个拦截器只执行preHandle部分。
3、当第一个拦截器preHandle返回true,第二个拦截器preHandle返回false,顺序为preHandle 1,preHandle 2 ,afterCompletion 1
demo网址链接~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
总结
一、调用顺序
preHandle
按拦截器定义顺序调用
postHandler、afterCompletion
按拦截器定义逆序
调用
二、调用条件
postHandler
在拦截器链内所有拦截器返成功调用(即,如果有多个拦截器,其中一个的preHandle返回false,则所有的postHandler都不会被调用!!!)
afterCompletion
只有preHandle
返回true才调用(即,如果有多个拦截器,只要自己的preHandler返回true就能调用)
更多推荐
springMVC+前端请求
发布评论