浅谈SpringMVC请求映射handler源码解读

以下是关于“浅谈SpringMVC请求映射handler源码解读”的完整攻略,其中包含两个示例。

浅谈SpringMVC请求映射handler源码解读

SpringMVC是一个基于MVC模式的Web框架,它的核心是请求映射handler。在本文中,我们将深入了解SpringMVC请求映射handler的源代码。

步骤一:创建Maven项目

  1. 打开IntJ IDEA,选择“Create New Project”。

  2. 选择“Maven”并点击“Next”。

  3. 输入项目的GroupId、Id和Version,并选择项目的存储路径。点击“Next”。

  4. 选择项目的类型和模板。点击“Next”。

5.项目的名称和描述。点击“Finish”。

步骤二:添加Spring MVC依赖

  1. 开pom.xml。

  2. 标签中添加以下依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.9</version>
</dependency>

步骤三:创建Controller

  1. 在src/main/java目录下创建一个名为com.example.controller的包。

  2. 在com.example.controller包创建一个名为HelloController的类。

  3. 在HelloController类中添加以下内容:

package com.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {

    @RequestMapping("/hello")
    @ResponseBody
    public String hello() {
        return "Hello, World!";
    }

}

在本示例中,我们实现了一个HelloController,用于处理/hello请求。我们使用@Controller注解来标识HelloController类。我们使用@RequestMapping注解来指定请求的URL。我们使用@ResponseBody注解来指定返回的内容。

步骤四:启动应用程序

  1. 在IntelliJ IDEA中,右键单击HelloController类,选择“Run HelloController.main()”。

  2. 在浏览器中输入http://localhost:8080/hello,应该会看到“Hello, World!”的输出。

步骤五:源码解读

  1. 打开HelloController类,找到@RequestMapping注解。
@RequestMapping("/hello")

@RequestMapping注解用于将请求URL映射到处理器方法。在本示例中,我们将/hello请求映射到hello方法。

  1. 打开DispatcherServlet类,找到doDispatch方法。
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) {
                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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            // Apply preHandle methods of registered interceptors.
            HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
            if (interceptors != null) {
                for (int i = 0; i < interceptors.length; i++) {
                    HandlerInterceptor interceptor = interceptors[i];
                    if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
                        triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
                        return;
                    }
                    interceptorIndex = i;
                }
            }

            // Actually invoke the handler.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            // Do we need view name translation?
            if (mv != null && !mv.hasView()) {
                mv.setViewName(getDefaultViewName(request));
            }

            // Apply postHandle methods of registered interceptors.
            if (interceptors != null) {
                for (int i = interceptors.length - 1; i >= 0; i--) {
                    HandlerInterceptor interceptor = interceptors[i];
                    interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
                }
            }
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }

        // Trigger afterCompletion callbacks on registered interceptors.
        if (mappedHandler != null && interceptorIndex != -1) {
            for (int i = interceptorIndex; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                try {
                    interceptor.afterCompletion(processedRequest, response, mappedHandler.getHandler(), dispatchException);
                }
                catch (Throwable ex) {
                    logger.error("HandlerInterceptor.afterCompletion threw exception", ex);
                }
            }
        }

        // If we already have a view, we're already rendering.
        if (mv != null && !mv.wasCleared()) {
            render(mv, processedRequest, response);
            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
        }
        else {
            // We might still need view name translation for a redirect, even if we don't have a view instance to render yet.
            if (multipartRequestParsed && !response.isCommitted() && mv != null && mv.hasView()) {
                String viewName = mv.getViewName();
                if (viewName.startsWith("redirect:")) {
                    render(mv, processedRequest, response);
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                }
            }
        }

        if (asyncManager.isConcurrentHandlingStarted()) {
            // Concurrent handling started during a forward
            if (mv == null) {
                mv = new ModelAndView();
            }
            if (!asyncManager.isConcurrentHandlingCompleted()) {
                handleAsyncException(request, response, mappedHandler, dispatchException, mv);
                return;
            }
        }

        if (mv != null && !mv.wasCleared()) {
            render(mv, processedRequest, response);
        }
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("No view rendering, null ModelAndView returned.");
            }
        }

        if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Concurrent handling started during a forward
            return;
        }

        // Clean up any resources used by a multipart request.
        if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
        }
    }
    catch (Exception ex) {
        triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
    }
    catch (Throwable err) {
        // As of 4.3, we're processing Errors thrown from handler methods as well,
        // making them available for @ExceptionHandler methods and other scenarios.
        Exception ex = new NestedServletException("Handler processing failed", err);
        triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Restore the original request before handling the error.
            if (processedRequest instanceof MultipartHttpServletRequest) {
                restoreMultipart((MultipartHttpServletRequest) processedRequest);
            }
        }
    }
}

doDispatch方法是DispatcherServlet的核心方法,它用于处理所有的请求。在本示例中,我们使用doDispatch方法来处理/hello请求。

  1. 打开RequestMappingHandlerMapping类,找到getHandlerInternal方法。
protected HandlerExecutionChain getHandlerInternal(HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request, LOOKUP_PATH);
    List<T> directPathMatches = this.handlerMap.get(lookupPath);
    if (directPathMatches != null) {
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        addMatchingMappings(this.corsHandlerMappings, matches, request);
        if (matches.isEmpty()) {
            addMatchingMappings(this.handlerMappings, matches, request);
        }
    }
    if (!matches.isEmpty()) {
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            matches.sort(comparator);
            if (logger.isTraceEnabled()) {
                logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
            }
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() +
                        "': {" + m1 + ", " + m2 + "}");
            }
        }
        HandlerMethod handlerMethod = bestMatch.handlerMethod;
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, handlerMethod);
        HandlerInterceptor[] interceptors = handlerMethod.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            request.setAttribute(HANDLER_INTERCEPTOR_LIST_ATTRIBUTE, interceptors);
        }
        return bestMatch.handlerMethod.getHandlerExecutionChain();
    }
    else {
        return null;
    }
}

getHandlerInternal方法用于获取请求映射handler。在本示例中,我们使用getHandlerInternal方法来获取/hello请求的handler。

  1. 打开RequestMappingInfo类,找到getMatchingCondition方法。
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
    RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
    ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
    HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
    ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
    ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
    RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
    return new RequestMappingInfo(this.patternsCondition.getMatchingCondition(request),
            methods, params, headers, consumes, produces, custom);
}

getMatchingCondition方法用于获取请求映射条件。在本示例中,我们使用getMatchingCondition方法来获取/hello请求的请求映射条件。

示例

以下是另一个示例,演示如何使用@RequestMapping注解来指定多个URL:

@Controller
@RequestMapping({"/hello", "/hi"})
public class HelloController {

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public String hello() {
        return "Hello, World!";
    }

}

在本示例中,我们使用@RequestMapping注解来指定/hello和/hi两个URL。我们使用@RequestMapping注解来指定处理器方法的请求映射条件。

总结

SpringMVC请求映射handler是SpringMVC的核心。我们可以使用@RequestMapping注解来指定请求映射条件。我们可以使用DispatcherServlet类来处理所有的请求。我们可以使用RequestMappingHandlerMapping类来获取请求映射handler。我们可以使用RequestMappingInfo类来获取请求映射条件。在使用SpringMVC时,我们需要遵循SpringMVC规范,确保代码可维护性和可扩展性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈SpringMVC请求映射handler源码解读 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • mybatis查询实现返回List类型数据操作

    Sure! 什么是MyBatis MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java 的 POJO(Plain Old Java Objects)为数据库中的记录…

    Java 2023年5月19日
    00
  • Java面试题之HashMap 的 hash 方法原理是什么

    HashMap 的 hash 方法原理是什么 在了解HashMap的原理之前, 我们先看看hash散列表是怎么工作的, 他的原理是什么。 散列表的原理是将关键字通过散列函数映射到固定的位置上, 并对原始值进行处理, 最终得到的值就是我们所说的哈希值, 即在HashMap中所表现出来的值。在JDK1.7之前,HashMap的内部实现方式是数组 + 链表,数组的…

    Java 2023年5月26日
    00
  • IDEA 非常重要的一些设置项(一连串的问题差点让我重新用回 Eclipse)

    下面是“IDEA 非常重要的一些设置项”的完整攻略。 1. 自动导入包的设置 开发中,我们需要使用很多的类。在使用类的时候,IDEA 会自动提示我们需要导入的包。但是,如果包的数量很多,我们可能会忘记导入某些包。 为了避免这种情况,我们可以设置 IDEA 在自动提示需要导入的包时,自动导入缺少的包。在 IDEA 的设置中,点击 Editor > Gen…

    Java 2023年5月20日
    00
  • 详解Java如何实现图像灰度化

    我将详细讲解“详解Java如何实现图像灰度化”的完整攻略。图像灰度化是指将彩色图像转化为灰度图像的过程,在这个过程中,我们将三个色彩通道的像素值转化为灰度值,转化公式如下: $gray = 0.299 * r + 0.587 * g + 0.114 * b$ 其中 $r, g, b$ 表示红、绿、蓝三个通道的像素值。使用这个公式,我们可以将一个彩色图像转化为…

    Java 2023年5月26日
    00
  • Java异常处理try catch的基本使用

    Java异常处理try catch的基本使用 在Java编程中,程序执行过程中可能出现各种错误,例如文件找不到,数组越界等,这些错误被称为异常。异常处理是Java编程中最基本的编程技巧之一。Java异常处理try catch提供了一种结构化的异常处理方法,可以使程序更加健壮,便于维护。 什么是Java异常处理try catch Java异常处理try cat…

    Java 2023年5月27日
    00
  • SpringBoot基于Mybatis-Plus自动代码生成

    下面是关于“Spring Boot基于Mybatis-Plus自动代码生成”的完整攻略: 1. 简介 Mybatis-Plus是Mybatis的一个开源插件,提供了许多功能,例如自动代码生成、通用CRUD操作、分页和逻辑删除等。通过Spring Boot和Mybatis-Plus的结合,我们可以快速构建高效的数据库操作应用程序。 2. 步骤 2.1 配置po…

    Java 2023年5月20日
    00
  • ASP.NET微信公众号添加菜单

    下面我将为您详细讲解“ASP.NET微信公众号添加菜单”的完整攻略。 1. 准备工作 首先,在进行微信公众号开发之前,我们需要准备以下工作: 申请微信公众号账号,并获取到对应的AppID和AppSecret。 下载微信公众号开发者工具,该工具可帮助我们进行调试和预览。 创建一个ASP.NET项目,并引入微信公众平台SDK。 2. 添加菜单 在准备工作完成后,…

    Java 2023年5月23日
    00
  • Javabean简介_动力节点Java学院整理

    Javabean简介:动力节点Java学院整理 什么是Javabean? Javabean是Java语言写成的、可重用的组成部分。它们实际上是简单的Java类,其中包括了表达业务层概念的属性和方法。Javabean对外暴露一个无参构造函数,并且使用一定的规范来描述它的属性和方法 Javabean命名规范 Javabean命名一般采用驼峰式的命名方式 Java…

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部