前言
随着springmvc的注解功能使用,springmvc已经逐渐取代struts2成为目前比较主流的mvc框架,在springmvc中除了核心控制器DispatcherServlet这个核心组件之外,还有在springmvc中的处理器映射器和适配器,这两个组件在springmvc整个的运行流程之中扮演一个很重要的角色,至于映射器和适配器这两个组件他们的功能,我们可以这样理解,映射器主要是跟我我们在浏览器上输入的url来映射对应的Handle,具体的映射规则需要根据使用哪一个映射器来决定,而适配器主要是决定调用哪个Handler来实现具体的业务逻辑,随着注解的发展,映射器和适配器的使用也越来越方便,但是熟悉这两个组件的底层实现,对我们在日常开发和对springmvc的理解也是有帮助的,下面我们一起来看看这个组件的进化史。
非注解的映射器和适配器
在早期的springmvc之中,那时候注解这个功能还没有现在这么强大。对于映射器和适配器都是需要在spring容器中进行配置的。
首先,我先来看看非注解的映射器的两种方式
- 利用BeanNameUrlHandlerMapping来实现映射
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
- 1
根据上面这个类的名字就可以知道,这种映射器是依据bean的名字来映射对应的Handler,所以在spring的容器中声明一个bean,通过设置其name属性来进行URL和Handler进行映射
<bean name="/SimpleControllerDemo.do" class="com.aiqinhai.springmvcdemo.controller.SimpleControllerDemo"></bean>
- 1
- 通过SimpleUrlHandlerMapping来实现映射器
<!-- 测试 SimpleUrlHandlerMapping映射器-->
<bean id="testController1" class="com.aiqinhai.springmvcdemo.controller.HttpRequestDemo"></bean>
<bean id="testController2" class="com.aiqinhai.springmvcdemo.controller.SimpleControllerDemo</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/test1.do">testController1</prop>
<prop key="/test2.do">testController2</prop>
</props>
</property>
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
上面的两种映射方式是可以同时并存的,哪一个路径对应哪个映射,就执行哪个映射来确定具体的Handler
3. 实现Controller接口来实现适配器功能,具体例子如下
/**
* @author 爱琴孩
*测试Handle实现Controller接口
*/
public class SimpleControllerDemo implements Controller{
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// TODO Auto-generated method stub
ModelAndView model=new ModelAndView();
List<String > studentList=new ArrayList<String>();
studentList.add("爱琴孩");//这里在实际开发中,可能是从数据库中查询的数据,这里只做演示
studentList.add("大牛");
model.addObject("studentList", studentList);
model.setViewName("test/login");
return model;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
上面这种方式的适配器是实现Controller接口,当然还需要在spring容器中注入
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
- 1
获取到数据之后,放在ModelAndView 之中,然后经过springmvc的视图解析器,渲染对应的视图
4. 实现HttpRequestHandler接口来实现适配器的功能,具体例子如下
/**
*
* @author 爱琴孩
*测试Handle实现HttpRequestHandler接口
*/
public class HttpRequestDemo implements HttpRequestHandler{
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
List<String > studentList=new ArrayList<String>();
studentList.add("爱琴孩");
studentList.add("大牛");
request.setAttribute("studentList", studentList);
request.getRequestDispatcher("/WEB-INF/views/test/login.jsp").forward(request, response);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
从上面可以看到,这种方式的适配器在获取到数据库的数据之后(上面是模拟获取到数据库查询的数据),将数据放在Request域中,然后再请求转发到对应的视图,这种方式和servlet是一致的。
上面两种方式的适配器实现,都是运用了适配器这种模式,来达到实现不同功能的作用,具体的适配器设计模式,后面再和大家一起学习,这里就不跑偏了。上面的两种适配器还存在两个特点,就是他们都是实现了一个接口,这样就导致业务逻辑只能在重写的方法中进行实现。这也就意味着,一个Handler中只能有一个方法,这样的局限性就很明显了,所以后面基于注解的映射器和适配器就在大家的呼喊中缓缓登场!
基于注解的映射器和适配器
说到基于注解的映射器和适配器,我想是要对springmvc的版本划分来进行学习
在spring 3.1之前的映射器和适配器
注解映射器:
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
- 1
注解适配器:
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
- 1
在spring 3.1之后的映射器和适配器
注解映射器:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
- 1
注解适配器:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
- 1
由于一般我们现在的spirngmvc版本应该是大于spring4了,所以一般在项目中开发中用到就是基于上的RequestMappingHandlerMapping 和RequestMappingHandlerAdapter(但是这种方式还是可以优化的),对于这两种方式,我们还是需要在spirng容器中定义对应的bean来,注意url和对应bean的映射关系,主要是通过@RequestMapping注解来实现的。这个注解想必大家在日常开发中都经常用到,这里就不多说。讲到这里有的小伙伴可能会想,在日常的项目开发中,我们并没有在spring容器中显示声明很多bean啊,这样声明的话,如果有很多bean,这样的配置还是挺烦的。其实,我们在日常开发中是基于注解的,会在springmvc的配置文件,开启包路径扫描。这样就会依据注解找到对应的Controller.
context:component-scan base-package="com.aiqinhai"
- 1
细心的小伙伴,可能会发现,我们在日常开发中,也没有显示在spring容器中声明RequestMappingHandlerMapping,RequestMappingHandlerAdapter这两个类啊,这是怎么回事呢??
其实这都要依靠在springmvc配置文件中的
<mvc:annotation-driven />
- 1
这样一句代码,看起来很简单,这句代码默认加载了很多的参数绑定,例如常见的json数据转换,还有其他消息转换。这个后续会单独结合源码来看看具体加载了哪些参数。