基于Maven构建SpringBoot多模块项目(完整实操指南)
你想通过pom.xml搭建SpringBoot多模块项目,核心思路是拆分「父模块(统一管理依赖+版本)+ 子模块(按功能/分层拆分)」,既解耦代码,又能统一管理依赖版本,适配企业级开发规范。以下是从「空项目初始化 → 模块拆分 → 依赖配置 → 启动测试」的全流程。
一、多模块项目结构设计(通用规范)
先明确拆分逻辑,以你的UDP设备探测项目为例,推荐经典的4模块结构(可按需增减):
udp-scan-parent(父模块,pom类型)
├── udp-scan-common(公共模块,jar类型:工具类、通用实体、常量)
├── udp-scan-mapper(数据层模块,jar类型:Mapper、MyBatis-Plus配置)
├── udp-scan-service(业务层模块,jar类型:Service接口/实现)
└── udp-scan-web(启动模块,jar类型:Controller、SpringBoot启动类、配置文件)
- 父模块:仅管理依赖版本,不写业务代码;
- 子模块 :按分层拆分,
web模块是唯一的启动模块(含@SpringBootApplication)。
二、步骤1:创建父模块(pom.xml核心配置)
父模块的核心作用是统一管理依赖版本、插件版本,定义子模块继承规则 ,类型为pom(无源码,仅做依赖管理)。
1. 父模块pom.xml(完整代码)
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">
<!-- 基础配置 -->
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging> <!-- 父模块必须为pom类型 -->
<groupId>com.example</groupId> <!-- 公司/组织标识 -->
<artifactId>udp-scan-parent</artifactId> <!-- 父模块名称 -->
<version>1.0.0</version> <!-- 统一版本号 -->
<name>udp-scan-parent</name>
<description>UDP设备探测项目-父模块(统一依赖管理)</description>
<!-- 1. 定义子模块(后续创建的子模块需在这里声明) -->
<modules>
<module>udp-scan-common</module>
<module>udp-scan-mapper</module>
<module>udp-scan-service</module>
<module>udp-scan-web</module>
</modules>
<!-- 2. 继承SpringBoot父工程(统一SpringBoot版本) -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version> <!-- SpringBoot版本(JDK17用3.x,JDK8用2.7.18) -->
<relativePath/> <!-- 从Maven仓库拉取,不找本地路径 -->
</parent>
<!-- 3. 统一管理依赖版本(子模块直接用,无需写版本号) -->
<dependencyManagement>
<dependencies>
<!-- 自定义子模块依赖(子模块间相互依赖时用) -->
<dependency>
<groupId>com.example</groupId>
<artifactId>udp-scan-common</artifactId>
<version>${project.version}</version> <!-- 继承父模块版本 -->
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>udp-scan-mapper</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>udp-scan-service</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 第三方依赖版本管理(MyBatis-Plus、MySQL等) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 4. 全局依赖(所有子模块都会继承,按需添加) -->
<dependencies>
<!-- Lombok(所有子模块都可能用到) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试依赖(所有子模块的测试都可用) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 5. 构建插件配置(统一编译、打包规则) -->
<build>
<plugins>
<!-- SpringBoot打包插件(仅启动模块生效,父模块声明统一配置) -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.example.udp.web.UdpScanApplication</mainClass> <!-- 启动类全路径 -->
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal> <!-- 打包成可执行jar -->
</goals>
</execution>
</executions>
</plugin>
<!-- 编译插件(指定JDK版本) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source> <!-- JDK版本(17/8) -->
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
关键配置说明
| 节点 | 作用 | 注意事项 |
|---|---|---|
<packaging>pom</packaging> |
标记为父模块,仅管理依赖/子模块 | 父模块必须设为pom,子模块默认jar |
<modules> |
声明子模块名称,与子模块文件夹名一致 | 子模块创建后必须在这里声明,否则Maven无法识别 |
<dependencyManagement> |
仅管理版本,不实际引入依赖 | 子模块需手动<dependency>引入,无需写版本号 |
<dependencies> |
全局依赖,所有子模块自动继承 | 仅放所有子模块都需要的依赖(如lombok),避免冗余 |
三、步骤2:创建子模块(按分层拆分)
每个子模块的pom.xml只需继承父模块,按需引入依赖即可,无需重复定义版本号。
子模块1:udp-scan-common(公共模块)
作用:存放通用工具类、实体类、常量、枚举等,被其他子模块依赖。
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>
<groupId>com.example</groupId>
<artifactId>udp-scan-parent</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath> <!-- 父模块pom.xml路径 -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>udp-scan-common</artifactId> <!-- 子模块名称 -->
<name>udp-scan-common</name>
<description>公共模块:工具类、实体类</description>
<!-- 依赖:仅引入公共模块需要的依赖 -->
<dependencies>
<!-- SpringBoot核心(可选,若需要Spring相关工具) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 常用工具包(如hutool,可选) -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
</dependencies>
</project>
子模块2:udp-scan-mapper(数据层模块)
作用:存放Mapper接口、MyBatis-Plus配置、自定义SQL等,依赖common模块。
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>
<groupId>com.example</groupId>
<artifactId>udp-scan-parent</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>udp-scan-mapper</artifactId>
<name>udp-scan-mapper</name>
<description>数据层:Mapper、MyBatis-Plus配置</description>
<dependencies>
<!-- 依赖公共模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>udp-scan-common</artifactId>
</dependency>
<!-- MyBatis-Plus(版本由父模块管理) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
子模块3:udp-scan-service(业务层模块)
作用:存放Service接口/实现,依赖mapper模块。
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>
<groupId>com.example</groupId>
<artifactId>udp-scan-parent</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>udp-scan-service</artifactId>
<name>udp-scan-service</name>
<description>业务层:Service接口/实现</description>
<dependencies>
<!-- 依赖公共模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>udp-scan-common</artifactId>
</dependency>
<!-- 依赖数据层模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>udp-scan-mapper</artifactId>
</dependency>
<!-- SpringBoot核心(业务层需要Spring容器) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
子模块4:udp-scan-web(启动模块)
作用:存放Controller、启动类、配置文件,是唯一的启动模块,依赖service模块。
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>
<groupId>com.example</groupId>
<artifactId>udp-scan-parent</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>udp-scan-web</artifactId>
<name>udp-scan-web</name>
<description>启动模块:Controller、启动类、配置文件</description>
<dependencies>
<!-- 依赖公共模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>udp-scan-common</artifactId>
</dependency>
<!-- 依赖业务层模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>udp-scan-service</artifactId>
</dependency>
<!-- SpringBoot Web(Controller需要) -->
<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>
<!-- 资源文件配置(读取application.yml) -->
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
四、步骤3:项目目录结构与启动类
1. 最终目录结构(对应pom配置)
udp-scan-parent/
├── pom.xml(父模块)
├── udp-scan-common/
│ ├── pom.xml
│ └── src/main/java/com/example/udp/common/
│ ├── entity/Device.java(通用实体)
│ ├── util/HttpUtil.java(工具类)
│ └── constant/Constants.java(常量)
├── udp-scan-mapper/
│ ├── pom.xml
│ └── src/main/java/com/example/udp/mapper/
│ ├── DeviceMapper.java(Mapper接口)
│ └── config/MyBatisPlusConfig.java(分页插件配置)
├── udp-scan-service/
│ ├── pom.xml
│ └── src/main/java/com/example/udp/service/
│ ├── DeviceService.java(接口)
│ └── impl/DeviceServiceImpl.java(实现)
└── udp-scan-web/
├── pom.xml
└── src/main/
├── java/com/example/udp/web/
│ ├── UdpScanApplication.java(启动类)
│ └── controller/DeviceController.java(控制器)
└── resources/application.yml(配置文件)
2. 启动类编写(udp-scan-web模块)
java
package com.example.udp.web;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* 多模块项目启动类(核心:扫描所有子模块的包)
*/
@SpringBootApplication
// 扫描所有子模块的组件(com.example.udp下的所有包)
@ComponentScan(basePackages = "com.example.udp")
// 扫描Mapper接口(mapper模块)
@MapperScan(basePackages = "com.example.udp.mapper")
public class UdpScanApplication {
public static void main(String[] args) {
SpringApplication.run(UdpScanApplication.class, args);
}
}
五、步骤4:编译与启动(验证多模块)
1. 编译打包(父模块根目录执行)
bash
# 清理并编译所有模块
mvn clean compile
# 打包(web模块会生成可执行jar)
mvn clean package
2. 启动项目
-
IDEA中启动 :直接运行
UdpScanApplication类,控制台无报错且能加载application.yml,说明多模块配置成功; -
jar包启动 :进入
udp-scan-web/target目录,执行:bashjava -jar udp-scan-web-1.0.0.jar
六、多模块配置避坑指南
1. 依赖循环问题
- 禁止子模块相互依赖(如service依赖mapper,mapper又依赖service);
- 通用逻辑放在common模块,避免循环依赖。
2. 包扫描问题
- 启动类的
@ComponentScan必须覆盖所有子模块的包(如com.example.udp); @MapperScan必须扫描mapper模块的Mapper接口包,否则MyBatis-Plus无法识别。
3. 资源文件加载问题
- 只有web模块需要放
application.yml,其他模块无需配置文件; - 若其他模块有自定义配置文件,需在web模块通过
@PropertySource加载。
4. 版本号统一问题
- 所有子模块的版本号必须与父模块一致,推荐用
${project.version}继承; - 第三方依赖版本统一在父模块
dependencyManagement中管理,子模块不写版本号。
总结
- 多模块SpringBoot项目的核心是「父模块pom(管理依赖)+ 子模块jar(按分层拆分)」;
- 父模块关键配置:
<packaging>pom</packaging>+<modules>+<dependencyManagement>; - 子模块关键:继承父模块 + 按需引入依赖 + 仅web模块作为启动模块;
- 启动类必须扫描所有子模块的包,否则组件/Mapper无法被Spring容器识别。