SpringBoot 多模块项目搭建:service/dao/web分层设计

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

更多文章