SpringMVC源码解读之HandlerMapping – AbstractUrlHandlerMapping系列request分发

简介

在Spring MVC中,HandlerMapping是一个非常重要的组件,它负责将请求分发给对应的处理器。AbstractUrlHandlerMappingHandlerMapping的一个实现类,它通过URL映射规则来确定请求应该由哪个处理器来处理。本文将详细介绍AbstractUrlHandlerMapping的源码实现,并提供两个示例说明。

AbstractUrlHandlerMapping源码解读

AbstractUrlHandlerMappingHandlerMapping的一个抽象实现类,它提供了一些通用的方法和属性,如urlMaporderpathMatcher等。以下是AbstractUrlHandlerMapping的源码实现。

public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
  private Map<String, Object> urlMap = new LinkedHashMap<>();
  private UrlPathHelper urlPathHelper = new UrlPathHelper();
  private PathMatcher pathMatcher = new AntPathMatcher();
  private boolean useTrailingSlashMatch = true;
  private boolean lazyInitHandlers = false;

  public void setUrlMap(Map<String, ?> urlMap) {
    this.urlMap = new LinkedHashMap<>(urlMap);
  }

  public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
    this.urlPathHelper = (urlPathHelper != null ? urlPathHelper : new UrlPathHelper());
  }

  public void setPathMatcher(PathMatcher pathMatcher) {
    this.pathMatcher = (pathMatcher != null ? pathMatcher : new AntPathMatcher());
  }

  public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
    this.useTrailingSlashMatch = useTrailingSlashMatch;
  }

  public void setLazyInitHandlers(boolean lazyInitHandlers) {
    this.lazyInitHandlers = lazyInitHandlers;
  }

  @Override
  protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    Object handler = lookupHandler(lookupPath, request);
    if (handler == null) {
      handler = getDefaultHandler();
    }
    return handler;
  }

  protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    Object handler = this.urlMap.get(urlPath);
    if (handler == null) {
      handler = lookupHandler(urlPath, request.getMethod());
    }
    return handler;
  }

  protected Object lookupHandler(String urlPath, String httpMethod) throws Exception {
    List<Object> matchingHandlers = new ArrayList<>();
    for (Map.Entry<String, Object> entry : this.urlMap.entrySet()) {
      String mappedPath = entry.getKey();
      Object handler = entry.getValue();
      if (this.pathMatcher.match(mappedPath, urlPath)) {
        if (handler instanceof String) {
          handler = getApplicationContext().getBean((String) handler);
        }
        matchingHandlers.add(handler);
      }
    }
    if (!matchingHandlers.isEmpty()) {
      if (matchingHandlers.size() > 1) {
        matchingHandlers = sortMatchingHandlers(matchingHandlers, urlPath, httpMethod);
      }
      return matchingHandlers.get(0);
    }
    return null;
  }

  protected List<Object> sortMatchingHandlers(List<Object> matchingHandlers, String lookupPath, String httpMethod) {
    if (matchingHandlers.size() > 1) {
      Comparator<Object> comparator = new RequestMappingInfoHandlerMethodMappingNamingComparator(this.pathMatcher, lookupPath);
      if (this.order != null) {
        comparator = new OrderComparator().compare(comparator, this.order);
      }
      if (this.useTrailingSlashMatch) {
        comparator = new TrailingSlashHandlerMappingComparator(lookupPath).compare(comparator, null);
      }
      Collections.sort(matchingHandlers, comparator);
    }
    return matchingHandlers;
  }
}

在上面的源码中,我们可以看到AbstractUrlHandlerMapping定义了一些属性和方法,如urlMapurlPathHelperpathMatcheruseTrailingSlashMatchlazyInitHandlers等。其中,urlMap是一个Map对象,用于存储URL映射规则和对应的处理器;urlPathHelper是一个UrlPathHelper对象,用于获取请求的URL路径;pathMatcher是一个PathMatcher对象,用于匹配URL路径和映射规则;useTrailingSlashMatch表示是否使用尾部斜杠匹配;lazyInitHandlers表示是否延迟初始化处理器。

getHandlerInternal()方法中,我们可以看到AbstractUrlHandlerMapping使用urlPathHelper获取请求的URL路径,并调用lookupHandler()方法查找对应的处理器。如果找不到对应的处理器,则返回默认的处理器。

lookupHandler()方法中,我们可以看到AbstractUrlHandlerMapping首先从urlMap中查找是否有对应的处理器,如果没有,则调用lookupHandler(String urlPath, String httpMethod)方法查找对应的处理器。在lookupHandler(String urlPath, String httpMethod)方法中,AbstractUrlHandlerMapping遍历urlMap中的所有映射规则,使用pathMatcher匹配URL路径和映射规则,找到匹配的处理器后,将其添加到matchingHandlers列表中。如果matchingHandlers列表不为空,则调用sortMatchingHandlers()方法对处理器进行排序,并返回第一个处理器。

示例1:使用AbstractUrlHandlerMapping处理HTTP GET请求

以下是一个使用AbstractUrlHandlerMapping处理HTTP GET请求的示例。

public class HelloController implements Controller {
  @Override
  public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
    ModelAndView modelAndView = new ModelAndView("hello");
    modelAndView.addObject("message", "Hello, World!");
    return modelAndView;
  }
}

public class HelloHandlerMapping extends AbstractUrlHandlerMapping {
  public HelloHandlerMapping() {
    setUrlMap(Collections.singletonMap("/hello", new HelloController()));
    setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
}

public class HelloWebApplicationInitializer implements WebApplicationInitializer {
  @Override
  public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    context.register(HelloHandlerMapping.class);
    context.setServletContext(servletContext);
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");
  }
}

在上面的示例中,我们首先定义了一个HelloController类,它实现了Controller接口,并在handleRequest()方法中返回一个ModelAndView对象。然后,我们定义了一个HelloHandlerMapping类,它继承了AbstractUrlHandlerMapping类,并在构造函数中使用setUrlMap()方法设置了URL映射规则和对应的处理器。最后,我们定义了一个HelloWebApplicationInitializer类,它实现了WebApplicationInitializer接口,并在onStartup()方法中注册了HelloHandlerMapping类和DispatcherServlet

示例2:使用AbstractUrlHandlerMapping处理HTTP POST请求

以下是另一个使用AbstractUrlHandlerMapping处理HTTP POST请求的示例。

public class CalculatorController implements Controller {
  @Override
  public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
    int a = Integer.parseInt(request.getParameter("a"));
    int b = Integer.parseInt(request.getParameter("b"));
    int result = a + b;
    ModelAndView modelAndView = new ModelAndView("result");
    modelAndView.addObject("result", result);
    return modelAndView;
  }
}

public class CalculatorHandlerMapping extends AbstractUrlHandlerMapping {
  public CalculatorHandlerMapping() {
    setUrlMap(Collections.singletonMap("/calculator", new CalculatorController()));
    setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
}

public class CalculatorWebApplicationInitializer implements WebApplicationInitializer {
  @Override
  public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    context.register(CalculatorHandlerMapping.class);
    context.setServletContext(servletContext);
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");
  }
}

在上面的示例中,我们首先定义了一个CalculatorController类,它实现了Controller接口,并在handleRequest()方法中获取请求参数ab,计算结果后返回一个ModelAndView对象。然后,我们定义了一个CalculatorHandlerMapping类,它继承了AbstractUrlHandlerMapping类,并在构造函数中使用setUrlMap()方法设置了URL映射规则和对应的处理器。最后,我们定义了一个CalculatorWebApplicationInitializer类,它实现了WebApplicationInitializer接口,并在onStartup()方法中注册了CalculatorHandlerMapping类和DispatcherServlet

总结

本文详细介绍了AbstractUrlHandlerMapping的源码实现,并提供了两个示例说明。我们首先介绍了AbstractUrlHandlerMapping的属性和方法,如urlMapurlPathHelperpathMatcheruseTrailingSlashMatchlazyInitHandlers等。然后,我们提供了一个使用AbstractUrlHandlerMapping处理HTTP GET请求的示例和一个使用AbstractUrlHandlerMapping处理HTTP POST请求的示例。通过本文的介绍,我们可以了解到如何在Spring MVC应用程序中使用AbstractUrlHandlerMapping来分发请求。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringMVC源码解读之HandlerMapping – AbstractUrlHandlerMapping系列request分发 - Python技术站

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

相关文章

  • java统计字符串中指定元素出现次数方法

    Java统计字符串中指定元素出现次数方法攻略 在Java中统计字符串中指定元素出现次数,我们通常有以下几种方法: 1. 使用正则表达式 我们可以使用正则表达式来匹配指定元素出现的次数。下面是一个示例代码: public static int countOccurrencesUsingRegex(String str, String element) { St…

    Java 2023年5月27日
    00
  • Java系统变量参数获取设置System.getProperties()的方法

    使用Java的System类提供了访问系统级别变量的方法,其中包括了Java系统变量。可以使用System.getProperties()方法来获取当前Java虚拟机的系统属性和变量,并可以进行进一步操作。 具体步骤如下: 1. 使用System.getProperties()方法获取Java系统变量 可以使用以下代码获取Java虚拟机的所有系统变量: Pr…

    Java 2023年6月15日
    00
  • PHP:微信小程序 微信支付服务端集成实例详解及源码下载

    PHP:微信小程序微信支付服务端集成实例详解 在本文中,我们将为大家讲解如何在 PHP 中集成微信支付服务端,并包含了两个具体的示例。 准备工作 在开始集成之前,需要完成以下准备工作: 注册微信支付账号 在微信支付后台配置公众号或小程序,并设置回调地址 安装 curl 扩展 集成微信支付服务端 首先,我们需要在 PHP 代码中引用微信支付 SDK,可以使用 …

    Java 2023年5月23日
    00
  • java在运行时能修改工作目录吗

    Java程序在运行时可以修改工作目录,可通过以下方式实现: 使用Java的File类修改工作目录 Java提供了File类来操作文件与目录,通过File类提供的方法可以对现有的目录进行修改。 可以通过以下代码来修改工作目录: File dir = new File("D:\\Java_Project"); System.setProper…

    Java 2023年6月15日
    00
  • Java十分钟精通异常处理机制

    Java 十分钟精通异常处理机制 异常是一种程序中发生错误的情况,Java 提供了异常处理机制,能够更加优雅地处理这种错误。本文将介绍 Java 异常处理机制的基础知识和常用语法,让你在十分钟内精通异常处理机制。 异常的分类 Java 中的异常可以分为两种:受检异常(Checked Exception)和非受检异常(Unchecked Exception)。…

    Java 2023年5月27日
    00
  • 微信小程序实时聊天WebSocket

    下面为您详细讲解“微信小程序实时聊天WebSocket”的完整攻略。 一、前期准备 了解WebSocket协议的基础知识,包括握手过程、消息格式等; 了解微信小程序基础知识,包括小程序开发、页面结构、组件等; 确保开发环境已经安装好,包括微信web开发者工具、编辑器等。 二、创建WebSocket连接 微信小程序提供了wx.connectSocket() A…

    Java 2023年5月23日
    00
  • 多种方法实现当jsp页面完全加载完成后执行一个js函数

    实现当JSP页面完全加载完成后执行一个JS函数,可以通过以下两种方法实现: 方法一:window.onload 在window对象上添加onload事件处理程序,当JSP页面全部加载完成后就会执行该处理程序。在该处理程序中可以调用JS函数。 <script> window.onload = function() { myFunction(); }…

    Java 2023年6月15日
    00
  • JAVA文件读写操作详解

    JAVA文件读写操作详解 什么是文件读写操作 文件读写操作是指对于指定的文件,通过程序的方式读取其中的数据或者将程序中的数据写入到文件中。文件读写操作是一个底层的技术,基本上所有的软件开发都会用到这个技术。 JAVA文件读写操作的常用类 在JAVA中,文件读写操作主要涉及到以下几个类: File类:代表文件和目录的抽象表示。通过对File类的操作,可以创建、…

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