How to Build a SpringBoot Multi‑Module Project with Service/DAO/Web Layered Design
The article explains why a single‑module SpringBoot project becomes problematic as business complexity grows, outlines the benefits of a multi‑module architecture—including clear responsibilities, high cohesion, faster compilation, and smoother microservice migration—and provides a step‑by‑step guide with Maven configuration, module responsibilities, code examples, packaging commands, and common pitfalls.
1. Why use a multi‑module project
In enterprise development a single‑module SpringBoot project quickly becomes problematic when business logic grows, the team expands, or iteration speeds increase. Issues include tangled code, unclear responsibilities, difficult maintenance, slow compilation, and obstacles to later microservice extraction.
SpringBoot multi‑module architecture addresses these problems by providing engineering‑level standardization and layered decoupling.
Single responsibility, high cohesion, low coupling
Controller only handles request reception and response.
Service only contains business logic, transactions, and workflow orchestration.
Dao only interacts with the database.
Each layer depends only on the layer below.
Strong code reuse
Common utilities, constants, and global configuration live in module-common.
Entity classes are placed in module-pojo and shared across the whole project.
Significant build speed improvement
Modifying a single module only rebuilds that module, saving time for large projects.
Facilitates team collaboration
Frontend developers depend only on the web module.
Business developers focus on service.
DBAs work on dao.
Smooth transition to microservices
Each module can later be split into an independent microservice.
2. Standard multi‑module structure
springboot-multi-module
├── pom.xml # Parent project: unified version & dependency management
├── module-common # Common utilities, exceptions, configuration, constants
├── module-pojo # Entity/DTO/VO/BO shared across the project
├── module-dao # Data access layer: mapper, repository, XML
├── module-service # Business logic layer: service interfaces, implementations, transactions
└── module-web # API layer: controllers, interceptors, startup classModule responsibilities
module-common
Global utilities (DateUtil, StringUtil, BeanUtil)
Global exception handling and unified response wrapper
Global configuration (Redis, MyBatis, thread pool)
Constants, enums, common annotations
module-pojo
Entity classes mapping to database tables
DTO for request parameters
VO for response objects
BO for internal business transfer
Query objects for pagination criteria
module-dao
MyBatis mapper interfaces and XML files
Repository abstractions for JPA/ES/MongoDB
Data source configuration
module-service
Service interfaces and implementations
Transaction control
Business validation and multi‑table operations
Cache logic and third‑party API calls
module-web
REST controllers
Global CORS, filters, interceptors
Application entry class
Swagger/Knife4j API documentation
3. Create the parent project (version management)
The parent pom.xml uses packaging = pom and contains only dependency management; no business code.
<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>
<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>4. Create sub‑modules one by one
4.1 module‑pojo (entity module)
All data structures are stored here and do not depend on any business module; only Lombok is required.
<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>Example entity:
@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;
}Example VO:
@Data
public class UserVO {
private Long id;
private String username;
private Integer status;
}4.2 module‑common (common utilities)
Depends on module-pojo and provides global utilities, exception handling, and a unified Result wrapper.
public class Result<T> {
private Integer code;
private String msg;
private T data;
public static <T> Result<T> success(T data) { /* ... */ }
public static <T> Result<T> fail(String msg) { /* ... */ }
}4.3 module‑dao (data access layer)
Depends on module-pojo, module-common, MyBatis‑Plus, and MySQL driver.
public interface UserMapper extends BaseMapper<User> { }4.4 module‑service (business layer)
Depends on module-dao and module-common.
public interface UserService {
UserVO getUserById(Long id);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@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);
}
}4.5 module‑web (API layer)
Depends on module-service and contains the SpringBoot entry class.
@SpringBootApplication(scanBasePackages = "com.demo")
@MapperScan("com.demo.dao.mapper")
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
@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));
}
}5. Module dependency relationships
web → service
service → dao
dao → pojo, common
all modules → common6. Layered design principles
Controller does only three things:
Receive parameters
Call the service layer
Return a unified result
Service is the business core, responsible for transaction control, business decisions, multi‑table operations, and cache logic.
Dao only reads/writes data; it never contains business logic or decisions.
Pojo contains no logic, only fields and getters/setters.
7. Packaging and running
mvn clean package -DskipTestsThe executable JAR is generated in module-web/target.
Run with java -jar module-web-1.0.0.jar.
8. Common pitfalls
Mapper not found / Invalid bound statement
Dao module may miss resource packaging for XML files.
@MapperScan path may be incorrect.
Startup class cannot scan other modules
Add scanBasePackages = "com.demo" to the @SpringBootApplication annotation.
Dependency conflicts
Use the parent project's dependencyManagement to unify versions.
Circular dependencies
Extract shared code into module-common and redesign the layer hierarchy.
Configuration files not effective
Place all configuration files under module-web/src/main/resources.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Tech Workshop
Focused on Java backend technologies, sharing fundamentals, multithreading, JVM, the Spring ecosystem, microservices, distributed systems, high concurrency, source‑code analysis, and practical experience. Continuously delivers high‑quality original content, interview guides, and learning roadmaps to help Java developers progress from beginner to advanced, enhancing technical skills and core competitiveness.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
