还不会SpringBoot项目模块分层?来这手把手教你

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
日志服务 SLS,月写入数据量 50GB 1个月
简介: 本文详细介绍了如何为SpringBoot项目创建模块并进行合理的分层设计。通过逐步演示,从创建项目到构建各功能模块,再到具体代码实现,手把手教你实现整洁的代码分层。主要内容包括:创建依赖层、主启动层、模块层及其子模块(如共通层、控制器层、数据持久层等),并通过实例演示了从前端请求到后台服务调用的实际流程。适合SpringBoot初学者及有一定经验但需优化项目结构的开发者参考。

前言

🍊缘由

经常看到网上很多优秀的开源项目中,代码简洁,模块分层完美。反观自己代码层级混乱,,却不知如何整理分层。此文手把手教你一步一步创建模块,左手右手一个慢动作。结合本人实际开发及个人项目中分层思路的分享,大神请勿喷

⏲️本文阅读时长

约25分钟

🎯主要目标

  1. 熟练掌握SpringBoot项目分层思路,丝滑拆分模块
  2. 熟悉代码层级依赖,规范化管理模块分布
  3. 手把手实战学习,理论实践相结合

👨‍🎓试用人群

  1. 对于Springboot熟悉但是不知道合理分层小白
  2. 有自己分层思路可以互相分享学习

🎁快速链接

公众号:JavaDog程序狗
在公众号,发送【分层】 ,无任何套路即可获得

或访问https://blog.javadog.net/archives/boot-module

🍩水图

下图反面教材,传统单体应用,结构臃肿

下图分层截选自本人的一个小项目,模块清晰,分工明确

我们要实现的小栗子的分层

正文

🥫1.IDEA新建项目

起名第一步,一个好名字,说不定是个好的开始

假如我们的项目是个聊天相关的项目,英文对应chat,所以定义项目名为chat-boot,其他的以此效仿

点击New->project

选择Maven项目,并选择合适JDK版本,点击Next

录入项目名称,并填写GAV坐标,点击Finish

删除无用文件及目录,如src目录和*.iml文件

删除后项目目录

修改pom.xml中依赖,增加spring-boot-starter-parent

 <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.3.1.RELEASE</version>
 </parent>


🌭2.创建子模块-dependencies(依赖层)

右击项目chat-boot,new ->Moudle新建模块chat-boot-dependencies

选择对应Module SDK版本,本人选择jdk1.8

填写子模块名 chat-boot-dependencies,然后检查对应GAV,点击Finish

生成子模块chat-boot-dependencies如下图

删除chat-boot-dependencies下无用文件及目录,如src目录,删除无用目录如下

完善chat-boot-dependencies下pom.xml依赖, 常用依赖放入,作为依赖主体,以下是本狗常用依赖,可酌情选择;记得把packaging改为pom
```xml
<?xml version="1.0" encoding="UTF-8"?>



chat-boot
net.javadog.chat
1.0-SNAPSHOT

4.0.0

<artifactId>chat-dependencies</artifactId>

<packaging>pom</packaging>

<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <mysql-connector-java.version>8.0.17</mysql-connector-java.version>
    <druid.version>1.1.21</druid.version>
    <mybatis-plus.version>3.4.1</mybatis-plus.version>
    <fastjson.version>1.2.75</fastjson.version>
    <hutool.version>5.5.8</hutool.version>
    <lombok.versin>1.18.12</lombok.versin>
    <easypoi.version>4.2.0</easypoi.version>
    <springfox-swagger2.version>2.9.2</springfox-swagger2.version>
    <springfox-swagger-ui.version>2.9.2</springfox-swagger-ui.version>
    <knife4j.version>2.0.4</knife4j.version>
    <weixin.version>4.4.5.B</weixin.version>
    <shiro.version>1.3.2</shiro.version>
    <jwt.version>3.2.0</jwt.version>
</properties>

<dependencyManagement>
    <dependencies>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>

        <!-- 数据库驱动,可根据自己需要自行删减,默认使用mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector-java.version}</version>
        </dependency>

        <!--数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>

        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>

        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.versin}</version>
        </dependency>

        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${springfox-swagger2.version}</version>
        </dependency>

        <!--swagger-ui-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${springfox-swagger-ui.version}</version>
        </dependency>

        <!-- swagger接口文档 -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>${knife4j.version}</version>
        </dependency>

        <!--easypoi导入导出-->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>${easypoi.version}</version>
        </dependency>

        <!--WxJava - 微信开发 Java SDK-->
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-miniapp</artifactId>
            <version>${weixin.version}</version>
        </dependency>

        <!--整合Shiro安全框架-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>

        <!--集成jwt实现token认证-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>${jwt.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

####  🎯重点
此处用的标签是 **dependencyManagement**,
> **dependencyManagement只是声明依赖,并不实现引入**,因此**子项目需要显示的声明需要用的依赖**。如果**不在子项目中声明依赖,是不会从父项目中继承下来**;**只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项**,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。

******
### 🍪3.创建子模块-main(主启动层)
>右击项目chat-boot,new ->Moudle新建模块chat-boot-main

![](https://img.javadog.net/blog/chat-boot/8b702215d47c4b1a9ef46f19521cedbd_tplv-k3u1fbpfcp-zoom-1.png)
>选择对应Module SDK版本,本狗选择jdk1.8,点击Next

![](https://img.javadog.net/blog/chat-boot/329503c3d25e41ab9b070fd18f3c8c8d_tplv-k3u1fbpfcp-zoom-1.png)

>填写子模块名 chat-boot-main,然后检查对应GAV,点击Finish

![](https://img.javadog.net/blog/chat-boot/5abde94615a6444b9bfde39ebaf1cba2_tplv-k3u1fbpfcp-zoom-1.png)
>生成子模块chat-boot-main如下图

![](https://img.javadog.net/blog/chat-boot/3b75169fb0f645eba46bb975636b03eb_tplv-k3u1fbpfcp-zoom-1.png)

>完善chat-boot-main模块下pom.xml中依赖

 1. 引入必要依赖
 2. 完善profiles标签中环境相关
 3. 配置build标签中插件

```xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>chat-boot</artifactId>
        <groupId>net.javadog.chat</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>chat-boot-main</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>net.javadog.chat</groupId>
                <artifactId>chat-boot-dependencies</artifactId>
                <version>1.0-SNAPSHOT</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        <!--swagger-ui-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency>
        <!-- swagger接口文档 -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

    <build>
        <finalName>chat</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/webapp</directory>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

    <profiles>
        <profile>
            <id>local</id>
            <properties>
                <spring.active>local</spring.active>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>dev</id>
            <properties>
                <spring.active>dev</spring.active>
            </properties>
        </profile>
        <profile>
            <id>prod</id>
            <properties>
                <spring.active>prod</spring.active>
            </properties>
        </profile>
    </profiles>
</project>

🎯重点

  • 配置引入依赖chat-boot-dependencies,用作此模块依赖引入
<dependencyManagement>
     <dependencies>
         <dependency>
             <groupId>net.javadog.chat</groupId>
             <artifactId>chat-boot-dependencies</artifactId>
             <version>1.0-SNAPSHOT</version>
             <type>pom</type>
             <scope>import</scope>
         </dependency>
     </dependencies>
</dependencyManagement>
  • 配置build标签用于完善插件plugins,其中包含maven-compiler-plugin和maven-resources-plugin
<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <delimiters>
                        <delimiter>@</delimiter>
                    </delimiters>
                    <useDefaultDelimiters>false</useDefaultDelimiters>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/webapp</directory>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
  • 配置profiles环境变量标签,用于方便打包切换,本狗设置了 local、dev、prod三种环境
 <profiles>
     <profile>
         <id>local</id>
         <properties>
             <spring.active>local</spring.active>
         </properties>
         <activation>
             <activeByDefault>true</activeByDefault>
         </activation>
     </profile>
     <profile>
         <id>dev</id>
         <properties>
             <spring.active>dev</spring.active>
         </properties>
     </profile>
     <profile>
         <id>prod</id>
         <properties>
             <spring.active>prod</spring.active>
         </properties>
     </profile>
 </profiles>

操作可在IDEA右上角方便切换环境

💥切记一定主动Reload一下Maven依赖

💥切记一定主动Reload一下Maven依赖

💥切记一定主动Reload一下Maven依赖

在chat-boot-main模块中加入启动类,在src/main/java下右键New=>Java Class

录入启动类名ChatApplication

完善ChatApplication启动类代码

package net.javadog.chat;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author: hdx
 * @Date: 2023-01-28 11:24
 * @version: 1.0
 **/
@SpringBootApplication
@ServletComponentScan
@Slf4j
@EnableSwagger2
@EnableKnife4j
public class ChatApplication {
   
   
    public static void main(String[] args) throws UnknownHostException {
   
   
        // 启动类
        ConfigurableApplicationContext application = SpringApplication.run(ChatApplication.class, args);
        // 打印基础信息
        info(application);
    }

    static void info(ConfigurableApplicationContext application) throws UnknownHostException {
   
   
        Environment env = application.getEnvironment();
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = env.getProperty("server.port");
        String active = env.getProperty("spring.profiles.active");
        String contextPath = env.getProperty("server.servlet.context-path");
        if (contextPath == null) {
   
   
            contextPath = "";
        }
        log.info("\n----------------------------------------------------------\n\t" +
                "欢迎访问  \thttps://blog.javadog.net\n\t" +
                "示例程序【" + active + "】环境已启动! 地址如下:\n\t" +
                "Local: \t\thttp://localhost:" + port + contextPath + "\n\t" +
                "External: \thttp://" + ip + ':' + port + contextPath + '\n' +
                "Swagger文档: \thttp://" + ip + ":" + port + contextPath + "/doc.html\n" +
                "----------------------------------------------------------");
    }
}

配置application.yml文件


application.yml

#============================#
# server 配置
#============================#
server:
  port: 82
  max-http-header-size: 10240
  servlet:
    context-path: /chat/v1

#============================#
# spring 配置
#============================#
spring:
  application:
    # 应用名
    name: chat
  profiles:
    active: @spring.active@
  servlet:
    multipart:
      max-request-size: 100MB
      max-file-size: 100MB
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss.SSS
    locale: zh_CN
    serialization:
      # 格式化输出
      indent_output: false
  main:
    allow-circular-references: true
    #解决swagger版本路径不兼容问题
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

#============================#
# mybatisplus 配置
#============================#
mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: true
    lazy-loading-enabled: true
    multiple-result-sets-enabled: true
    log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
  global-config:
    banner: false
    db-config:
      id-type: assign_id
      table-underline: true
    enable-sql-runner: true
      #数据库类型
    db-type: MYSQL
  configuration-properties:
    prefix:
    #如果数据库为postgresql,则需要配置为blobType: BINARY
    blobType: BLOB
    #如果数据库为oracle或mssql,则需要配置为boolValue: 1
    boolValue: true

#============================#
# logging 配置
#============================#
logging:
  level:
    root: info
  file:
    path: /root/javadog/chat/logs/${
   
   spring.application.name}/
    name: ${
   
   spring.application.name}
  logback:
    rollingpolicy:
      max-history: 7
      max-file-size: 10MB

#============================#
# file 配置
#============================#
file:
  # 静态附件前缀
  static-prefix: attach
  # 上传的文件对外暴露的访问路径
  access-path-pattern: /${
   
   file.static-prefix}/**
  # 文件上传目录
  upload-folder: /root/javadog/chat/
  # 文件上传最大
  max-post-size: 10

application-local.yml

#服务配置
server:
  port: 8001
  max-http-header-size: 10240

# Mysql数据库
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/chat-boot?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT&nullCatalogMeansCurrent=true
    username: root
    password: root
  redis:
    host: localhost
    port: 6379
    password:

application-dev.yml

#服务配置
server:
  port: 7001
  max-http-header-size: 10240

# mybatisplus 配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

application-prod.yml

#服务配置
server:
  port: 8005

🌊顺便加一下logback-spring.xml 日志文件

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
    <property name="CONSOLE_LOG_PATTERN"
              value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <property name="FILE_LOG_PATTERN"
              value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <springProperty scope="context" name="application.name" source="spring.application.name" defaultValue="javadog"/>
    <springProperty scope="context" name="logging.path" source="logging.file.path" defaultValue="logs"/>
    <springProperty scope="context" name="logging.file.max-size" source="logging.logback.rollingpolicy.max-size"
                    defaultValue="10MB"/>
    <springProperty scope="context" name="logging.file.max-history" source="logging.logback.rollingpolicy.max-history"
                    defaultValue="30"/>
    <contextName>${application.name}</contextName>

    <springProfile name="dev,prod">
        <!--输出到控制台-->
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            </encoder>
        </appender>
        <root level="info">
            <appender-ref ref="console"/>
        </root>
    </springProfile>

    <springProfile name="dev,test,prod">
        <!--输出到文件-->
        <appender name="file-info" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${logging.path}/info/${application.name}-info.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${logging.path}/info/${application.name}-info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>

                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${logging.file.max-size}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                <!--只保留最近n天的日志-->
                <maxHistory>${logging.file.max-history}</maxHistory>
            </rollingPolicy>
            <!-- 追加方式记录日志 -->
            <append>true</append>
            <encoder>
                <pattern>${FILE_LOG_PATTERN}</pattern>
            </encoder>
        </appender>
        <appender name="file-warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>warn</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <file>${logging.path}/warn/${application.name}-warn.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${logging.path}$/warn/${application.name}-warn.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${logging.file.max-size}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                <!--只保留最近n天的日志-->
                <maxHistory>${logging.file.max-history}</maxHistory>
            </rollingPolicy>
            <encoder>
                <pattern>${FILE_LOG_PATTERN}</pattern>
            </encoder>
        </appender>
        <appender name="file-error" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>error</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <file>${logging.path}/error/${application.name}-error.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${logging.path}/error/${application.name}-error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${logging.file.max-size}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                <!--只保留最近n天的日志-->
                <maxHistory>${logging.file.max-history}</maxHistory>
            </rollingPolicy>
            <encoder>
                <pattern>${FILE_LOG_PATTERN}</pattern>
            </encoder>
        </appender>

        <root level="INFO">
            <appender-ref ref="file-info"/>
            <appender-ref ref="file-warn"/>
            <appender-ref ref="file-error"/>
        </root>
    </springProfile>

</configuration>

启动一下项目试试,启动如下证明成功。如果报错少依赖请再拉一下Maven依赖!!!



🍇4.创建子模块-module(模块层)

右击项目chat-boot,new ->Moudle新建模块chat-boot-module

填写子模块名 chat-boot-module,然后检查对应GAV,点击Finish

生成子模块chat-boot-module如下图

删除chat-boot-module下无用文件及目录,如src目录,删除无用目录如下

自此外部大框架初步搭建成功

完善chat-boot-module下pom.xml依赖,如lombok,web等必要依赖

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>chat-boot</artifactId>
        <groupId>net.javadog.chat</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>chat-boot-module</artifactId>
    <packaging>pom</packaging>
    <modules>
        <module>chat-boot-common</module>
        <module>chat-boot-controller</module>
        <module>chat-boot-dao</module>
        <module>chat-boot-dto</module>
        <module>chat-boot-entity</module>
        <module>chat-boot-service</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>net.javadog.chat</groupId>
                <artifactId>chat-boot-dependencies</artifactId>
                <version>${project.parent.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--WxJava - 微信开发 Java SDK-->
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-miniapp</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        <!--swagger-ui-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency>
        <!--整合Knife4j-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
        </dependency>
        <!--整合Shiro安全框架-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
        </dependency>
        <!--jwt-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

</project>

一定要重新拉取依赖!
一定要重新拉取依赖!
一定要重新拉取依赖!


🍉5.创建chat-boot-module模块下对应功能分层

目前本狗分为如下6层

  • common-共通层
  • controller-控制器层
  • dao-数据持久层
  • dto-数据传输对象层
  • entity-实体层
  • service-业务逻辑层

依次按照上述添加模块方式进行新增子模块,本狗如下示例一个,其余都如法炮制

右击项目chat-boot-module,new ->Moudle新建模块chat-boot-common

一定看清楚父模块是否正确
一定看清楚父模块是否正确
一定看清楚父模块是否正确

确认父级模块后,点击Finish,生成chat-boot-common模块

依次按照上述方法,新建其他模块

chat-boot-controller模块

chat-boot-dao模块

chat-boot-dto模块

chat-boot-entity模块

chat-boot-service模块

总体模块雏形基本完成

🍧6.实际流程填充

  • 模拟正常前端请求后台服务调用过程,进行实际代码补充

在chat-boot-entity下新建实体类User,在src/main/java下右键New=>Java Class,录入包名及类名

package net.javadog.chat.entity;

import lombok.Data;

/**
 * @author: hdx
 * @Date: 2023-01-28 14:26
 * @version: 1.0
 **/
@Data
public class User {
   
   

    private Long id;

    private String username;

    private String idCard;
}

在chat-boot-dto下新建目request和response,分别代表请求传输对象和返回传输对象,并分别在目录下创建UserRequest.java和UserResponse.java

package net.javadog.chat.request;

import lombok.Data;

/**
 * @author: hdx
 * @Date: 2023-01-28 14:59
 * @version: 1.0
 **/
@Data
public class UserRequest {
   
   

    private Long id;

    private String username;
}
package net.javadog.chat.response;

import lombok.Data;

/**
 * @author: hdx
 * @Date: 2023-01-28 14:59
 * @version: 1.0
 **/
@Data
public class UserResponse {
   
   

    private Long id;

    private String username;
}

在chat-boot-dao下修改chat-boot-dao模块下修改pom.xml文件依赖,引入chat-boot-entity;并增对应UserMapper.java

```java
package net.javadog.chat.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.javadog.chat.entity.User;

/**

  • 用户mapper
    *
  • @author: hdx
  • @Date: 2023-01-10 11:43
  • @version: 1.0
    **/
    public interface UserMapper extends BaseMapper {
    }
```xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>chat-boot-module</artifactId>
        <groupId>net.javadog.chat</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>chat-boot-dao</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>net.javadog.chat</groupId>
            <artifactId>chat-boot-entity</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
    </dependencies>

</project>

在chat-boot-service下新建目录service和impl,并在对应目录下新建UserService.java和UserServiceImpl.java,并修改chat-boot-service模块下修改pom.xml文件依赖,引入chat-boot-dto,chat-boot-dao

package net.javadog.chat.service;

import com.baomidou.mybatisplus.extension.service.IService;
import net.javadog.chat.entity.User;

/**
 * 用户接口
 *
 * @author: hdx
 * @Date: 2023-01-10 11:53
 * @version: 1.0
 **/
public interface UserService extends IService<User> {
   
   

}
package net.javadog.chat.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.javadog.chat.entity.User;
import net.javadog.chat.mapper.UserMapper;
import net.javadog.chat.service.UserService;
import org.springframework.stereotype.Service;

/**
 * 用户接口实现类
 *
 * @author: hdx
 * @Date: 2023-01-10 11:55
 * @version: 1.0
 **/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
   
   

}
<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>chat-boot-module</artifactId>
        <groupId>net.javadog.chat</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>chat-boot-service</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>net.javadog.chat</groupId>
            <artifactId>chat-boot-dao</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
        <dependency>
            <groupId>net.javadog.chat</groupId>
            <artifactId>chat-boot-dto</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
    </dependencies>

</project>

在chat-boot-controller创建UserController.java,并修改chat-boot-controller模块下修改pom.xml文件依赖,引入chat-boot-dto,chat-boot-service

package net.javadog.chat.controller;

import cn.hutool.core.bean.BeanUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.javadog.chat.entity.User;
import net.javadog.chat.request.UserRequest;
import net.javadog.chat.response.UserResponse;
import net.javadog.chat.service.UserService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * 用户控制器
 *
 * @author: hdx
 * @Date: 2022-12-07 15:48
 * @version: 1.0
 **/
@Api(tags = "用户控制器")
@RestController
@RequestMapping("/user")
public class UserController {
   
   

    @Resource
    private UserService userService;

    @ApiOperation(value = "用户详情", notes = "用户详情")
    @GetMapping
    public UserResponse detail(UserRequest userRequest){
   
   
        UserResponse userResponse = new UserResponse();
        User user = userService.getById(userRequest.getId());
        BeanUtil.copyProperties(user, userResponse);
        return userResponse;
    }

}

🎯重要补充
1.切记修改chat-boot-main下的pom.xml依赖,将chat-boot-controller模块加入
2.切记修改chat-boot-main下的pom.xml依赖,将chat-boot-dao模块加入
3.切记修改启动类ChatApplication中加入@MapperScan注解

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>chat-boot</artifactId>
        <groupId>net.javadog.chat</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>chat-boot-main</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>net.javadog.chat</groupId>
                <artifactId>chat-boot-dependencies</artifactId>
                <version>1.0-SNAPSHOT</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        <!--swagger-ui-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency>
        <!-- swagger接口文档 -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
        </dependency>

        <!-- controller -->
        <dependency>
            <groupId>net.javadog.chat</groupId>
            <artifactId>chat-boot-controller</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
        <!-- dao -->
        <dependency>
            <groupId>net.javadog.chat</groupId>
            <artifactId>chat-boot-dao</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <delimiters>
                        <delimiter>@</delimiter>
                    </delimiters>
                    <useDefaultDelimiters>false</useDefaultDelimiters>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/webapp</directory>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

    <profiles>
        <profile>
            <id>local</id>
            <properties>
                <spring.active>local</spring.active>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>dev</id>
            <properties>
                <spring.active>dev</spring.active>
            </properties>
        </profile>
        <profile>
            <id>prod</id>
            <properties>
                <spring.active>prod</spring.active>
            </properties>
        </profile>
    </profiles>
</project>

package net.javadog.chat;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author: hdx
 * @Date: 2023-01-28 11:24
 * @version: 1.0
 **/
@SpringBootApplication
@ServletComponentScan
@Slf4j
@EnableSwagger2
@EnableKnife4j
@MapperScan(basePackages = {
   
   "net.javadog.chat.mapper"})
public class ChatApplication {
   
   
    public static void main(String[] args) throws UnknownHostException {
   
   
        // 启动类
        ConfigurableApplicationContext application = SpringApplication.run(ChatApplication.class, args);
        // 打印基础信息
        info(application);
    }

    static void info(ConfigurableApplicationContext application) throws UnknownHostException {
   
   
        Environment env = application.getEnvironment();
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = env.getProperty("server.port");
        String active = env.getProperty("spring.profiles.active");
        String contextPath = env.getProperty("server.servlet.context-path");
        if (contextPath == null) {
   
   
            contextPath = "";
        }
        log.info("\n----------------------------------------------------------\n\t" +
                "欢迎访问  \thttps://blog.javadog.net\n\t" +
                "示例程序【" + active + "】环境已启动! 地址如下:\n\t" +
                "Local: \t\thttp://localhost:" + port + contextPath + "\n\t" +
                "External: \thttp://" + ip + ':' + port + contextPath + '\n' +
                "Swagger文档: \thttp://" + ip + ":" + port + contextPath + "/doc.html\n" +
                "----------------------------------------------------------");
    }
}

🦔7.示例DB更新

  • 模拟正常前端请求后台服务调用过程,进行实际代码补充

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `id_card` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '身份证',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'JavaDog', '123123');

🧩8.访问测试

浏览器访问http://localhost:8001/chat/v1/user?id=1

测试成功如下图所示

总结

以上示例只是简单示范分层思路,其中代码逻辑实现方式有很多种,大家选取适用自己就好,希望自己的思路能对大家有帮助

如遇缺少依赖情况,一定要重新拉取依赖!

写在最后

此生两悔,悔遇见你,更悔未早遇见你,珍惜当下拥有,勿念昔日美好。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
12天前
|
Java 容器
如何在SpringBoot项目中使用过滤器和拦截器
过滤器和拦截器是日常开发中常用技术,用于对特定请求进行增强处理,如插入自定义代码以实现特定功能。过滤器在请求到达 `servlet` 前执行,而拦截器在请求到达 `servlet` 后执行。`SpringBoot` 中的拦截器依赖于 `SpringBoot` 容器,过滤器则由 `servlet` 提供。通过实现 `Filter` 接口并重写 `doFilter()` 方法可实现过滤器;通过实现 `HandlerInterceptor` 接口并重写相应方法可实现拦截器。两者的主要区别在于执行时机的不同,需根据具体场景选择使用。
如何在SpringBoot项目中使用过滤器和拦截器
|
6天前
|
Java 关系型数据库 MySQL
创建一个SpringBoot项目,实现简单的CRUD功能和分页查询
【9月更文挑战第6天】该内容介绍如何使用 Spring Boot 实现具备 CRUD 功能及分页查询的项目。首先通过 Spring Initializr 创建项目并选择所需依赖;其次配置数据库连接,并创建实体类与数据访问层;接着构建服务层处理业务逻辑;最后创建控制器处理 HTTP 请求。分页查询可通过添加 URL 参数实现。
|
15天前
|
小程序 前端开发 Java
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
JavaDog Chat v1.0.0 是一款基于 SpringBoot、MybatisPlus 和 uniapp 的简易聊天软件,兼容 H5、小程序和 APP,提供丰富的注释和简洁代码,适合初学者。主要功能包括登录注册、消息发送、好友管理及群组交流。
37 0
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
|
24天前
|
JavaScript 前端开发 Java
SpringBoot + Vue 前端后分离项目精进版本
这篇文章详细介绍了一个基于SpringBoot + Vue的前后端分离项目的搭建过程,包括前端Vue项目的初始化、依赖安装、页面创建和路由配置,以及后端SpringBoot项目的依赖添加、配置文件修改、代码实现和跨域问题的解决,最后展示了项目运行效果。
SpringBoot + Vue 前端后分离项目精进版本
|
25天前
|
Java
SpringBoot项目配置热部署启动 及 热部署失效的问题解决
这篇文章介绍了如何在SpringBoot项目中配置热部署启动,包括在pom文件中添加热部署依赖、在IDEA中进行设置、修改配置文件以及IDEA启动设置,以解决热部署失效的问题。
SpringBoot项目配置热部署启动 及 热部署失效的问题解决
|
15天前
|
小程序 前端开发 JavaScript
【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序
【避坑宝】是一款企业黑红名单吐槽小程序,旨在帮助打工人群体辨别企业优劣。该平台采用SpringBoot+MybatisPlus+uniapp+uview2等技术栈构建,具备丰富的注释与简洁的代码结构,非常适合实战练习与学习。通过小程序搜索“避坑宝”即可体验。
37 0
【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序
|
15天前
|
JavaScript 前端开发 小程序
【项目实战】SpringBoot+vue+iview打造一个极简个人博客系统
这是一个基于 SpringBoot+MybatisPlus+Vue+Iview 技术栈构建的个人极简博客系统,适合初学者实战练习。项目包含文章分类、撰写文章、标签管理和用户管理等功能,代码简洁并配有详细注释,易于上手。此外,该项目也可作为毕业设计的基础进行二次开发。
61 0
【项目实战】SpringBoot+vue+iview打造一个极简个人博客系统
|
23天前
|
安全 Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+jsp实现的健身房管理系统(含教程&源码&数据库数据)
本文介绍了一款基于Spring Boot和JSP技术实现的健身房管理系统。随着健康生活观念的普及,健身房成为日常锻炼的重要场所,高效管理会员信息、课程安排等变得尤为重要。该系统旨在通过简洁的操作界面帮助管理者轻松处理日常运营挑战。技术栈包括:JDK 1.8、Maven 3.6、MySQL 8.0、JSP、Shiro、Spring Boot 2.0等。系统功能覆盖登录、会员管理(如会员列表、充值管理)、教练管理、课程管理、器材管理、物品遗失管理、商品管理及信息统计等多方面。
|
21天前
|
JavaScript Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+vue实现的前后端分离的考试管理系统(含教程&源码&数据库数据)
在数字化时代背景下,本文详细介绍了如何使用Spring Boot框架结合Vue.js技术栈,实现一个前后端分离的考试管理系统。该系统旨在提升考试管理效率,优化用户体验,确保数据安全及可维护性。技术选型包括:Spring Boot 2.0、Vue.js 2.0、Node.js 12.14.0、MySQL 8.0、Element-UI等。系统功能涵盖登录注册、学员考试(包括查看试卷、答题、成绩查询等)、管理员功能(题库管理、试题管理、试卷管理、系统设置等)。
毕设项目&课程设计&毕设项目:基于springboot+vue实现的前后端分离的考试管理系统(含教程&源码&数据库数据)
|
前端开发 JavaScript 关系型数据库
前后端分离 -- SpringBoot + Vue实战项目 部署至阿里云服务器
前后端分离 -- SpringBoot + Vue实战项目 部署至阿里云服务器
3169 2
前后端分离 -- SpringBoot + Vue实战项目 部署至阿里云服务器