Java EE应用分层模型:
Domain Object
表现层-->DAO(Data Access Object)
数据访问对象层 --->Service
业务逻辑层 --->Controller
控制器层-->View
表现层。
之前学习的是JSP
+ Servlet
+JavaBean
的技术来开发web应用。使用的是JDBC技术来与数据库进行交互。尤其是结合DBUtils工具和数据源,简化了数据库的连接、结果集的封装等操作。而接下来要学习的MyBatis据说消除了几乎所有的JDBC代码和参数的手工设置过程以及对结果集的检索封装。本文主要不涉及数据库这块。重点放在Servlet。
Servlet
与SpringMVC中的DispatcherServlet
和Controller
区别
使用JSP +Servlet的应用,分层不够清晰,业务逻辑的实现没有单独分离出来,造成后期的维护困难。
在Spring MVC中,Servlet有了各种“分身”,有负责拦截和分发请求的DispatcherServlet
,还有负责处理业务的Controller
,还有各种的处理映射器和处理器适配器等,每一个都有明确的分工。这些是本文重点涉及的内容。
SpringMVC框架提供了一个DispatcherServlet作为前端控制器来分派请求。DispatcherServlet继承自HttpServlet。它拦截请求的功能让人联想到Servlet技术中的Filter。不过Filter不会干涉原来的URL,经过Filter处理完毕的URL请求还是会按照web.xml配置中的映射跳转到对应的Servlet,甚至不经过Filter照样可以跳转到对应的Servlet。
Spring MVC中的DispatcherServlet
而DispatcherServlet则有所不同,URL请求必须
经过DispatcherServlet,因为映射信息需要DispatcherServlet去读取。
DispatcherServlet在web.xml配置时,使用<load-on-startup>1</load-on-startup>标签来指定其在程序启动时立即加载。DispatcherServlet
加载时需要读取Spring MVC
的配置文件,然后解析该文件内容并根据配置信息生成一个WebApplicationContext
容器对象。(该对象保存了请求映射和和处理器映射器等的信息)。有了这个容器对象,开发者就能使用Spring的IOC、AOP等功能。
在DispatcherServlet中有一个initStrategies(ApplicationContext context)
方法,调用该方法时,会将生成的WebApplicationContext
对象传入该方法,如果配置文件中自定义了处理映射器、处理器适配器等组件,那么就会从WebApplicationContext
中寻找并进行初始化。如果没有找到那么就会使用Spring默认的组件。
DispatcherServlet分发的请求会交给对应的Java类,Spring MVC中称为Handle
。在Spring 2.5版本之前,这个Handle类需要实现Controller接口。
Spring MVC中的Controller(与Servlet的区别)
Controller接口必须实现一个方法,该方法必须返回一个ModelAndView对象:
public class HelloController implements Controller{
...
ModelAndView handleRequest(HTtpServletReqeust request,HttpServletResponse response) throws Exceptiona{
...
}
}
Spring2.5版本以后新增了基于注解的控制器。
@Controller
public class HelloController{
...
@RequestMapping(value="/hello")
public ModelAndView hello(){
...
}
}
同样是HelloController,写法上现在不需要继承自Controller接口。也不需要强制实现handleRequest()方法来返回ModelAndView对象,而是可以自定义多个方法
来返回ModelAndView对象,这样的话可以实现多个请求映射到同一个Controller,并且能调用不同的方法来处理请求。如果沿用之前的做法,虽然能够在Spring MVC的配置文件中将多个请求映射到同一个Controller,但只能够调用handleRequest()方法。
相应地,使用注释后也不需要在Spring MVC的配置文件中映射请求。
而使用Servlet技术处理Http请求时,在Servlet接口中提供了一个抽象类HttpServlet,它是GenericServlet的子类。继承HttpServlet并重写doGet()和doPost()方法:并且不要求一定返回对象,也可以跳转到到JSP页面,然后让JSP自行显示内容。
public class UploadServlet extends HttpServelt{
public void doGet(HttpServeltRequest request,HttpServeltResponse response) throws ServletException,IOException{
...
}
...
}
即便只是跳转,在Spring MVC中也需要将跳转信息封装到ModelAndView对象中,需要传递的参数同样保存到该对象中。而在新的页面中就能够通过requestScope访问到所传递的参数。
配置Spring MVC的Controller
Spring MVC的配置文件的部分信息如下:
<!-- 配置Handle,映射"/hello"请求 -->
<bean name="/hello" class="org.fkit.controller.HelloController"/>
<!-- 处理映射器将bean的name作为url进行查找,需要在配置Handle时指定name(即url) -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- SimpleControllerHandlerAdapter是一个处理器适配器,所有处理适配器都要实现 HandlerAdapter接口-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
这些信息都是和Controller有很大关系。无论是在Servlet或是这里的Controller中,都需要映射请求。这里将/hello请求映射到HelloController这个Handle中。而SimpleControllerHandlerAdapter
用于完成对HelloController类的handleRequest方法的调用。而InternalResourceViewResolver
则是用于解析视图(Spring4.0之后,即便不配置映射处理器、处理器适配器和视图解析器,也会使用默认的完成Spring内部MVC的工作)。
使用注释后,需要对Spring MVC配置文件进行修改。首先不需要在配置文件中映射请求。但是需要知道所有的controller的位置。
<context:component-scan base-package="org.fkit.controller">
接着要配置annotation类型的处理映射器和处理器适配器,但是视图解析器不需要更改。当然,Spring4.0之后有更简便的配置方式
。
而这里只是实现了映射,并没有进行访问。是通过反射来创建Controller实例。我的理解是根据URL链接,寻找到对应的class类的路径,然后根据这个路径生成一个实例。这一部分猜想是通过HandlerMapping
来具体实现的。然后处理器适配器用于调用handleRequest()方法,我们知道使用Servlet的时候,当遇到Request会根据是GET或者POST自动执行doGet()或者doPost()方法。而这里创建完以后还需要处理器适配器来进行调用。
视图解析器则是负责从ModelAndView对象中获取连接和参数然后传递给DispatcherServlet的。按我的理解,目前来看,Handler和Servlet的区别在于Handler需要返回一个ModelAndView对象,而Servlet不需要,其他也没有太大的区别。也有说Servlet是Controller的父类。
网友评论