Spring Boot 入门之基础构建篇(一)

博客地址:http://www.moonxy.com

一、前言

随着 Spring 的功能越来越强,在使用 Spring 的时候,门槛也变得高了起来,诸如搭建一个基于 Spring 的 Web 程序却并不简单,需要进行各种配置,Spring 通过多年的发展,本身变得很臃肿,过时的使用方式,如 XML 系统配置方式,没有被淘汰的同时,出现了新的注解配置方式,这给初学者带来了使用上的混乱。同时 Spring 也集成了越来越多的第三方技术,如何方便地使用这些技术,各版本之间是否会产生冲突,也需要一定的实践。庆幸的是,Spring 的开发者们认识到了这个问题,推出了基于 Spring 技术的 Spring Boot,解决了上面的许多问题,尤其是上手难,技术使用不统一这两个缺点。Sping Boot 简化了 Spring 应用开发,不需要配置就能运行 Spring 应用,Spring Boot 管理Spring 容器,第三方插件,并提供很多系统级别的服务。

二、环境搭建

由于 Spring Boot 需要 JDK8、Maven3 的支持,所有需要配置对应版本的环境:

2.1 下载 JDK

在系统环境变量中设置好 JAVA_HOME,PATH,CLASSPATH。JDK 所有版本下载地址为:http://www.oracle.com/technetwork/java/javase/archive-139210.html

比如下载Windos 64 位 JDK1.8.0_144,地址为:http://download.oracle.com/otn/java/jdk/8u144-b01/090f390dda5b47b9b721c7dfaa008135/jdk-8u144-windows-x64.exe,可以下载 Windos,Linux,Mac 等版本的 JDK。

2.2 下载 Maven

在系统环境变量中设置 M2_HOME。Maven3 所有版本的下载地址为:https://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/

比如下载 apache-maven-3.3.9,地址为:https://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip

2.3 下载 CURL 工具

curl 是利用 URL 语法在命令行方式下工作的开源文件传输工具。它被广泛应用在 UNIX、多种 Linux 发行版中,并且有 DOS 和 Win32、Win 64 下的移植版本,Mac 和 Linux 中,会自带 curl,但是 Windos 系统,需要自己下载安装,如果已经安装了 git shell,也会自带了 curl。curl 自行下载地址为:https://curl.haxx.se/download.html

比如拖动到最下面,下载 Win64 x86_64 CAB,并在系统环境变量中设置 CURL_HOME,在 PATH 末尾添加";%CURL_HOME%I386",地址为:https://skanthak.homepage.t-online.de/download/curl-7.57.0.cab

三、创建应用

3.1 以 Eclipse 为例,File - New - Maven Project,勾选 Create a simple project(skip archetype selection),

进入到填写坐标的对话框中,组织 Group Id 填写:springboot.example,项目标识 Artifact Id 填写:spring-boot-hello,版本号 Version 和打包方式 Packaging 可以保持默认,如下所示:

再创建相应的包,目录结构如下:

3.2 添加依赖

在工程的 pom.xml 中添加 maven 依赖,其中 spring-boot-starter-web 属于搭建 Web 应用时必须添加的依赖,默认会使用内置 Tomcat,并支持 Spring MVC、RESTFul服务等,如下

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>springboot.example</groupId>
    <artifactId>spring-boot-hello</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.6.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    
    <dependencies>
        <!-- 上边已经引入 parent,因此下边无需指定版本 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3.3 创建启动类

在 com.light.springboot 包下,创建 SpringbootApplication.java,如下:

package com.light.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 该注解指定项目为springboot,由此类当作程序入口,自动装配web依赖的环境
 * @author Administrator
 *
 */
@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

}

3.4 创建演示案例

在 com.light.springboot.controller 包下,创建 HelloWorldController.java,基于 RestFul 架构风格的请求,如下:

package com.light.springboot.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value="/helloWorldController")
public class HelloWorldController {
    
    @GetMapping("/helloworld1/{name}")
    public String helloworld1(@PathVariable(required = false) String name) {
        return "hello" + name + "World1";
    }
}

四、启动应用

 打开 SpringbootApplication.java,右键 Run as - Java Application,控制台显示如下日志:

21:25:44.465 [main] DEBUG org.springframework.boot.devtools.settings.DevToolsSettings - Included patterns for restart : []
21:25:44.467 [main] DEBUG org.springframework.boot.devtools.settings.DevToolsSettings - Excluded patterns for restart : [/spring-boot-starter/target/classes/, /spring-boot-autoconfigure/target/classes/, /spring-boot-starter-[w-]+/, /spring-boot/target/classes/, /spring-boot-actuator/target/classes/, /spring-boot-devtools/target/classes/]
21:25:44.467 [main] DEBUG org.springframework.boot.devtools.restart.ChangeableUrls - Matching URLs for reloading : [file:/F:/workspace/spring-boot-hello/target/classes/]

  .   ____          _            __ _ _
 /\ / ___'_ __ _ _(_)_ __  __ _    
( ( )\___ | '_ | '_| | '_ / _` |    
 \/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.6.RELEASE)

2018-01-21 21:25:44.708  INFO 7496 --- [  restartedMain] c.l.springboot.SpringbootApplication     : Starting SpringbootApplication on PC201601051134 with PID 7496 (F:workspacespring-boot-hello	argetclasses started by Administrator in F:workspacespring-boot-hello)
2018-01-21 21:25:44.709  INFO 7496 --- [  restartedMain] c.l.springboot.SpringbootApplication     : No active profile set, falling back to default profiles: default
2018-01-21 21:25:44.760  INFO 7496 --- [  restartedMain] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@3e2d4e88: startup date [Sun Jan 21 21:25:44 CST 2018]; root of context hierarchy
2018-01-21 21:25:46.681  INFO 7496 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2018-01-21 21:25:46.694  INFO 7496 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-01-21 21:25:46.695  INFO 7496 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.16
2018-01-21 21:25:46.780  INFO 7496 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-01-21 21:25:46.780  INFO 7496 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2023 ms
......
2018-01-21 21:25:47.304  INFO 7496 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@3e2d4e88: startup date [Sun Jan 21 21:25:44 CST 2018]; root of context hierarchy
2018-01-21 21:25:47.373  INFO 7496 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/helloWorldController/helloworld1/{name}],methods=[GET]}" onto public java.lang.String com.light.springboot.controller.HelloWorldController.helloworld1(java.lang.String)
......
2018-01-21 21:25:48.286  INFO 7496 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8081 (http)
2018-01-21 21:25:48.287  INFO 7496 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-01-21 21:25:48.287  INFO 7496 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.16
2018-01-21 21:25:48.299  INFO 7496 --- [ost-startStop-1] o.a.c.c.C.[Tomcat-1].[localhost].[/]     : Initializing Spring embedded WebApplicationContext
2018-01-21 21:25:48.300  INFO 7496 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 172 ms
2018-01-21 21:25:48.310  INFO 7496 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2018-01-21 21:25:48.310  INFO 7496 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'springSecurityFilterChain' to: [/*]
2018-01-21 21:25:48.395  INFO 7496 --- [  restartedMain] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/manage/mappings || /manage/mappings.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-01-21 21:25:48.396  INFO 7496 --- [  restartedMain] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/manage/trace || /manage/trace.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-01-21 21:25:48.399  INFO 7496 --- [  restartedMain] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/manage/shutdown || /manage/shutdown.json],methods=[POST],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint.invoke()
......
2018-01-21 21:25:48.533  INFO 7496 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8081 (http)
2018-01-21 21:25:48.537  INFO 7496 --- [  restartedMain] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0
2018-01-21 21:25:48.606  INFO 7496 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2018-01-21 21:25:48.610  INFO 7496 --- [  restartedMain] c.l.springboot.SpringbootApplication     : Started SpringbootApplication in 4.13 seconds (JVM running for 4.463)

日志中会显示已经扫描到的 Mapping,tomcat 启动时间等信息。启动成功之后输入:http://localhost:8080/helloWorldController/helloworld1/Java,如下图所示:

4.1 添加热部署

当我们修改或者添加类以及配置文件时,必须再次运行应用,对于开发者来说非常不方便。Spring Boot 提供了 spring-boot-devtools,它能在修改类或者配置文件的时候自动重新加载 Spring Boot 应用,需要在 pom 文件中添加如下依赖:

<!-- 热部署 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>

配置好 pom.xml 文件,待依赖的包下载完毕之后,我们启动项目,随便创建/修改一个文件并保存,会发现控制台打印 springboot 重新加载文件的信息。如向 HelloWorldController.java 中添加方法:

@RequestMapping(value="/helloworld2/{name}")
public String helloworld2(@PathVariable(value = "name",required = false) String name) {
    return "hello" + name + "World2";
}

同时,Spring Boot 会重新加载,如下:

......
2018-01-21 21:39:23.664 INFO 7496 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/helloWorldController/helloworld2/{name}]}" onto public java.lang.String com.light.springboot.controller.HelloWorldController.helloworld2(java.lang.String)
......

五、关闭应用

5.1 打包应用

Spring Boot 应用可以打成 jar 包,其中内置了 tomcat,因此可以直接启动使用。上面的演示中是使用启动类启动了应用,此处将应用打成 jar 包,通过 CMD 进入到工程的根目录下执行命令:mvn clean package -Dmaven.test.skip=true,或在 Eclipse 中自定义 maven 命令,运行 run -> Maven build...,在 Goals 中填写 clean package -Dmaven.test.skip=true,运行,日志中出现 BUILD SUCCESS 则打包完成。注意:maven 跳过测试打包可以使用 mvn clean package -DskipTests 或者 mvn clean package -Dmaven.test.skip=true,但是这两个命令并不完全相同。

在使用 mvn clean package 进行编译、打包时,Maven会执行 src/test/java 中的 JUnit 测试用例,有时为了跳过测试,会使用参数 -DskipTests 和 -Dmaven.test.skip=true,这两个参数的主要区别是:
-DskipTests,不执行测试用例,但编译测试用例类生成相应的 class 文件至 target/test-classes 下;
-Dmaven.test.skip=true,不执行测试用例,也不编译测试用例类。

5.2 运行应用

进入到生成 jar 包的目录下 targetspring-boot-hello-0.0.1-SNAPSHOT.jar,执行:java -jar spring-boot-hello-0.0.1-SNAPSHOT.jar 命令,运行应用,显示的日志与 3.4 中的一样,最后启动成功,便可以通过浏览器访问应用。

5.3 关闭应用

由于 Spring Boot 内置了 tomcat,所以我们不能直接关闭关闭,需要添加 spring-boot-starter-actuator 依赖,建议在开发环境中禁用密码验证,在正式环境中开启密码验证,如下

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

在 resources 目录下新建 application.properties 文件,并添加:

# 启用shutdown
endpoints.shutdown.enabled=true

# 禁用密码验证
endpoints.shutdown.sensitive=false

在 CMD 中执行关闭命令:curl -X POST http://localhost:8080/shutdown,则显示:{"message":"Shutting down, bye..."},如下:

如果要配置路径,需要在 application.properties 中添加 management.context-path=/manage,则关闭命令变为:curl -X POST host:port/manage/shutdown

5.4 安全验证

通过 5.3 中的命令可以直接关闭应用,但是每个人都可以关闭,很不安全,我们通过设置用户名和密码来管理关闭的权限验证,但是要添加 spring-boot-starter-security 依赖,如下:

<!-- 安全验证 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

且 application.properties 需要被修改为:

# 启用shutdown
endpoints.shutdown.enabled=true

# 开启密码验证
endpoints.shutdown.sensitive=true

# 验证用户名
security.user.name=admin

# 验证密码
security.user.password=secret

# 角色
management.security.role=SUPERUSER

# 也可以统一指定所有endpoints的路径'management.context-path=/manage'
management.context-path=/manage

# 指定端口
management.port=8081

# 指定地址
management.address=127.0.0.1

使用安全验证之后,则命令变为:curl -u admin:secret -X POST http://127.0.0.1:8081/manage/shutdown

六、多环境切换

在日常的软件开发中,我们一般都是使用自己的机器开发,测试的时候需要用到测试服务器,上线时使用正式环境的服务器。这三种环境需要的配置信息往往都不一样,比如数据源地址等。当我们切换环境运行项目时,一般都需要手动的修改配置文件,非常不方便且容易出错。为了解决上述问题,Spring Boot 提供多环境配置的机制,让开发者很容易的根据需求而切换不同的配置环境。

在 Spring Boot 中,将所需要的配置信息放在 application.properties 中,在 src/main/resources 目录下创建三个配置文件,分别对应开发、测试和生产三个环境:

application-dev.properties:用于开发环境
application-test.properties:用于测试环境
application-prod.properties:用于生产环境

我们可以在这个三个配置文件中设置不同的信息,比如访问应用的端口号,并在 application.properties 配置激活信息。

spring.profiles.active=dev

表示激活 application-dev.properties 文件配置, Spring Boot 会加载使用 application.properties 和 application-dev.properties 配置文件的信息。同理可将 spring.profiles.active 的值修改成 test 或 prod 达到切换到测试环境或生产环境的目的。

七、配置日志

Spring Boot 官方推荐使用 logback,其次也可以使用 log4j2 来配置日志。

7.1 配置 logback

Spring Boot 默认会加载 classpath:logback-spring.xml 或者 classpath:logback-spring.groovy。如需要自定义文件名称,在 application.properties 中配置 logging.config 选项即可。在 src/main/resources 下创建 logback-spring.xml 文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 文件输出格式 -->
    <property name="PATTERN" value="%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) |-%-5level [%thread] %c [%L] -| %msg%n" />
    <!-- test文件路径 -->
    <property name="TEST_FILE_PATH" value="F:/springlog/test.log" />
    <!-- pro文件路径 -->
    <property name="PRO_FILE_PATH" value="/opt/test/log" />
    
    <!-- 开发环境 -->
    <springProfile name="dev">
        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>${PATTERN}</pattern>
            </encoder>
        </appender>
        <logger name="com.light.springboot" level="debug" />
        <root level="info">
            <appender-ref ref="CONSOLE" />
        </root>
    </springProfile>
    
    <!-- 测试环境 -->
    <springProfile name="test">
        <!-- 每天产生一个文件 -->
        <appender name="TEST-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 文件路径 -->
            <file>${TEST_FILE_PATH}</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 文件名称 -->
                <fileNamePattern>${TEST_FILE_PATH}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
                <!-- 文件最大保存历史数量 -->
                <MaxHistory>100</MaxHistory>
            </rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>${PATTERN}</pattern>
            </layout>
        </appender>
        <root level="info">
            <appender-ref ref="TEST-FILE" />
        </root>
    </springProfile>
    
    <!-- 生产环境 -->
    <springProfile name="prod">
        <appender name="PROD_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${PRO_FILE_PATH}</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${PRO_FILE_PATH}/warn.%d{yyyy-MM-dd}.log</fileNamePattern>
                <MaxHistory>100</MaxHistory>
            </rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>${PATTERN}</pattern>
            </layout>
        </appender>
        <root level="warn">
            <appender-ref ref="PROD_FILE" />
        </root>
    </springProfile>
</configuration>

其中,springProfile 标签的 name 属性对应 application.properties 中的 spring.profiles.active 的配置。即 spring.profiles.active 的值可以看作是日志配置文件中对应的 springProfile 是否生效的开关。

7.2 配置 log4j2

要使用 log4j2,需要添加 spring-boot-starter-log4j2 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

spring boot 默认会加载 classpath:log4j2.xml 或者 classpath:log4j2-spring.xml。如需要自定义文件名称,在 application.properties 中配置 logging.config 选项即可。log4j2.xml 文件内容如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <properties>
        <!-- 文件输出格式 -->
        <property name="PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} |-%-5level [%thread] %c [%L] -| %msg%n</property>
    </properties>
    <appenders>
        <Console name="CONSOLE" target="system_out">
            <PatternLayout pattern="${PATTERN}" />
        </Console>
    </appenders>
    <loggers>
        <logger name="com.light.springboot" level="debug" />
        <root level="info">
            <appenderref ref="CONSOLE" />
        </root>
    </loggers>
</configuration>

log4j2 不能像 logback 那样在一个文件中设置多个环境的配置数据,只能命名 3 个不同名的日志文件,分别在 application-dev,application-test 和 application-prod 中配置 logging.config 选项。

除了在日志配置文件中设置参数之外,还可以在 application-*.properties 中设置,日志相关的配置:

logging.config                    # 日志配置文件路径,如 classpath:logback-spring.xml
logging.exception-conversion-word # 记录异常时使用的转换词
logging.file                      # 记录日志的文件名称,如:test.log
logging.level.*                   # 日志映射,如:logging.level.root=WARN,logging.level.org.springframework.web=DEBUG
logging.path                      # 记录日志的文件路径,如:d:/
logging.pattern.console           # 向控制台输出的日志格式,只支持默认的 logback 设置。
logging.pattern.file              # 向记录日志文件输出的日志格式,只支持默认的 logback 设置。
logging.pattern.level             # 用于呈现日志级别的格式,只支持默认的 logback 设置。
logging.register-shutdown-hook    # 初始化时为日志系统注册一个关闭钩子

八、应用打包

常用应用打包的形式有两种:jar 和 war。

8.1 打包成可执行的 jar 包

默认情况下,通过 maven 执行 package 命令后,会生成 jar 包,且该 jar 包会内置了 tomcat 容器,因此我们可以通过 java -jar 就可以运行项目。

8.2 打包成部署的 war 包

Spring Boot 生成的 war 包,需要启动类继承自SpringBootServletInitializer方可正常部署至常规tomcat下,其主要能够起到 web.xml 的作用。让 SpringbootApplication 类继承 SpringBootServletInitializer 并重写 configure 方法,如下:

package com.light.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

/**
 * 该注解指定项目为springboot,由此类当作程序入口,自动装配web依赖的环境
 * @author Administrator
 *
 */
@SpringBootApplication
public class SpringbootApplication extends SpringBootServletInitializer {
    
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringbootApplication.class);
    }
    
    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

}

修改 pom.xml 文件,将 jar 改成 war,如下:

<packaging>war</packaging>

打包成功后,将 war 包部署到 tomcat 容器中运行即可。

原文地址:https://www.cnblogs.com/cnjavahome/p/8324321.html