详解SpringMVC从基础到源码

以下是关于“详解SpringMVC从基础到源码”的完整攻略,其中包含两个示例。

详解SpringMVC从基础到源码

SpringMVC是一个基于MVC模式的Web框架,它提供了一种灵活、高效的方式来开发Web应用程序。在本攻略中,我们将从基础概念到源码实现,全面讲解SpringMVC的工作原理和实现细节。

SpringMVC基础概念

MVC模式

MVC模式是一种软件设计模式,它将应用程序分为三个部分:模型、视图和控制器。模型表示应用程序的数据和业务逻辑,视图表示应用程序的用户界面,控制器负责协调模型和视图之间的交互。

在SpringMVC中,模型、视图和控制器分别对应以下组件:

  • 模型:业务逻辑组件和数据访问组件。
  • 视图:JSP、Thymeleaf等模板引擎。
  • 控制器:DispatcherServlet。

DispatcherServlet

DispatcherServlet是SpringMVC的核心组件,它负责接收所有的请求,并将请求分发给对应的控制器进行处理。在SpringMVC中,我们需要在web.xml文件中配置DispatcherServlet。

以下是一个web.xml文件的示例:

<web-app>
    <servlet>
        <servlet-name>Servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/dispatcherServlet-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url>
    </servlet-mapping>
</web-app>

在本示例中,我们定义了一个名为dispatcherServlet的Servlet,并将其映射到根路径"/"。我们使用元素指定了DispatcherServlet的类名,并使用元素指定了DispatcherServlet的配置文件路径。

HandlerMapping

HandlerMapping是SpringMVC的组件之一,它负责将请求映射到对应的控制器进行处理。在SpringMVC中,我们可以使用多种方式来配置HandlerMapping,例如注解、XML配置等。

以下是一个使用注解配置HandlerMapping的示例:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example.controller")
public class AppConfig implements WebMvcConfigurer {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    }
}

在本示例中,我们使用@Configuration注解标识AppConfig类为配置类,并使用@EnableWebMvc注解启用SpringMVC。我们使用@ComponentScan注解指定了控制器所在的包路径。在configureDefaultServletHandling()方法中,我们启用了默认的Servlet处理。在addViewControllers()方法中,我们添加了一个视图控制器,将根路径"/"映射到index视图。在addResourceHandlers()方法中,我们添加了一个资源处理器,将/static/路径下的静态资源映射到/static/**路径。

HandlerAdapter

HandlerAdapter是SpringMVC的组件之一,它负责将请求分发给对应的控制器进行处理,并将处理结果封装成ModelAndView对象返回给DispatcherServlet。在SpringMVC中,我们可以使用多种方式来配置HandlerAdapter,例如注解、XML配置等。

以下是一个使用注解配置HandlerAdapter的示例:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example.controller")
public class AppConfig implements WebMvcConfigurer {
    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
        RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
        adapter.setArgumentResolvers(Collections.singletonList(new RequestParamMethodArgumentResolver()));
        adapter.setMessageConverters(Collections.singletonList(new MappingJackson2HttpMessageConverter()));
        return adapter;
    }
}

在本示例中,我们使用@Bean注解定义了一个名为requestMappingHandlerAdapter的HandlerAdapter,并使用setArgumentResolvers()方法和setMessageConverters()方法分别配置了请求参数解析器和消息转换器。

SpringMVC源码实现

DispatcherServlet源码实现

DispatcherServlet的源码实现位于org.springframework.web.servlet包中。以下是DispatcherServlet的核心方法doDispatch()的源码实现:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    ModelAndView mv = null;
    Exception dispatchException = null;

    try {
        processedRequest = checkMultipart(request);
        mappedHandler = getHandler(processedRequest);
        if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
        }

        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    }
    catch (Exception ex) {
        dispatchException = ex;
    }
    catch (Throwable err) {
        dispatchException = new NestedServletException("Handler dispatch failed", err);
    }

    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}

在本方法中,我们首先调用checkMultipart()方法对请求进行处理,然后调用getHandler()方法获取对应的HandlerExecutionChain对象。如果获取不到HandlerExecutionChain对象,则调用noHandlerFound()方法进行处理。如果获取到HandlerExecutionChain对象,则调用getHandlerAdapter()方法获取对应的HandlerAdapter对象,并调用handle()方法进行处理。最后,我们调用processDispatchResult()方法对处理结果进行处理。

HandlerMapping源码实现

HandlerMapping的源码实现位于org.springframework.web.servlet包中。以下是RequestMappingHandlerMapping的源码实现:

public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
    @Override
    protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
        super.registerHandlerMethod(handler, method, mapping);
    }

    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                info = typeInfo.combine(info);
            }
        }
        return info;
    }

    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        RequestMapping requestMapping = AnnotationUtils.getAnnotation(element, RequestMapping.class);
        if (requestMapping != null) {
            return RequestMappingInfo.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
                    .methods(requestMapping.method())
                    .params(requestMapping.params())
                    .headers(requestMapping.headers())
                    .consumes(requestMapping.consumes())
                    .produces(requestMapping.produces())
                    .mappingName(requestMapping.name())
                    .options(this.config)
                    .build();
        }
        return null;
    }
}

在本示例中,我们继承了AbstractHandlerMethodMapping类,并实现了registerHandlerMethod()方法和getMappingForMethod()方法。在registerHandlerMethod()方法中,我们调用了父类的registerHandlerMethod()方法。在getMappingForMethod()方法中,我们调用了createRequestMappingInfo()方法创建RequestMappingInfo对象,并使用combine()方法将RequestMappingInfo对象合并。

HandlerAdapter源码实现

HandlerAdapter的源码实现位于org.springframework.web.servlet包中。以下是RequestMappingHandlerAdapter的源码实现:

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter<RequestMappingInfo> {
    @Override
    protected boolean supportsInternal(HandlerMethod handlerMethod) {
        return true;
    }

    @Override
    protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        modelFactory.initModel(webRequest, mavContainer, handlerMethod);

        Object result = handlerMethod.invokeForRequest(webRequest, mavContainer);
        if (result == null) {
            if (isRequestNotModified(request, handlerMethod.getMethod())) {
                return null;
            }
            handleResponseBody(null, mavContainer, webRequest);
        }
        else if (StringUtils.hasText(mavContainer.getViewName())) {
            handleResponseBody(result, mavContainer, webRequest);
        }
        else {
            mavContainer.setRequestHandled(true);
        }

        return getModelAndView(mavContainer);
    }
}

在本示例中,我们继承了AbstractHandlerMethodAdapter类,并实现了supportsInternal()方法和handleInternal()方法。在supportsInternal()方法中,我们返回true表示支持所有的HandlerMethod对象。在handleInternal()方法中,我们首先创建了ServletWebRequest对象和ModelAndViewContainer对象,并调用initModel()方法初始化ModelAndViewContainer对象。然后,我们调用invokeForRequest()方法执行HandlerMethod对象,并获取处理结果。如果处理结果为null,则调用handleResponseBody()方法处理响应体。如果处理结果不为null且ModelAndViewContainer对象中包含视图名称,则调用handleResponseBody()方法处理响应体。否则,我们将ModelAndViewContainer对象的requestHandled属性设置为true。最后,我们调用getModelAndView()方法获取ModelAndView对象并返回。

示例1

以下是一个使用SpringMVC的示例:

@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public ModelAndView list() {
        List<User> userList = userService.getUserList();
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("userList", userList);
        modelAndView.setViewName("userList");
        return modelAndView;
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ModelAndView detail(@PathVariable("id") Long userId) {
        User user = userService.getUserById(userId);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("user", user);
        modelAndView.setViewName("userDetail");
        return modelAndView;
    }
}

在本示例中,我们使用@Controller注解标识UserController类为控制器,并使用@RequestMapping注解指定了请求路径、请求方法、请求参数等信息。在list()方法中,我们调用了UserService的getUserList()方法获取用户列表,并将用户列表添加到ModelAndView对象中。在detail()方法中,我们调用了UserService的getUserById()方法获取指定ID的用户,并将用户信息添加到ModelAndView对象中。

示例2

以下是一个使用Thymeleaf模板引擎的示例:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>User Detail</title>
</head>
<body>
    <h1>User Detail</h1>
    <table>
        <tr>
            <td>ID:</td>
            <td th:text="${user.id}"></td>
        </tr>
        <tr>
            <td>Name:</td>
            <td th:text="${user.name}"></td>
        </tr>
        <tr>
            <td>Age:</td>
            <td th:text="${user.age}"></td>
        </tr>
    </table>
</body>
</html>

在本示例中,我们使用Thymeleaf模板引擎来渲染视图。我们使用th:text指令来显示用户的ID、姓名和年龄。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解SpringMVC从基础到源码 - Python技术站

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

相关文章

  • 解析Java的Spring框架的基本结构

    下面是详细讲解“解析Java的Spring框架的基本结构”的攻略: 1. Spring框架的基本结构 Spring框架是一个基于Java的轻量级开源框架,开发者可以使用它开发企业级应用程序。 Spring框架基于IoC(控制反转)和AOP(面向切面编程)设计,提供了使用Java编写应用程序的框架,并减少了业务代码和底层代码之间的耦合。 Spring框架由以下…

    Java 2023年5月19日
    00
  • SpringBoot中定时任务@Scheduled的多线程使用详解

    下面是关于“SpringBoot中定时任务@Scheduled的多线程使用详解”的攻略,分为以下三个部分: 1. 什么是@Scheduled注解 SpringBoot中的@Scheduled注解是用来标记方法执行定时任务的注解。使用该注解能够非常方便地实现某些任务的周期性执行。@Scheduled注解可以设置的属性如下: fixedRate:指定任务开始后每…

    Java 2023年5月19日
    00
  • Java指令重排序在多线程环境下的处理方法

    Java指令重排序在多线程环境下的处理方法是非常重要的,因为指令重排序可能导致程序出现难以预测的结果,尤其是在多线程环境下。下面,我将详细讲解Java指令重排序在多线程环境下的处理方法,包括原理、处理方法和示例。 原理 Java指令重排序是指JVM在执行指令时,为了优化程序执行效率,可能会调整指令的执行顺序。这种优化不会影响单线程程序的执行,但是在多线程环境…

    Java 2023年5月26日
    00
  • 浅谈springBoot注解大全

    浅谈Spring Boot注解大全 在Spring Boot应用程序开发中,注解成为了一种非常重要的方式来实现各种功能。本文将详细介绍Spring Boot注解的大全,希望对于初学者以及有一定经验的开发人员有所帮助。 Spring Boot自动配置注解 Spring Boot的自动配置是通过注解实现的,以下是一些常用的自动配置注解: @SpringBootA…

    Java 2023年5月15日
    00
  • java springmvc 注册中央调度器代码解析

    下面我将详细讲解如何完成“java springmvc 注册中央调度器代码解析”的攻略。 一、什么是中央调度器 中央调度器又称为中央控制器,是一种设计模式,它的功能是对系统中的各种请求进行分类,以便对它们进行操作或执行来自不同部分的中央逻辑。在Java Spring MVC框架中,中央调度器类似于Servlet,拦截所有的HTTP请求并决定将其发送到哪个控制…

    Java 2023年6月15日
    00
  • 在vue中完美使用ueditor组件(cdn)解读

    在Vue中完美使用Ueditor组件(CDN)解读 UEditor是一款开源的富文本编辑器,我们可以在Vue项目中通过CDN引入UEditor组件来使用它。 步骤一:引入UEditor组件 我们可以在Vue组件的template部分直接嵌入UEditor组件,需要用到Ueditor的CDN地址。 <template> <div> &l…

    Java 2023年6月15日
    00
  • 一文详解Tomcat下载安装以及配置

    一文详解Tomcat下载安装以及配置 Apache Tomcat(简称Tomcat)是一个流行的开源Web服务器和Java Servlet容器,可运行于各种操作系统上。本文将提供完整的Tomcat下载、安装和配置教程。 步骤一:下载Tomcat 首先,访问官方网站,进入Tomcat下载页面。选择最新版本的Tomcat,然后在下载页面中选择“Core”板块中的…

    Java 2023年6月2日
    00
  • Java单例模式的深入了解

    Java单例模式的深入了解 单例模式是一种常用的设计模式,它确保一个类只有一个实例,同时提供一种全局访问的方式。 在Java中,单例模式有多种实现方式,我们既可以使用经典的饿汉式实现,也可以使用懒汉式、静态内部类等方式实现。本篇攻略将为大家深入讲解Java单例模式的各种实现方式及其优缺点,同时提供一些示例说明。 一、饿汉式单例模式 饿汉式单例模式是最简单的一…

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