在实际企业开发中,简单的单模块 SpringBoot 项目只能用来快速 Dem)o 或小型应用,一旦业务复杂、团队人数变多、需求迭代加快,单模块就会暴露出代码混乱、职责不清、难以维护、编译打包慢、不利于后期微服务拆分等一系列问题。
而 SpringBoot 多模块架构 ,正是解决这些问题的标准方案。它不仅仅是把代码拆成几个文件夹,而是真正意义上的工程化、规范化、分层解耦,也是后端开发者从"会写代码"走向"会做架构"的重要一步。
一、为什么必须使用多模块项目?
多模块不是为了复杂而复杂,而是为了工程更健康:
-
- 职责单一,高内聚低耦合
-
• Controller 只负责接收请求、返回结果
-
• Service 只负责业务逻辑、事务、流程编排
-
• Dao 只负责数据库交互
-
• 每层只依赖下层,不跨层调用
-
- 代码复用性极强
-
-
• 工具类、常量、通用配置放在 common
-
• 实体类统一放在 pojo,全工程共享
-
• 避免重复代码,减少 Bug
-
-
- 编译速度大幅提升
-
-
• 修改单个模块只打包当前模块
-
• 大型项目节省大量时间
-
-
- 便于团队协作开发
-
-
• 前端只对接 web 模块
-
• 业务开发专注 service
-
• DBA 关注 dao
-
• 互不干扰、权限清晰
-
-
- 平滑过渡微服务
-
-
• 多模块是微服务的"前身"
-
• 未来业务膨胀,可直接把模块独立成微服务
-
-
- 结构规范,新人快速上手
-
-
• 统一包结构、统一配置、统一规范
-
• 降低团队沟通与维护成本
二、标准多模块结构设计
最经典、最通用、最稳定的结构如下:
gospringboot-multi-module ├── pom.xml # 父工程:统一版本、依赖管理 ├── module-common # 公共模块:工具、异常、配置、常量 ├── module-pojo # 实体模块:entity/dto/vo/bo ├── module-dao # 数据访问层:mapper、repository、xml ├── module-service # 业务逻辑层:service接口、实现、事务 └── module-web # 接口层:controller、拦截器、启动类各模块职责说明
-
- module-common
-
• 全局工具类:DateUtil、StringUtil、BeanUtil
-
• 全局异常处理、统一返回封装
-
• 全局配置类:Redis、MyBatis、线程池
-
• 常量、枚举、公共注解
-
-
- module-pojo
-
-
• Entity:数据库映射实体
-
• DTO:前端传入参数封装
-
• VO:返回前端视图对象
-
• BO:业务层内部传递对象
-
• Query:分页查询条件
-
-
- module-dao
-
-
• Mapper 接口(MyBatis/MyBatis-Plus)
-
• Repository(JPA、ES、MongoDB)
-
• Mapper XML 文件
-
• 数据源相关配置
-
-
- module-service
-
-
• Service 接口
-
• ServiceImpl 业务实现
-
• 事务控制
-
• 缓存逻辑
-
• 第三方接口调用
-
• 内部逻辑编排
-
-
- module-web
-
-
• Controller 接口
-
• 全局跨域、过滤器、拦截器
-
• 项目启动类
-
• application.yml / application-prod.yml
-
• Swagger/Knife4j 接口文档
三、第一步:创建父工程(统一版本管理)
父工程 packaging = pom,只做依赖管理,不写业务代码。
父 pom.xml
go<?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> <groupId>com.demo</groupId> <artifactId>springboot-multi-module</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <name>springboot-multi-module</name> <!-- 子模块声明 --> <modules> <module>module-common</module> <module>module-pojo</module> <module>module-dao</module> <module>module-service</module> <module>module-web</module> </modules> <!-- 统一版本 --> <properties> <java.version>1.8</java.version> <spring.boot.version>2.7.18</spring.boot.version> <mybatis.plus.version>3.5.3.1</mybatis.plus.version> <lombok.version>1.18.30</lombok.version> </properties> <!-- 全局依赖版本管理 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis.plus.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> </dependencies> </dependencyManagement> </project>
四、第二步:逐个创建子模块
1. module-pojo 实体模块
所有数据结构统一存放,不依赖任何业务模块,只依赖 lombok。
pom.xml
go<parent> <groupId>com.demo</groupId> <artifactId>springboot-multi-module</artifactId> <version>1.0.0</version> </parent> <artifactId>module-pojo</artifactId> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>示例 User.java
go@Data @TableName("t_user") public class User { @TableId(type = IdType.AUTO) private Long id; private String username; private String password; private Integer status; private LocalDateTime createTime; }UserVO.java
go@Data public class UserVO { private Long id; private String username; private Integer status; }
2. module-common 公共模块
依赖:pojo
go<parent> <groupId>com.demo</groupId> <artifactId>springboot-multi-module</artifactId> <version>1.0.0</version> </parent> <artifactId>module-common</artifactId> <dependencies> <dependency> <groupId>com.demo</groupId> <artifactId>module-pojo</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.25</version> </dependency> </dependencies>统一返回 Result
go@Data public class Result<T> { private Integer code; private String msg; private T data; public static <T> Result<T> success(T data) { Result<T> r = new Result<>(); r.setCode(200); r.setMsg("success"); r.setData(data); return r; } public static <T> Result<T> fail(String msg) { Result<T> r = new Result<>(); r.setCode(500); r.setMsg(msg); return r; } }
3. module-dao 数据访问层
依赖:pojo + common + mybatis-plus
go<parent> <groupId>com.demo</groupId> <artifactId>springboot-multi-module</artifactId> <version>1.0.0</version> </parent> <artifactId>module-dao</artifactId> <dependencies> <dependency> <groupId>com.demo</groupId> <artifactId>module-pojo</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.demo</groupId> <artifactId>module-common</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies> <!-- 打包 xml --> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.xml</include> <include>**/*.yml</include> </includes> </resource> </resources> </build>UserMapper.java
gopublic interface UserMapper extends BaseMapper<User> { }
4. module-service 业务层
依赖:dao + common + pojo
go<parent> <groupId>com.demo</groupId> <artifactId>springboot-multi-module</artifactId> <version>1.0.0</version> </parent> <artifactId>module-service</artifactId> <dependencies> <dependency> <groupId>com.demo</groupId> <artifactId>module-dao</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.demo</groupId> <artifactId>module-common</artifactId> <version>1.0.0</version> </dependency> </dependencies>UserService.java
gopublic interface UserService { UserVO getUserById(Long id); }UserServiceImpl.java
go@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override @Transactional(rollbackFor = Exception.class) public UserVO getUserById(Long id) { User user = userMapper.selectById(id); if (user == null) { throw new RuntimeException("用户不存在"); } return BeanUtil.copyProperties(user, UserVO.class); } }
5. module-web 接口层(启动模块)
依赖:service
go<parent> <groupId>com.demo</groupId> <artifactId>springboot-multi-module</artifactId> <version>1.0.0</version> </parent> <artifactId>module-web</artifactId> <dependencies> <dependency> <groupId>com.demo</groupId> <artifactId>module-service</artifactId> <version>1.0.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>application.yml
gospring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/demo?useSSL=false username: root password: root mybatis-plus: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.demo.pojo启动类
go@SpringBootApplication(scanBasePackages = "com.demo") @MapperScan("com.demo.dao.mapper") public class WebApplication { public static void main(String[] args) { SpringApplication.run(WebApplication.class, args); } }Controller
go@RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping("/{id}") public Result<UserVO> getUser(@PathVariable Long id) { return Result.success(userService.getUserById(id)); } }
五、模块依赖关系
goweb → service service → dao dao → pojo, common 所有模块 → common禁止:
-
• web 直接调用 dao
-
• dao 调用 service
-
• pojo 依赖任何业务模块
-
• 循环依赖 A↔B
六、分层设计原则
-
- Controller 只做三件事
-
• 接收参数
-
• 调用 service
-
• 返回统一结果
-
-
- Service 是业务核心
-
-
• 事务控制
-
• 业务判断
-
• 多表操作
-
• 缓存逻辑
-
-
- Dao 只做数据读写
-
-
• 不写业务
-
• 不做判断
-
• 只提供数据能力
-
-
- Pojo 无任何逻辑
-
- • 只有属性、get/set
七、项目打包与运行
go# 父工程执行 mvn clean package -DskipTests-
• 可执行 jar 仅出现在
module-web/target -
• 运行:
gojava -jar module-web-1.0.0.jar
八、注意事项
-
- Mapper 找不到 / Invalid bound statement
-
• dao 模块未配置 resource 打包 xml
-
• @MapperScan 路径错误
-
- 启动类无法扫描其他模块
-
- • 添加 scanBasePackages = "com.demo"
-
- 依赖冲突
-
- • 父工程使用 dependencyManagement 统一管控
-
- 循环依赖
-
-
• 抽取公共部分到 common
-
• 重新设计分层
-
-
- 配置文件不生效
-
- • 配置文件必须放在 web 模块 resources
九、总结
SpringBoot 多模块 + MVC 三层架构(web/service/dao)是企业后端最标准、最通用、最稳健的工程结构。
它的核心价值是:职责清晰、分层解耦、易于维护、易于扩展、便于团队协作 。
只要按照这套结构搭建项目,你的工程规范度、可维护性、可扩展性都会直接达到企业级标准。
掌握多模块搭建,是你从普通程序员迈向架构思维的关键一步。
你们公司项目是单模块还是多模块?有没有遇到过分层混乱、依赖冲突、启动报错的问题?
欢迎在评论区留言 交流你的经验和踩坑经历!
关注我,持续更新 SpringBoot 企业级实战教程,从工程搭建到微服务、高并发、分布式架构,带你一步步成长为后端大牛!