Spring Web MVC 是建立在 Servlet API 上的原始 Web 框架,从一开始就包含在 Spring 框架中。它的正式名称 「Spring Web MVC」来自其源模块的名称(spring-webmvc),但它更多地被称为 「Spring MVC」。

与 Spring Web MVC 并行,Spring Framework 5.0 引入了一个反应堆 Web 框架,其名称为 「Spring WebFlux」,也是基于其源模块(spring-webflux)。本节介绍了 Spring Web MVC。下一节将介绍 Spring WebFlux。

关于基线信息以及与 Servlet 容器和 Java EE 版本范围的兼容性,请参见 Spring Framework Wiki


快速搭建一个 mvc 项目

用太久的 SpringBoot 之后,原始的 servlet 项目不知道如何部署了,这里记录下步骤,方便后面文档知识的理解和测试

这里分为两种启动方式:

  1. 外部 Tomcat 启动:传统的 war 包部署,这种感觉好像无法 debug 了,不知道怎么弄的
  2. 内嵌 Tomcat 启动:类似简单版的 spring boot 启动,这里建议使用这种方式启动,后续还要学习 boot 的,

外部 tomcat 启动方式

项目创建

下图是项目结构
image.png
我是用 Gradle(版本 7.1.1) 部署的。build.gradle

  1. plugins {
  2. id 'war'
  3. id 'java'
  4. }
  5. group 'cn.mrcode'
  6. version '1.0-SNAPSHOT'
  7. repositories {
  8. mavenCentral()
  9. }
  10. dependencies {
  11. implementation group: 'org.springframework', name: 'spring-webmvc', version: '5.3.15'
  12. }
  13. test {
  14. useJUnitPlatform()
  15. }

web.xml

  1. <web-app>
  2. <listener>
  3. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  4. </listener>
  5. <context-param>
  6. <param-name>contextConfigLocation</param-name>
  7. <param-value>classpath:app-context.xml</param-value>
  8. </context-param>
  9. <servlet>
  10. <servlet-name>app</servlet-name>
  11. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  12. <init-param>
  13. <param-name>contextConfigLocation</param-name>
  14. <param-value></param-value>
  15. </init-param>
  16. <load-on-startup>1</load-on-startup>
  17. </servlet>
  18. <servlet-mapping>
  19. <servlet-name>app</servlet-name>
  20. <url-pattern>/</url-pattern>
  21. </servlet-mapping>
  22. </web-app>

app-context.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:mvc="http://www.springframework.org/schema/mvc"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
  8. <!-- ioc 核心包扫描:为了能用上注解配置,这里直接扫描根路径 -->
  9. <context:component-scan base-package="cn.mrcode.spring"></context:component-scan>
  10. <!-- 这是启用 mvc 相关的注解支持 -->
  11. <mvc:annotation-driven/>
  12. </beans>

DemoController

  1. package cn.mrcode.spring;
  2. import org.springframework.web.bind.annotation.GetMapping;
  3. import org.springframework.web.bind.annotation.RestController;
  4. /**
  5. * @author mrcode
  6. * @date 2022/3/28 20:06
  7. */
  8. @RestController
  9. public class DemoController {
  10. public DemoController() {
  11. System.out.println("sss");
  12. }
  13. @GetMapping("/aabb")
  14. public String test() {
  15. return "success";
  16. }
  17. }

项目启动

这里用 Tomcat8 来部署的,需要注意一些事项

检查以下地方是否有报错,选中项目目录,然后按 F4 打开这个配置弹框
image.png
工件是否正常生成
image.png
然后编辑配置,添加一个 tomcat
image.pngimage.png
服务器配置界面
image.png
在部署界面,添加工件
image.png
image.png
启动后访问:http://localhost:8081/aabb 返回 success ,环境部署成功。

内嵌 Tomcat

内嵌 Tomcat 方式是 100% 使用注解方式,无 xml 配置,实现 SpringMVC 的使用,也不依赖于外部的 Tomcat 容器
image.png
build.gradle

  1. plugins {
  2. id 'java'
  3. }
  4. group 'cn.mrcode'
  5. version '1.0-SNAPSHOT'
  6. repositories {
  7. mavenCentral()
  8. }
  9. dependencies {
  10. implementation group: 'org.springframework', name: 'spring-webmvc', version: '5.3.15'
  11. implementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.5.77'
  12. }
  13. test {
  14. useJUnitPlatform()
  15. }

内嵌 tomcat 启动类

  1. package cn.mrcode;
  2. import org.apache.catalina.startup.Tomcat;
  3. import java.io.File;
  4. /**
  5. * @author mrcode
  6. * @date 2022/3/28 20:50
  7. */
  8. public class TomcatServer {
  9. public static void main(String[] args) {
  10. Tomcat tomcat = new Tomcat();
  11. try {
  12. String docBase = "src/main/webapp/";
  13. String contextPath = "/";
  14. /*
  15. * tomcat 加入 web 工程
  16. *
  17. * host: 缺省默认为 localhost
  18. * contextPath: 在浏览器中访问项目的根路径
  19. * 例:localhost:port/{contextPath}/xx
  20. * docBase:项目中 webapp 所在路径
  21. */
  22. // tomcat.addWebapp(host, contextPath, docBase)
  23. tomcat.addWebapp(contextPath, new File(docBase).getAbsolutePath());
  24. tomcat.setBaseDir(".");
  25. tomcat.setPort(8081);
  26. tomcat.start();
  27. System.out.println("tomcat服务启动成功。。");
  28. tomcat.getServer().await();
  29. } catch (Exception e) {
  30. System.out.println("tomcat服务启动失败。。");
  31. e.printStackTrace();
  32. }
  33. }
  34. }

:::tips 这里并没有代码指向后面的 WebApplicationInitializer 类,原理是 WebApplicationInitializer 使用了 JDK 的 servlet SPI 策略规范,所以会被扫描到,这个可以在 WebApplicationInitializer 类注释上看到说明 ::: 注解风格的 AppConfig

  1. package cn.mrcode;
  2. import org.springframework.context.annotation.ComponentScan;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.web.servlet.config.annotation.EnableWebMvc;
  5. /**
  6. * @author mrcode
  7. * @date 2022/3/28 20:53
  8. */
  9. @Configuration
  10. @EnableWebMvc
  11. @ComponentScan("cn.mrcode.spring")
  12. public class AppConfig {
  13. }

编程式的 DispatcherServlet 初始化

  1. package cn.mrcode.spring;
  2. import cn.mrcode.AppConfig;
  3. import org.springframework.web.WebApplicationInitializer;
  4. import org.springframework.web.context.ContextLoaderListener;
  5. import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
  6. import org.springframework.web.servlet.DispatcherServlet;
  7. import javax.servlet.ServletContext;
  8. import javax.servlet.ServletRegistration;
  9. /**
  10. * @author mrcode
  11. * @date 2022/3/28 20:53
  12. */
  13. public class MyWebApplicationInitializer implements WebApplicationInitializer {
  14. @Override
  15. public void onStartup(ServletContext servletContext) {
  16. // 加载 Spring web application configuration
  17. AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
  18. context.register(AppConfig.class);
  19. // Manage the lifecycle of the root application context
  20. servletContext.addListener(new ContextLoaderListener(context));
  21. // 创建和注册 DispatcherServlet
  22. DispatcherServlet servlet = new DispatcherServlet(context);
  23. ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
  24. registration.setLoadOnStartup(1);
  25. registration.addMapping("/");
  26. }
  27. }

一个测试 controller

  1. package cn.mrcode.spring;
  2. import org.springframework.web.bind.annotation.GetMapping;
  3. import org.springframework.web.bind.annotation.RestController;
  4. /**
  5. * @author mrcode
  6. * @date 2022/3/28 20:06
  7. */
  8. @RestController
  9. public class DemoController {
  10. public DemoController() {
  11. System.out.println("sss");
  12. }
  13. @GetMapping("/aabb")
  14. public String test() {
  15. return "success";
  16. }
  17. }

image.png
可以看到启动后,spring 相关的也初始化了

启动后访问 http://localhost:8081/aabb 响应 success