SpringMVC快速入门详解

  • 简介
  • 快速入门
  • 1. 快速实现
  • 1.1 导入SpringMVC坐标与Servlet坐标
  • 1.2 创建SpringMVC控制器类(等同于Servlet功能)
  • 1.3 初始化SpringMVC环境(同Spring环境),设定SpringMVC加载对应的bean
  • 1.4 初始化SpringMVC容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求
  • 2. 注解分析
  • 2.1 @Controller
  • 2.2 @RequestMapping
  • 2.3 @ResponseBody
  • 3. 1+N 特点
  • 3.1 一次性工作
  • 3.2 多次工作
  • 4. Servlet容器启动的配置类解析
  • 4.1 createServletApplicationContext()方法
  • 4.2 getServletMappings()方法
  • 4.3 createRootApplicationContext()方法
  • 5. 工作流程分析
  • 5.1 启动服务器初始化过程
  • 5.2 单次请求过程
  • 6. Spring和SpringMVC相关bean加载控制
  • 7. Servlet容器启动的配置类简化
  • 总结


简介

SpringMVC是一种基于Java实现MVC模型的轻量级Web框架。
具有如下优点:

  1. 使用简单,开发便捷(相比于Servlet)。
  2. 灵活性强。

SpringMVC是一种标签层框架技术。
SpringMVC是用于进行表现层功能开发。

快速入门

1. 快速实现

1.1 导入SpringMVC坐标与Servlet坐标

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.2.20.RELEASE</version>
</dependency>

需要注意的是spring-webmvc版本5.2.20.RELEASE对应的jdk不能太高,1.8版本的jdk即可,我试了16是不匹配的,会出问题。

1.2 创建SpringMVC控制器类(等同于Servlet功能)

@Controller
public class UserController {
    @RequestMapping("/save")
    @ResponseBody
    public String save() {
        System.out.println("springmvc save ...");
        return "{'module':'springmvc save'}";
    }
}

1.3 初始化SpringMVC环境(同Spring环境),设定SpringMVC加载对应的bean

@Configuration
@ComponentScan({"com.hao.controller"})
public class SpringMVCConfig {
}

1.4 初始化SpringMVC容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    // 加载springmvc容器配置
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringMVCConfig.class);
        return ctx;
    }
    // 设置哪些请求归属springmvc处理
    @Override
    protected String[] getServletMappings() {
        // 所有请求
        return new String[]{"/"};
    }
    // 加载spring容器配置
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
}

2. 注解分析

2.1 @Controller

类型:类注解。
位置:SpringMVC控制器类定义上方。
作用:设定SpringMVC的核心控制器bean
例如:

@Controller
public class UserController {
}

2.2 @RequestMapping

类型:方法注解。
位置:SpringMVC控制器方法定义上方。
作用:设置当前控制器方法请求访问路径。
例如:

@RequestMapping("/save")
public void save() {
    System.out.println("springmvc save ...");
}

相关属性:
value(默认):请求访问路径。

2.3 @ResponseBody

类型:方法注解。
位置:SpringMVC控制器方法定义上方。
作用:设置当前控制器方法响应内容为当前返回值,无需解析。
例如:

@RequestMapping("/save")
@ResponseBody
public String save() {
    System.out.println("springmvc save ...");
    return "{'module':'springmvc save'}";
}

3. 1+N 特点

3.1 一次性工作

  1. 创建工程,设置服务器,加载工程。
  2. 导入坐标。
  3. 创建web容器启动类,加载SpringMVC配置,并设置SpringMVC请求拦截路径。
  4. SpringMVC核心配置类(设置配置类,扫描controller包,加载Controller控制器bean)。

3.2 多次工作

  1. 定义处理请求的控制器类。
  2. 定义处理请求的控制器方法,并配置映射路径(@RequestMapping)与返回json数据(@ResponseBody)。

4. Servlet容器启动的配置类解析

AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类。
AbstractDispatcherServletInitializer提供了三个接口方法供用户实现。

4.1 createServletApplicationContext()方法

该方法是创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围。

protected WebApplicationContext createServletApplicationContext() {
    AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
    ctx.register(SpringMVCConfig.class);
    return ctx;
}

4.2 getServletMappings()方法

该方法是设定SpringMVC对应的请求映射路径,设置为/表示拦截所有请求,任意请求都将转入到SpringMVC进行处理。

protected String[] getServletMappings() {
    return new String[]{"/"};
}

4.3 createRootApplicationContext()方法

该方法是创建Servlet容器时需要加载Spring对应的bean,使用当前方法进行,使用方式同createServletApplicationContext()

protected WebApplicationContext createRootApplicationContext() {
	return null;
}

5. 工作流程分析

5.1 启动服务器初始化过程

  1. 服务器启动,执行ServletContainerInitConfig类(自己创建继承AbstractDispatcherServletInitializer),初始化web容器。
  2. 执行createServletApplicationContext()方法,创建了WebApplicationContext对象。
  3. 加载SpringMVCConfig
  4. 执行@ComponentScan加载对应的bean
  5. 加载UserController,每个@RequestMapping的名称对应一个具体的方法。
  6. 执行getServletMappings()方法,定义所有的请求都通过SpringMVC

5.2 单次请求过程

  1. 发送请求localhost/save
  2. web容器发现所有请求都经过SpringMVC,将请求交给SpringMVC处理。
  3. 解析请求路径/save
  4. /save匹配执行对象的方法save()
  5. 执行save()
  6. 检测到有@ResponseBody直接将save()方法的返回值作为响应体返回给请求方。

6. Spring和SpringMVC相关bean加载控制

SpringMVC相关bean主要是表现层bean
Spring控制的bean主要是业务bean(Service)和功能bean(DataSource等)

为了开发中减少相互之间的影响,所以在相应的配置文件扫描路径中,尽量区分开来。

SpringMVC加载的bean对应的包均在controller包内,例如com.hao.controller
Spring加载的bean设定扫描范围为精准范围例如com.hao.service包和com.hao.dao包,还可以设置大范围com.hao,然后排除掉controller包内的bean,如下:

@Configuration
@ComponentScan(value = "com.hao",
        excludeFilters = @ComponentScan.Filter(
                type = FilterType.ANNOTATION,
                classes = Controller.class
        )
)
public class SpringConfig {
}

这里使用到了注解@ComponentScan的属性excludeFilters来实现加载bean的过滤,同时还有与之对应的属性includeFilters指定bean的包含,这两者的含义如下:
excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)与具体项(classes)。
includeFilters:加载指定的bean,需要指定类别(type)与具体项(classes)。

7. Servlet容器启动的配置类简化

上边创建的Servlet容器启动的配置类ServletContainersInitConfig是继承自AbstractDispatcherServletInitializer,需要实现三个方法来配置相应的配置,其中关于SpringSpringMVC的配置还需要创建AnnotationConfigWebApplicationContext对象并且注册相关配置类,稍微有些繁琐。SpringMVC框架对此进行了简化,只需要继承自AbstractAnnotationConfigDispatcherServletInitializer同样实现三个对应方法来配置,如下:

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMVCConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

总结

以上就是关于SpringMVC快速入门详解的全部内容。

综上可以很直观的看到SpringMVC相比于Servlet,简化了很多的代码量,使用起来也非常的简单便捷,并且灵活性更强。

如果有什么问题,我们可以一起交流讨论解决。

最后,希望可以帮助到有需要的码友。