SpringMVC(3)之处理器映射器和适配器
一、处理器映射器和适配器
非注解的处理映射器2种:
(处理器映射器HandlerMapping,负责根据request请求,找到对应的Handler处理器和拦截器,然后封装在HandlerExecutionChain对象中,最后返回给中央调度器,常用的实现类见以下俩种)
1.BeanNameUrlHandlerMapping: 会根据请求的url与spring中定义的处理器bean的name属性值进行匹配,从而在spring中找到处理器bean(这种方式bean id必须以“/”开头,否则无法加到url数组中)
//注册处理器映射器BeanNameUrlHandlerMapping <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> //注册处理器Handel <bean name="/queryItems.action" class="com.dmz.ssm.controller.ItemsController"></bean>
PS:为什么必须以“/”方式开头,详情见源码如下图
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping { public BeanNameUrlHandlerMapping() { } protected String[] determineUrlsForHandler(String beanName) { List<String> urls = new ArrayList(); if (beanName.startsWith("/")) { urls.add(beanName); } String[] aliases = this.getApplicationContext().getAliases(beanName); String[] var4 = aliases; int var5 = aliases.length; for(int var6 = 0; var6 < var5; ++var6) { String alias = var4[var6]; if (alias.startsWith("/")) { urls.add(alias); } } return StringUtils.toStringArray(urls); } }
BeanNameUrlHandlerMapping不足之处:
1.处理器的id名称是一个url,并不是bean的名称,有些不伦不类
2.处理器的定义与请求的url绑在一起,若出现多个url请求同一个处理器的情况,就需要在spring容器中配置多个处理器类的bean
2.SimpleUrlHandlerMapping
SimpleUrlHandlerMapping处理映射器,可以将url与处理器的定义分离,还可以对url进行统一管理,该映射器会根据请求的url与spring容器中定义的处理器映射器,子标签的key属性进行匹配,匹配上后,在根据key的value值与处理器bean的id进行匹配,从而在spring中找到处理器bean
//注册处理器映射器SimpleUrlHandlerMapping <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <!--第一种 <prop key="/queryItemsone.action">myController</prop> <prop key="/queryItemstwo.action">myController</prop> --> <!--第二种 <prop key="/queryItemsone.action" value="myController"/> <prop key="/queryItemstwo.action" value="myController"/> --> //以上俩种方式都可以根据key,访问到myController </props> </property> </bean> //注册处理器 <bean id="myController" class="com.dmz.ssm.controller.ItemsController"></bean>
非注解的处理适配器2种:
(处理器适配器HandlerAdapter)
1.SimpleControllerHandlerAdapter底层调用Controller.handlerRequest(request,response);看源码如下:
//代码实现 public class ItemsControllerone implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception { ModelAndView modelAndView = new ModelAndView(); //相当于request的setAttribute方法 modelAndView.addObject("msg",hello); modelAndView.setViewName("/WEB-INF/jsp/itemsList.jsp"); return modelAndView; } }
//源码 public class SimpleControllerHandlerAdapter implements HandlerAdapter { public SimpleControllerHandlerAdapter() { } public boolean supports(Object handler) { return handler instanceof Controller; } public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //这里调用Controller.handleRequest return ((Controller)handler).handleRequest(request, response); } public long getLastModified(HttpServletRequest request, Object handler) { return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L; } }
2.HttpRequestHandlerAdapter底层调用HttpRequestHandler.handlerRequest(request,response);看源码如下:
//代码实现 public class ItemsControllerone implements HttpServletRequest { @Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //设置模型数据 request.setAttribute("msg",hello); //设置转发的视图 request.getRequestDispatcher("/WEB-INF/jsp/items/itemsList.jsp").forward(request, response); //使用此方法可以通过修改response,设置响应的数据格式,比如响应json格式 /*response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("json串");*/ } }
//源码 public class HttpRequestHandlerAdapter implements HandlerAdapter { public HttpRequestHandlerAdapter() { } public boolean supports(Object handler) { return handler instanceof HttpRequestHandler; } public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //这里调用的是HttpRequestHandler.handleRequest ((HttpRequestHandler)handler).handleRequest(request, response); return null; } public long getLastModified(HttpServletRequest request, Object handler) { return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L; } }
下面说一下具体自定义的controller 里面的handleRequest方法是怎么被调用的,见源码DispatcherServlet类的doDispatch方法
如果实现的是Controller接口,则需要使用SimpleControllerHandlerAdapter适配器来执行自定义Controller,若使用HttpRequestHandlerAdapter无法把Controller转换为HttpRequestHandler,执行时会报错,反之如果是HttpRequestHandler接口需要使用HttpRequestHandlerAdapter适配器
在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping注解映射器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping注解映射器。
<!--================注解的处理器映射器==============================-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 注解适配器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter 注解适配器
<!--================注解的适配器==============================-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
Handler 单个配置
<!-- 配置Handler -->
<bean class="spring.ssm.controller.ItemsController3"/>
Handler 使用组件扫描配置
<context:component-scan base-package="com.iot.ssm.controller"></context:component-scan>
注意: 使用mvc:annotation-driven代替上面两个注解映射器和注解适配的配置 mvc:annotation-driven默认加载很多的参数绑定方法, 比如json转换解析器默认加载了 如果使用mvc:annotation-driven则不用配置上面的RequestMappingHandlerMapping和RequestMappingHandlerAdapter实际开发时使用mvc:annotation-driven