SpringMVC实战(详解)丨HandlerMapping与HandlerAdapter

    /    2018-07-31

SpringMVC是由C-Dispatcher、M-HanlderMapping、HandlerAdapter、Handler、V-ViewResolver三部分组成,我们在Web.xml中加入了一个spring的字符集拦截器CharacterEncodingFilter构成了SpringMVC。

今天我们讲一下映射器HandlerMapping与HandlerAdapter。

1. BeanNameUrlHandlerMapping

匹配Spring容器Bean的Name找到的Bean(程序员编写Hanlder),springmvc.xml中配置如下代码:

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<!-- 2.1 BeanNameUrlHandlerMapping controller配置 -->
<bean name="/items1" id="itemList1" class="com.spring.Controller.ItemController"/>


SimpleUrlHandlerMapping

BeanNameHandlerMapping的升级版,因为它可以统一配置Controller里面对应Url

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
            <property name="mappings">
                <props>
                    <prop key="/simpleItems1" >simpleController1</prop>
                    <prop key="/simpleItems2" >simpleController1</prop>
                </props>
            </property>
        </bean>
<bean  id="simpleController1" class="com.ycy.controller.ItemController"/>


注意:benaname与simple两者同时配置,那么两者同时有效。

2.SimpleControllerHandlerAdapter

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter">
        </bean>


要求程序编写的Handler(Controller)需要实现 Controller接口

package
import com.ycy.model.Items;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
/**
 * 
 */
public class ItemController implements Controller {
 
    public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest,
                                      javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
        //商品列表
        List<Items> itemsList = new ArrayList<Items>();
 
        Items items_1 = new Items();
        items_1.setName("联想笔记本");
        items_1.setPrice(6000f);
        items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
        items_1.setCreatetime(new Date());
 
        Items items_2 = new Items();
        items_2.setName("苹果手机");
        items_2.setPrice(5000f);
        items_2.setDetail("iphone6苹果手机!");
        items_2.setCreatetime(new Date());
        itemsList.add(items_1);
        itemsList.add(items_2);
 
        //创建modelAndView准备填充数据、设置视图
        ModelAndView modelAndView = new ModelAndView();
        httpServletRequest.setCharacterEncoding("utf-8");
        //填充数据
        modelAndView.addObject("itemsList", itemsList);
        //视图
        modelAndView.setViewName("order/itemsList");
 
        return modelAndView;
    }
}


HttpRequestHandlerAdapter

要求Handler 实现 HttpRequestHandler接口

<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter">
        </bean>
package 
import com.ycy.model.Items;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
/**
 * Created by Administrator on 2015/9/17 0017.
 */
public class ItemController2 implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
        //商品列表
        List<Items> itemsList = new ArrayList<Items>();
 
        Items items_1 = new Items();
        items_1.setName("联想笔记本");
        items_1.setPrice(6000f);
        items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
        items_1.setCreatetime(new Date());
 
        Items items_2 = new Items();
        items_2.setName("苹果手机");
        items_2.setPrice(5000f);
        items_2.setDetail("iphone6苹果手机!");
        items_2.setCreatetime(new Date());
        itemsList.add(items_1);
        itemsList.add(items_2);
 
        //创建modelAndView准备填充数据、设置视图
        ModelAndView modelAndView = new ModelAndView();
        httpServletRequest.setCharacterEncoding("utf-8");
        httpServletRequest.setAttribute("itemsList", itemsList);
            httpServletRequest.getRequestDispatcher("pages/jsp/order/itemsList.jsp").forward(httpServletRequest,httpServletResponse);
    }
 
}


3.注解处理器映射器与适配器

spring3.1版本之前加载映射器

org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

spring3.1之后用org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping

也是源码解读:

/org/springframework/spring-webmvc/4.2.0.RELEASE/spring-webmvc-4.2.0.RELEASE.jar!/org/springframework/web/servlet/DispatcherServlet.properties

里面清楚记载了先加载谁在springmvc.xml中配置

RequestMappingHandlerMapping:

使用RequestMappingHandlerMapping需要在Handler 中使用@controller标识此类是一个控制器,使用@requestMapping指定Handler方法所对应的url。

<!--
         2.3使用注解RequestMappingInfoHandlerMapping映射器
         注解映射器配对使用,主要解析Handler方法中的形参
         单个:
         <bean class="com.ycy.controller.ItemController3"/>
        -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
        </bean>
 
        <context:component-scan base-package="com.ycy.controller"/>


注解适配器

spring3.1版本之前org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

spring3.1版本之后org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter

<!--
        3.3 RequestMappingHandlerAdapter:注解适配器,与RequestMappingInfoHandlerMapping配对使用
        -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>


Controler

package com.ycy.controller;

import com.ycy.model.Items;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
 
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
/**
 * Created by Administrator on 2015/9/17 0017.
 */
@Controller
public class ItemController3 {
    @RequestMapping("/queryItems")//建议与方法名称一致
    public ModelAndView queryItems(javax.servlet.http.HttpServletRequest httpServletRequest,
                                      javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
        //商品列表
        List<Items> itemsList = new ArrayList<Items>();
 
        Items items_1 = new Items();
        items_1.setName("联想笔记本");
        items_1.setPrice(6000f);
        items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
        items_1.setCreatetime(new Date());
 
        Items items_2 = new Items();
        items_2.setName("苹果手机");
        items_2.setPrice(5000f);
        items_2.setDetail("iphone6苹果手机!");
        items_2.setCreatetime(new Date());
        itemsList.add(items_1);
        itemsList.add(items_2);
 
        //创建modelAndView准备填充数据、设置视图
        ModelAndView modelAndView = new ModelAndView();
        httpServletRequest.setCharacterEncoding("utf-8");
        //填充数据
        modelAndView.addObject("itemsList", itemsList);
        //视图
        modelAndView.setViewName("order/itemsList");
 
        return modelAndView;
    }
}


访问结果url:

http://localhost:8080/spring01/queryItems

4.SpringMVC总结分析

前面我们清楚了一下流程,现在我们看看spring源码分析,到底这些流程是怎么来的!

DispatcherServlet

前端控制器,中央指挥机器,降低组件之间的耦合度。

HandlerMappring

负责处理器映射,根据url找到Handle。

HandlerAdapter

处理器适配器,根据处理器需求执行适配器。可以通过扩展适配器支持不同类型的Handler 例如:Struts2

ViewResolver

视图解析器,根据逻辑视图解析为真正的视图。视图地址=前缀+逻辑视图名+后缀

视图解析器配置:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
            <property name="prefix" value="/pages/jsp/"/>
            <property name="suffix" value=".jsp"/>
        </bean>


执行流程

DispatcherServlet

我们进入该类看到doDispatch这个方法有个注释:

Process the actual dispatching to the handler

翻译:进程调度的实际处理程序。

这个就是我们的中心处理程序方法:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
 
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
 
            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
 
                // Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
 
                // Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
 
                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
 
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
 
                // Actually invoke the handler.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
 
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
 
                applyDefaultViewName(processedRequest, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }


1) Dispatcher通过Hander查询handle

2)Dispatcher 通过适配器执行Handler,得到ModelAndView

3)得到ModelAndView,解析视图

解析视图最里层我们看看。再往里,其实就是网request里面放置属性了

jiangmodle数据填充到request中

(12)

分享至