浅谈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日

相关文章

  • jsp使用sessionScope获取session案例详解

    当我们在使用JSP进行开发时,经常需要使用到session来存储用户的信息。使用session,能够方便地在多个页面之间共享数据,因此我们需要掌握如何使用session。在本篇攻略中,我们将会使用sessionScope对象来获取session,并带您演示两个简单的使用示例。 什么是session? 在Web开发中,服务器与客户端之间通信使用的是HTTP协议…

    Java 2023年6月15日
    00
  • JSP中常用的JSTL fmt(format格式化)标签用法整理

    当我们在JSP页面中需要对显示的内容进行格式化时,JSTL fmt标签库提供了一些非常便捷的方法。下面就来整理一下JSTL fmt标签的一些用法。 JSTL fmt标签的引入 我们需要在JSP页面中引入以下标签库: <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/j…

    Java 2023年6月15日
    00
  • Spring Security如何在Servlet中执行

    Spring Security 是 Spring 框架中的一个安全框架,可以用于保护 Web 应用程序的安全,包括身份验证、授权、防止攻击等功能。在 Servlet 中使用 Spring Security 可以有效地保护应用程序的安全,下面是详细的使用攻略。 1. 添加 Spring Security 依赖 首先,需要在项目中添加 Spring Securi…

    Java 2023年5月20日
    00
  • 在PHP上显示JFreechart画的统计图方法

    在PHP上显示JFreechart画的统计图方法需要以下步骤: 在PHP上安装Java环境 因为JFreeChart是Java编写的,所以需要先在PHP上安装Java环境。可以通过下载Java Runtime Environment (JRE)或Java Development Kit (JDK)来实现。安装好之后,可以通过命令行输入“java -versi…

    Java 2023年6月15日
    00
  • Jenkins初级使用过程中的异常处理

    Jenkins初级使用过程中的异常处理 Jenkins作为一款自动化构建工具,在使用过程中难免会遇到一些异常情况。以下是几个常见的问题以及解决方法。 1. 账号密码认证失败 当我们在Jenkins的Job配置中设置了账号密码凭据,但通过验证时发现提示“验证失败”等错误信息。这种情况下,应该检查以下几个问题: 账号密码是否输入正确 账号密码凭据是否拥有足够授权…

    Java 2023年5月25日
    00
  • 在js与java中判断json数据中是否含有某字段的案例

    在 JS 中判断 JSON 数据中是否含有某字段的方法如下: 使用 in 运算符: const jsonData = { name: ‘Tom’, age: 18 }; if (‘name’ in jsonData) { console.log(‘jsonData 存在 name 字段’); } 使用 hasOwnProperty() 方法: const j…

    Java 2023年5月26日
    00
  • 详解kotlin中::双冒号的使用

    详解kotlin中::双冒号的使用 在Kotlin中,双冒号::是一个重要的语法符号,它可以表示一些函数和属性的引用。双冒号有以下用法: 1. 表示函数引用 可以使用::符号来表示一个函数的引用,例如: fun plus(a: Int, b: Int): Int = a + b val functionRef = ::plus 在上面的代码中,functio…

    Java 2023年5月26日
    00
  • java的Hibernate框架报错“SQLGrammarException”的原因和解决方法

    当使用Java的Hibernate框架时,可能会遇到“SQLGrammarException”错误。这个错误通常是由于以下原因之一引起的: SQL语法错误:如果您的SQL语法不正确,则可能会出现此错误。在这种情况下,需要检查您的SQL语法以解决此问题。 数据库表或列不存在:如果您的SQL语句引用了不存在的数据库表或列,则可能会出现此错误。在这种情况下,需要检…

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