目录
1、曾经的王者----Servlet
2、想要更进一步
3、Spring MVC----两级控制器方式
4、DispatcherServlet----前端控制器
5、HandlerMapper----请求映射专家
6、Handler 的拦路虎----HandlerInterceptor
7、次级控制器----Handler
8、Handler 与 HandlerInterceptor 的桥梁---HandlerExecutionChain
9、解耦的关键----ModelAndView
10、视图渲染查找----ViewResolver
11、数据渲染----View
1、曾经的王者----Servlet
在刚接触到使用 Java 举行 Web 开发的时间,Spring MVC 远没有本日这么盛行,君不见曾经的王者 Servlet 繁盛一时的场面。现在回想起来,使用 Servlet 举行开发固然不像现在这么容易,很多多少的事故必要自己做,但是 Servlet 使得开发的逻辑变得十分清晰,尤其是在 Servlet 与 jsp 很好的负担了各自的脚色之后,再加上 mvc 分层思想的盛行。编写 Web 应用程序在当时是一件快乐而又简单的事故。
现实上 Servlet 做的事故并不是很多,Servlet 想要完成的就是统一请求的担当、处理惩罚与响应的流程。
网络编程中绕不开的一个东东想必不消说各人也猜得到,那就是 Socket。但是网络必要传输的话是很复杂的,起首必要遵照肯定的协议,现在一样平常使用 Http 与 Https 传输数据,而 Socket 就是在一些网络协议之上,屏蔽了底层协议的细节,为使用者提供一个统一的 api。但是 Servlet 以为 Socket 做的还不敷,或者说还要举行相应的处理惩罚。于是 Servlet(就 HttpServlet 来说),他将网络中的请求报文举行封装转化成为了 Request 表现,在 Http 通讯过程之中就是 HttpServletRequest,而将服务端处理惩罚请求后返回的响应统一的封装为了 HttpServletResponse 对象。
如许做的好处是什么呢?
作为开发者,不必再去做一些处理惩罚网络请求与响应的繁琐之事,而只必要关注于业务逻辑开发。
每一次框架服从的提升很多时间都是在将最最紧张的业务逻辑与其他任务尽大概完全的分离开,可以满身心的投入到业务逻辑的开发之中,Spring AOP 是不是就是一个很好的佐证呢!
那么 Servlet 如何使用呢?
- 起首通常要编写一个自己的 Servlet 然后继承自 HttpServlet,然后重写其 doGet()与 doPost()方法。这两个方法都会将 HttpServletRequest 与 HttpServletResponse 作为参数转达进去,然后从 Request 中提取前端传来的参数,在相应的 doXXX 方法内调用事先编写好的 Service 接口,Dao 接口即可将数据准备好放置到 Response 中并跳转到指定的页面即可,跳转的方式可以选择转发或者重定向。
- Servlet 使用的是模板方法的设计模式,在 Servlet 顶层将会调用 service 方法,该方法会构造 HttpServletRequest 与 HttpServletResponse 对象作为参数调用子类重写的 doXXX()方法。然后返回请求。
- 最后必要将编写的自定义 Servlet 注册到 web.xml 中,在 web.xml 中设置 servlet-mapping 来为该 servlet 指定处理惩罚哪些请求。
Servlet 的使用就是这么简单!究竟上,在很长的一段时间内他的盛行也得益于他的简单易用易上手。
- <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
- version="2.4">
- <servlet>
- <servlet-name>ShoppingServlet</servlet-name>
- <servlet-class>com.myTest.ShoppingServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>ShoppingServlet</servlet-name>
- <url-pattern>/shop/ShoppingServlet</url-pattern>
- </servlet-mapping>
- </web-app>
复制代码
2、想要更进一步
当使用 Servlet 来举行业务逻辑开发的时间,有那么一点点不适。不适的地方重要有以下几点:
- 每个 Servlet 只能处理惩罚一个请求,如许当系统比较大,业务比较复杂的时间大概会存在成百上千的 Servlet,找起来都眼花。
- 每次都必要手动的从 Request 中获取请求参数,然后封装成想要的对象,这其中大概还要对参数举行校验,在调用业务逻辑层获取到数据之后,还要手动的设置到响应中,同时手动的选择转发或者重定向举行跳转。
- 请求的 url 是硬设置到 web.xml 中的,缺乏机动性,假如可以动态的设置这种请求 url 与处理惩罚的对应关系就好了。
- Servlet 与前端的渲染框架紧耦合在一块,如许当前端换一种显示技能的时间就必要改动较大的代码,假如能把数据的处理惩罚与数据的显示分离,让其疏松耦合就更好了。
带着这些思索,能不能进一步的来抽离业务逻辑的开发呢?
在早期的时间也曾举行一些尝试,其大概思绪就是编写一个 BaseServlet,然后自己定义的 Servlet 继承自 BaseServlet,前端的请求必要指定 Servlet 的哪个方法举行处理惩罚,如许请求的时间将必要带上一个 method 参数,例如如许:
http://localhost:8080/myProject/MyServlet?method=getInfo
在 BaseServlet 中将提取该参数信息,并使用反射的方法调用子类的该方法,子类方法统一返回 String 范例的效果,代表要返回的逻辑视图名,也就是要跳转的路径,然后父类拿到效果,使用重定向或者转发举行跳转。
假如想要在 Servlet 上更进一步,想要进一步的将业务逻辑与其他工作相分离,那么就必要在 Servlet 之上,构建一个事无巨细,任劳任怨,神通过大,的超等 Servlet,来做这些工作,并正式命名为 DispatcherServlet。
3、Spring MVC----两级控制器方式
接下来就要正式的开始 Spring MVC 之旅了,通过前面的了解,DispatcherServlet为简化开发操碎了心,称之为前端控制器。现在不禁思索,前面写的 BaseServlet 对应现在的 DispatcherServlet。那么定义业务逻辑的自定义 Servlet 叫啥呢?Spring MVC 管定义业务逻辑处理惩罚的类叫做 Handler,只不过他不再是一个 Servlet 了,而是一个普平凡通的类,这也很好明白,究竟 DispatcherServlet 做了太多,完全可以像对待 Servlet 一样对待一个平凡的类,而这个 Handler 就叫做次级控制器。
有的书上说了 Spring MVC 的次级控制器叫 Controller,不是 Handler。
其实 Spring MVC 的次级控制器确实是叫 Handler,只不过 Hander 是一个抽象的,而 Spring MVC 选择使用 Controller 来实现 Handler,能不能自定义一个 Handler 实现,叫做 Lellortnoc 呢?答案固然是可以的!就好像 List 是一个抽象的接口,而 List 的实现有 ArrayList,LinkedList 一样。
4、DispatcherServlet----前端控制器
DispatcherServlet 是整个 Spring MVC 的核心,超等牛逼 Servlet 这个荣誉称号他是名副其实。DispatcherServlet 和其家族成员兄弟一起完成了很多的工作,包罗请求参数的自动绑定,参数的自动校验,请求 url 的自动匹配,逻辑视图名到真实页面的跳转,数据获取与数据渲染显示的分离等等。。。在此过程中他更像是一个指挥家,井井有条的指挥着请求不断的向前处理惩罚,并终极完成服务端的响应数据。
想要了解具体 DispatcherServlet 都是怎么指挥的,那就继续往下看吧!
5、HandlerMapper----请求映射专家
在使用 Servlet 编写代码的时间,请求的映射工作是交给了 web.xml。但是现在 Spring MVC 采用了两级控制器的方式,就必须解决这个棘手的问题。
起首 DispatcherServlet 也是一个 Servlet,那么也应该在 web.xml 中设置其处理惩罚的请求路径。那么应该设置什么路径呢? 希望DispatcherServlet能处理惩罚全部的请求,那么就可以让 DispatcherServlet 担当全部请求的处理惩罚。像下面如许设置:
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app version="3.0"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
- <servlet>
- <servlet-name>Spring MVC</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <!-- 表示启动容器时初始化该servlet -->
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:Spring-servlet.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>Spring MVC</servlet-name>
- <url-pattern>/*</url-pattern>
- </servlet-mapping>
- </web-app>
复制代码 现在全部的请求都被映射到了 DispatcherServlet,那么 DispatcherServlet 现在就有责任将请求分发至具体的次级控制器,如何找到或者说如何生存请求到具体的次级控制器的这种映射关系呢?DispatcherServlet 选择请求他的好兄弟 HandlerMapping。
在 HandlerMapping 中,生存了特定的请求 url 应该被哪一个 Handler(也就是通常的 Controller)所处理惩罚。HandlerMapping 根据映射策略的不同,大概有下面几种映射查找方式:
- org.springframework.web.servlet.handler.SimpleUrlHandlerMapping 通过设置请求路径和 Controller 映射建立关系,找到相应的 Controller
- org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping 通过 Controller 的类名找到请求的 Controller。
- org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping 通过定义的 beanName 举行查找要请求的 Controller
- org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping 通过注解 @RequestMapping("/userlist") 来查找对应的 Controller。
想必现在最常用的就是第四种了吧,直接在对应的 Controller 上以及其内部的方法之上加上相应的注解,就可以设置好请求的映射。
6、Handler 的拦路虎----HandlerInterceptor
你以为 DispatcherServlet 把请求的 url 交给 HandlerMapping, HandlerMapping 根据请求查出对应的 Controller 来交给 DispatcherServlet, 然后 DispatcherServlet 交给 Controller 实行就完事了?那就 To young to native 了,这其中另有一些小插曲。比如不能什么请求都交给 Handler 实行,最起码要过滤一下不合理的请求,比如跳转页面的时间检查 Session,假如用户没登录跳转到登录界面啊,以及一些程序的异常以统一的方式跳转等等,都必要对请求举行拦截。
假如对 Servlet 了解的同砚是不是有一点似曾相识的感觉?没错,Servlet 中的 Filter 也可以完成请求拦截与过滤的功能,不过既然 Spring MVC 是两级控制器结构,那么 HandlerInterceptor 就与 Filter 有一些细微的差别,其最重要的差别, HandlerInterceptor 提供了更细粒度的拦截。究竟 Filter 拦截的对象是 Serlvet,而 HandlerInterceptor 拦截的则是 Handler(Controller)。用一张图可以生动的体现出来。
从图中可以看出 HandlerInteceptor 可以设置多个,其中任何一个返回 false 的话,请求都将被拦截,直接返回。
7、次级控制器----Handler
前端控制器已经很熟悉了,而次级控制器也就是 Handler,是真正实行业务逻辑的类。通常在 Spring MVC 中,这个 Handler 就是很熟悉的 Controller。调用封装好的业务逻辑接口就是在这里举行处理惩罚的。可以说 Spring MVC 已经将业务逻辑与其他不相干的繁杂工作分离的较为彻底了。如许,就在 Handler(Controller)中用心的编写业务逻辑!
8、Handler 与 HandlerInterceptor 的桥梁---HandlerExecutionChain
前面讲到 DispatherServlet 求助 HandlerMapping 举行 url 与次级控制器的映射,但是 DispatherServlet 在将 url 交给特定的 HandlerMapping 之后,HandlerMapping 在举行了一顿猛如虎的操作之后,返回给 DispaterServlet 的却不是一个可实行的 Handler(Controller),而是一个 HandlerExecutionChain 对象。那么 HandlerMapping 究竟为什么要返回给如许的一个对象而不是返回 Handler 对象呢?
其着实看上面图的时间,HandlerInterceptor 与 Handler 是怎样接洽在一起的呢?答案就是 HandlerExecutionChain。它就是若干的 HandlerInterceptor 与 Handler 的组合。那么是怎么组合的呢?
这里就涉及到设计模式中的责任链设计模式,HandlerExecutionChain 将 HandlerInterceptor 与 Handler 串成一个实行链的形式,起首请求会被第一个 HandlerInterceptor 拦截,假如返回 false,那么直接短路请求,假如返回 true,那么再交给第二个 HandlerInterceptor 处理惩罚,直到全部的 HandlerInterceptor 都检查通过,请求才到达 Handler(Controller),交由 Handler 正式的处理惩罚请求。实行完成之后再逐层的返回。
而 DispatcherServlet 拿到的就是如许一个串联好的 HandlerExecutionChain,然后顺序的实行请求。
9、解耦的关键----ModelAndView
到这里,请求终于来到了对应的 Handler。希望的是 Handler 只处理惩罚负责的业务逻辑即可,而一些 url 的跳转等无需 Handler 负责。那么 DispatcherServlet 就使用了 ModelAndView 生存数据和想要跳转的路径。
调用业务逻辑层获取数据,并将数据封装到 ModelAndView 中,同时设置 ModelAndView 的 view 逻辑视图名称。从 ModelAndView 的名称可以看出,它生存了 Handler 实行完成之后所必要发送到前端的数据,以及必要跳转的路径。这些是 DispatcherServlet 必要用到的。
10、视图渲染查找----ViewResolver
这一步是 Spring MVC 将数据的获取与数据的显示渲染相分离的关键,前端大概采用各种各样的方式显示数据,大概是 Jsp,大概是 Html,也大概是其他的方式。DispatcherServlet 已经拿到了 ModelAndView,这里面有实行完成请求后返回的响应效果数据,另有逻辑视图的路径,这个时间 DispatcherServlet 就必要根据这个逻辑视图的路径去查找谁能把数据举行解析与渲染。
比如说使用 FreeMarker 模板引擎渲染数据,那么这个时间就要找到能够胜任该工作的那个 View 实现类,那么问题来了,如何寻找呢?以什么策略寻找呢?这个就依靠 ViewResolver 了。
通常的寻找策略有以下几种:
- BeanNameViewResolver :将逻辑视图名解析为一个 Bean,Bean 的 id 即是逻辑视图名。
- XmlViewResolver:和 BeanNameViewResolver 雷同,只不过目的视图 Bean 对象定义在一个独立的 XML 文件中,而非定义在 DispatcherServlet 上下文的主设置文件中
- InternalResourceViewResovlver:将视图名解析为一个 URL 文件,一样平常使用该解析器将视图名映射为生存在 WEB-INF 目录中的程序文件(如 JSP)
- XsltViewResolver:将视图名解析为一个指定 XSLT 样式表的 URL 文件
- JasperReportsViewResolver:JasperReports 是一个基于 java 的开源报表工具,该解析器将视图名解析为报表文件对应的 URL
- FreeMarkerViewResolver:解析为基于 FreeMarker 模板技能的模板文件
- VelocityViewResolver 和 VelocityLayoutViewResolver:解析为基于 Velocity 模板技能的模板文件 11、数据渲染----View
在根据逻辑视图名借助 ViewResolver 查找到对应的 View 实现类之后,DispatcherServlet 就会将 ModelAndView 中的数据交给 View 实现类来举行渲染,待该 View 渲染完成之后,会将渲染完成的数据交给 DispatcherServlet,这时间 DispatcherServlet 将其封装到 Response 返回给前端显示。
至此,整个 Spring MVC 的处理惩罚流程就算完成了,固然这其中还会有对于国际化的支持,主题的定义与设置等等,但是这些是不常用的,Spring MVC 最重要的处理惩罚流程所必要的用到的就是以上这些类。可以看到在此过程中,DispatcherServlet 起到了至关紧张的作用,所以说 Spring MVC 的核心就在于 DispatcherServlet。
最后附上一张流程图作为以上内容的总结。
假如小假的内容对你有帮助,请点赞,评论,收藏。创作不易,各人的支持就是我坚持下去的动力!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |