掘金 后端 ( ) • 2024-04-23 10:42

关于版本选择:JDK(1.8)、SpringBoot(2.6.3)、MyBatis-Spring-Boot(2.2.2)、Maven(3.9.6)

新建Spring Boot多模块工程

模块设计

Spring Boot各模块及模块设计如下:

cnc-test-start :启动配置、web相关入口

cnc-test-common:通用类功能,日志处理、异常、通用工具等。

cnc-test-persistence:数据库持久化相关

cnc-test-service:业务逻辑部分

为什么要设计这么多模块:

1、方便代码组织,提高代码可读性,企业级服务代码量一般都不会少,试想如果整个代码放在一起,查找起来是不是很不方便,分层后先判断要查找的代码再哪一层,就大大减少了查找成本。

2、方便管理maven依赖,父工程中管理公共依赖,每一层管理各自的依赖,减少重复依赖及依赖版本不统一等各种问题。

依赖关系,默认上层依赖下层:

  • Web 端:前端部分,所有业务请求均由前端发起,前端请求后端返回业务数据进行页面渲染。
  • 开放API:对外提供的开放接口,根据业务需要决定是否需要该层。
  • Start(Web层):主要是Web端请求入口,接收请求数据并返回响应数据,各类请求参数校验,或者不复用的业务简单处理等。
  • Service 层:相对具体的业务逻辑服务层。
  • Persistence 层:数据访问层,与底层 MySQL进行数据交互。
  • Common层:整个系统公共的部分,比如全局异常处理、登录鉴权、业务日志打印、通用工具封装等等都放在该层。
  • 第三方服务:包括与其他服务的集成(根据需要)。
  • 外部数据接口:外部(应用)数据存储服务提供的接口(根据需要)。
  • 数据库存储系统:存储业务数据的数据库,如MySQL等。

通过Maven创建各模块

1、新建父工程

打开IDEA,新建工程,按如下配置,注意1处的地址需要修改下,不然选择不了Java8,Name、Group、Artifact可自行命名:

Spring Boot 没有2.6.3的版本可供选择,可以先选择2.6.13的,后面在代码里再改为2.6.3的:

由于这是个父级工程,具体代码都在每个子模块中写,所以可以将src文件夹删除,HELP.md改为README.md,最终的目录格式如下:

整理pom.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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <!-- 将spring boot版本改为2.6.3 -->
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.3</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <!-- 父项目的坐标,如果子项目没有规定某个坐标的值如version,则父项目的值即为其的值 -->
  <groupId>com.cxzx</groupId>
  <artifactId>cnc-test</artifactId>
  <version>${cncproject.version}</version>
  <name>cnc-test</name>
  <description>cnc-test</description>

  <!-- 打包方式 -->
  <packaging>pom</packaging>

  <!-- 子模块管理 -->
  <modules>

  </modules>

  <!-- 统一版本号 可以理解为父项目及其子项目的公共变量 -->
  <properties>
    <cncproject.version>0.0.1-SNAPSHOT</cncproject.version>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  </properties>

  <!-- 统一依赖定义 定义整个项目依赖的版本,子工程中需要使用,直接引用不用带版本号,解决不同子工程引入
  相同依赖而版本号定义的不同的问题-->
  <dependencyManagement>

  </dependencyManagement>


  <build>
    <!-- 统一插件、jar包构建等相关 -->
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
          <configuration>
            <excludes>

            </excludes>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>

  <!-- maven仓库改为阿里云的提供下载速度 -->
  <repositories>
    <repository>
      <id>aliyunmaven</id>
      <name>aliyun</name>
      <url>https://maven.aliyun.com/repository/public</url>
    </repository>
  </repositories>
</project>

2、创建子模块(common层)

工程名上右键:

按如下配置:

删掉无关文件,最终目录结构如下,注意把CncTestCommonApplication.java删掉(启动相关类及配置在start层),test文件夹也要删掉,一般企业应用都要求快速迭代,所以很少写单元测试:

整理pom.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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.cxzx</groupId>
        <artifactId>cnc-test</artifactId>
        <version>${cncproject.version}</version>
    </parent>

    <groupId>com.cxzx</groupId>
    <artifactId>cnc-test-common</artifactId>
    <name>cnc-test-common</name>
    <description>cnc-test-common</description>

    <dependencies>
      
    </dependencies>
</project>

3、创建子模块(persistence层)

删除无用文件:

整理pom.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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.cxzx</groupId>
        <artifactId>cnc-test</artifactId>
        <version>${cncproject.version}</version>
    </parent>

    <groupId>com.cxzx</groupId>
    <artifactId>cnc-test-persistence</artifactId>
    <name>cnc-test-persistence</name>
    <description>cnc-test-persistence</description>

    <dependencies>

    </dependencies>
</project>

4、新建子模块(service层)

新建:

删除无用文件:

整理pom,最终如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.cxzx</groupId>
        <artifactId>cnc-test</artifactId>
        <version>${cncproject.version}</version>
    </parent>

    <groupId>com.cxzx</groupId>
    <artifactId>cnc-test-service</artifactId>
    <name>cnc-test-service</name>
    <description>cnc-test-service</description>
</project>

5、新建子模块(starter层)

勾选Spring Web:

整理文件结构:

整理pom文件:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.cxzx</groupId>
        <artifactId>cnc-test</artifactId>
        <version>${cncproject.version}</version>
    </parent>

    <groupId>com.cxzx</groupId>
    <artifactId>cnc-test-start</artifactId>
    <name>cnc-test-start</name>
    <description>cnc-test-start</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

6、梳理个层间的依赖

父工程中定义各个模块信息:

<!-- ........ 省略 -->
    <!-- 子模块管理 -->
    <modules>
        <module>cnc-test-start</module>
        <module>cnc-test-common</module>
        <module>cnc-test-persistence</module>
        <module>cnc-test-service</module>
    </modules>
<!-- ........ 省略 -->
    <!-- 统一依赖定义 定义整个项目依赖的版本,子工程中需要使用,直接引用不用带版本号,解决不同子工程引入
    相同依赖而版本号定义的不同的问题-->
    <dependencyManagement>
        <dependencies>
          <!-- ........ 省略 -->
            <!-- 定义内部模块 -->
            <dependency>
                <groupId>com.cxzx</groupId>
                <artifactId>cnc-test-common</artifactId>
                <version>${cncproject.version}</version>
            </dependency>
            <dependency>
                <groupId>com.cxzx</groupId>
                <artifactId>cnc-test-starter</artifactId>
                <version>${cncproject.version}</version>
            </dependency>
            <dependency>
                <groupId>com.cxzx</groupId>
                <artifactId>cnc-test-persistence</artifactId>
                <version>${cncproject.version}</version>
            </dependency>
            <dependency>
                <groupId>com.cxzx</groupId>
                <artifactId>cnc-test-service</artifactId>
                <version>${cncproject.version}</version>
            </dependency>
          <!-- ........ 省略 -->
          </dependencies>
    </dependencyManagement>
<!-- ........ 省略 -->

start层引入common和service依赖:

<!-- ........ 省略 -->
  <dependencies>
        <dependency>
            <groupId>com.cxzx</groupId>
            <artifactId>cnc-test-common</artifactId>
        </dependency>
        <dependency>
            <groupId>com.cxzx</groupId>
            <artifactId>cnc-test-service</artifactId>
        </dependency>
  <!-- ........ 省略 -->
  </dependencies>
<!-- ........ 省略 -->

service层引入common和persistence依赖:

<!-- ........ 省略 -->
  <dependencies>
        <dependency>
            <groupId>com.cxzx</groupId>
            <artifactId>cnc-test-common</artifactId>
        </dependency>
        <dependency>
            <groupId>com.cxzx</groupId>
            <artifactId>cnc-test-persistence</artifactId>
        </dependency>
  <!-- ........ 省略 -->
  </dependencies>
<!-- ........ 省略 -->

5、启动工程:

先执行1处的reload project

打开CncTestStartApplication 启动工程,Console打印如下信息说明启动成功:

Spring Boot多环境配置

开发Spring Boot应用时,根据软件开发的不同周期,代码会被部署到不同的环境上,比如开发测试环境、预发环境、生产环境,每个环境的数据库地址、服务器端口等配置信息是不一样的,如果在不同的环境打包时都要频繁的修改配置,必将非常繁琐且容易出错。Spring Boot提供的解决思路是提供多种配置文件,启动时通过指定参数来决定读取哪份配置。

在Spring Boot中多环境配置文件名需要满足application-{profile}.properties的格式,其中{profile}对应你的环境标识,比如:

application.properties:默认配置
application-dev.properties:开发环境

application-pre.properties:开发环境
application-prod.properties:生产环境

因此,我们也在start层下新建多种配置文件:

具体加载哪个配置,可以在application.properties文件中通过spring.profiles.active属性来设置,其值对应{profile}值:

最终部署时可以通过jar启动参数:-Dspring-boot.run.profiles=prod指定。

集成swagger调式页面

前后端分离架构中,前端后端独立开发,后端开发中对于接口是否正常运行需要调试。Swagger是一款RESTFUL接口的文档在线自动生成+功能测试功能软件。Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务。而Knife4j是基于swagger做了增强,可以比swagger更友好的显示接口文档。

1、父pom中定义Knife4j版本

<!-- ........ 省略 -->
    <!-- 统一版本号 可以理解为父项目及其子项目的公共变量 -->
    <properties>
        <!-- ........ 省略 -->
        <knife4j.version>4.3.0</knife4j.version>
    </properties>
    <!-- 统一依赖定义 定义整个项目依赖的版本,子工程中需要使用,直接引用不用带版本号,解决不同子工程引入
    相同依赖而版本号定义的不同的问题-->
    <dependencyManagement>
        <dependencies>
            <!-- knife4j(API 文档工具) -->
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
                <version>${knife4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
<!-- ........ 省略 -->

swagger调式页面属于公共功能,所以放到了common层。

2、start层中定义bean扫描路径

CncTestStartApplication.java中加入注解:@ComponentScan({"com.cxzx.cnctest.*"})

2、common层开发代码

common层的pom中引入依赖:

<!-- ........ 省略 -->
    <dependencies>
        <!-- knife4j(API 文档工具) -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
<!-- ........ 省略 -->

新建config目录:

config包下新建Knife4jConfig类:

完整代码如下:

package com.cxzx.cnctest.common.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

/**
 * @author 某角落的IT打杂工
 * @version 1.0
 * @description: TODO
 * @date 2024/4/22 21:19
 */
@Configuration
@EnableSwagger2WebMvc
@Profile("dev")
public class Knife4jConfig {
    @Bean("webApi")
    public Docket createApiDoc() {
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
        .apiInfo(buildApiInfo())
        // 分组名称
        .groupName("分组1接口文档")
        .select()
        // 这里指定 Controller 扫描包路径
        .apis(RequestHandlerSelectors.basePackage("com.cxzx.cnctest.start"))
        .paths(PathSelectors.any())
        .build();
        return docket;
    }

    /**
     * 构建 API 信息
     * @return ApiInfo
     */
    private ApiInfo buildApiInfo() {
        return new ApiInfoBuilder()
        .title("企业级服务-demon测试接口文档") // 标题
        .description("企业级服务-demon测试接口文档") // 描述
        .termsOfServiceUrl(" ") // API 服务条款
        .contact(new Contact("某角落的IT打杂工", " ", "[email protected]")) // 联系人
        .version("1.0") // 版本号
        .build();
    }
}

@Profile("dev") 注解用于标明仅开发环境开启。

重新启动工程:

出现如下信息说明启动成功:

浏览器打开http://localhost:8080/doc.html

具体如何调式,后面开发接口时再进行说明。