Chapter 2: Structure of a Spring Boot Project
Introduction
A Spring Boot project follows a standardized structure based on Maven conventions. This organization facilitates code navigation and allows developers to quickly find the necessary files.
Chapter Objectives
By the end of this chapter, you will be able to:
- Understand the directory organization of a Spring Boot project
- Identify the role of each important file
- Organize your code according to best practices
- Navigate efficiently in a Spring Boot project
Overview of the Structure
Complete Tree
greeting-app/
├── .mvn/ # Maven Wrapper
│ └── wrapper/
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── src/
│ ├── main/
│ │ ├── java/ # Java source code
│ │ │ └── com/example/greeting/
│ │ │ └── GreetingApplication.java
│ │ └── resources/ # Application resources
│ │ ├── static/ # Static files (CSS, JS, images)
│ │ ├── templates/ # Templates (Thymeleaf, Freemarker)
│ │ ├── application.properties # Main configuration
│ │ └── application.yml # YAML configuration (alternative)
│ └── test/
│ ├── java/ # Unit and integration tests
│ │ └── com/example/greeting/
│ │ └── GreetingApplicationTests.java
│ └── resources/ # Test resources
│ └── application-test.properties
├── target/ # Compiled files (generated)
├── .gitignore # Files to ignore by Git
├── mvnw # Maven wrapper (Unix/macOS)
├── mvnw.cmd # Maven wrapper (Windows)
├── pom.xml # Maven configuration
├── HELP.md # Generated documentation
└── README.md # Project documentation
Root Directory
1. pom.xml File
Role: Maven configuration file (Project Object Model)
Main Content:
<?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 Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<!-- Project Identifiers -->
<groupId>com.example</groupId>
<artifactId>greeting</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>greeting</name>
<description>Greeting application</description>
<!-- Properties -->
<properties>
<java.version>17</java.version>
</properties>
<!-- Dependencies -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Build Plugin -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Important Sections:
| Section | Description |
|---|---|
<parent> | Inherits Spring Boot configuration |
<groupId>, <artifactId>, <version> | Maven project coordinates |
<properties> | Global configuration (Java version, encoding, etc.) |
<dependencies> | List of project dependencies |
<build> | Build process configuration |
2. Maven Wrapper (mvnw, mvnw.cmd)
Role: Allows running Maven without installing it globally
Advantages:
- Guaranteed Maven version for all developers
- No need to install Maven manually
- Scripts included in the project
Usage:
Linux/macOS:
./mvnw clean install
./mvnw spring-boot:run
Windows:
mvnw.cmd clean install
mvnw.cmd spring-boot:run
3. .gitignore File
Role: List of files not to be versioned with Git
Typical Content:
# Compiled files
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
# IDE
.idea/
*.iml
.vscode/
.classpath
.project
.settings/
# System
.DS_Store
Thumbs.db
# Logs
*.log
# Temporary files
*.tmp
*.bak
src/main/java Directory
Package Structure
Convention: Organize code in functional layers
src/main/java/com/example/greeting/
├── GreetingApplication.java # Main class
├── controller/ # REST/MVC controllers
│ ├── GreetingController.java
│ └── UserController.java
├── service/ # Business logic
│ ├── GreetingService.java
│ └── UserService.java
├── repository/ # Data access
│ ├── UserRepository.java
│ └── ProductRepository.java
├── model/ # Entities and DTOs
│ ├── entity/
│ │ ├── User.java
│ │ └── Product.java
│ └── dto/
│ ├── UserDTO.java
│ └── ProductDTO.java
├── config/ # Spring configuration
│ ├── SecurityConfig.java
│ └── DatabaseConfig.java
├── exception/ # Error handling
│ ├── ResourceNotFoundException.java
│ └── GlobalExceptionHandler.java
└── util/ # Utility classes
└── DateUtil.java
Layered Architecture
Responsibilities of each layer:
| Layer | Role | Annotations |
|---|---|---|
| Controller | Handles HTTP requests | @RestController, @Controller |
| Service | Business logic | @Service |
| Repository | Data access | @Repository, JPA interface |
| Model | Data representation | @Entity, POJO |
Main Class: GreetingApplication.java
Content:
package com.example.greeting;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GreetingApplication {
public static void main(String[] args) {
SpringApplication.run(GreetingApplication.class, args);
}
}
@SpringBootApplication Annotation:
This annotation is a shortcut that combines three annotations:
@SpringBootApplication
=
@SpringBootConfiguration // Spring configuration
+ @EnableAutoConfiguration // Auto-configuration
+ @ComponentScan // Component scanning
Role of each annotation:
src/main/resources Directory
Overview
src/main/resources/
├── static/ # Static files
│ ├── css/
│ │ └── style.css
│ ├── js/
│ │ └── script.js
│ └── images/
│ └── logo.png
├── templates/ # Templates (Thymeleaf)
│ ├── index.html
│ └── user.html
├── application.properties # Main configuration
├── application-dev.properties # Development configuration
├── application-prod.properties # Production configuration
├── application.yml # YAML configuration (alternative)
├── banner.txt # Custom startup banner
└── data.sql # Initialization SQL script
1. static/ Directory
Role: Contains static files served directly
File types:
- CSS (stylesheets)
- JavaScript (client-side scripts)
- Images (PNG, JPG, SVG)
- Fonts (custom fonts)
Access:
http://localhost:8080/css/style.css
http://localhost:8080/js/script.js
http://localhost:8080/images/logo.png
Recommended structure:
static/
├── css/
├── js/
├── images/
├── fonts/
└── favicon.ico
2. templates/ Directory
Role: Contains view templates (if using a template engine)
Supported template engines:
- Thymeleaf (recommended)
- Freemarker
- Mustache
- Groovy Templates
Thymeleaf example:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Greeting</title>
</head>
<body>
<h1 th:text="${message}">Default message</h1>
</body>
</html>
3. application.properties File
Role: Main application configuration
Format: key=value
Configuration examples:
# Server port
server.port=8080
# Application name
spring.application.name=greeting-app
# Database configuration
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=postgres
spring.datasource.password=secret
# JPA/Hibernate
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
# Logs
logging.level.root=INFO
logging.level.com.example=DEBUG
# Date format
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=America/Montreal
4. application.yml File (Alternative)
Role: Same as application.properties but in YAML format
Format: Hierarchical with indentation
Equivalent example:
server:
port: 8080
spring:
application:
name: greeting-app
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: postgres
password: secret
jpa:
hibernate:
ddl-auto: update
show-sql: true
logging:
level:
root: INFO
com.example: DEBUG
Comparison:
| Format | Advantages | Disadvantages |
|---|---|---|
| properties | Simple, familiar | Repetitive for complex structures |
| yml | Readable, hierarchical | Sensitive to indentation |
5. Configuration Profiles
Concept: Different configurations depending on the environment
Profile files:
application.properties # Default configuration
application-dev.properties # Development
application-test.properties # Tests
application-prod.properties # Production
Activating a profile:
Via application.properties:
spring.profiles.active=dev
Via command line:
java -jar app.jar --spring.profiles.active=prod
Via environment variable:
export SPRING_PROFILES_ACTIVE=prod
Environment-specific configuration example:
application-dev.properties:
server.port=8080
spring.datasource.url=jdbc:h2:mem:testdb
logging.level.root=DEBUG
application-prod.properties:
server.port=80
spring.datasource.url=jdbc:postgresql://prod-server:5432/mydb
logging.level.root=WARN
src/test/java Directory
Test Structure
src/test/java/com/example/greeting/
├── GreetingApplicationTests.java # Startup test
├── controller/
│ └── GreetingControllerTest.java # Controller tests
├── service/
│ └── GreetingServiceTest.java # Service tests
└── repository/
└── UserRepositoryTest.java # Repository tests
Default Startup Test
package com.example.greeting;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class GreetingApplicationTests {
@Test
void contextLoads() {
// Checks that the Spring context loads correctly
}
}
Role: Verify that the application starts without error
target/ Directory
Role: Contains compiled files and the final JAR
Generated by: Maven during the build
Content:
target/
├── classes/ # Compiled classes (.class)
├── test-classes/ # Compiled tests
├── generated-sources/ # Generated sources
├── maven-status/ # Maven status
└── greeting-0.0.1-SNAPSHOT.jar # Final executable JAR
Important: This directory is ignored by Git (in .gitignore)
Cleaning:
mvn clean
Organization by Feature vs by Layer
Approach 1: By Layer (Recommended for small projects)
com.example.greeting/
├── controller/
│ ├── UserController.java
│ └── ProductController.java
├── service/
│ ├── UserService.java
│ └── ProductService.java
├── repository/
│ ├── UserRepository.java
│ └── ProductRepository.java
└── model/
├── User.java
└── Product.java
Advantages:
- Simple and clear
- Easy to understand for beginners
- Standard Spring Boot
Disadvantages:
- Difficult to scale for large projects
- Coupling between features
Approach 2: By Feature (Recommended for large projects)
com.example.greeting/
├── user/
│ ├── UserController.java
│ ├── UserService.java
│ ├── UserRepository.java
│ └── User.java
├── product/
│ ├── ProductController.java
│ ├── ProductService.java
│ ├── ProductRepository.java
│ └── Product.java
└── order/
├── OrderController.java
├── OrderService.java
├── OrderRepository.java
└── Order.java
Advantages:
- High cohesion
- Low coupling
- Facilitates transition to microservices architecture
Disadvantages:
- Less standard
- Can be confusing at first
Naming Conventions
Packages
Convention: All lowercase, words separated by dots
com.example.greeting // ✅ Good
com.example.greeting.service // ✅ Good
com.Example.Greeting // ❌ Bad (uppercase)
com.example.greeting_service // ❌ Bad (underscore)
Classes
Convention: PascalCase (first letter of each word capitalized)
UserController // ✅ Good
GreetingService // ✅ Good
userController // ❌ Bad (starts with lowercase)
user_controller // ❌ Bad (underscore)
Recommended suffixes:
| Type | Suffix | Example |
|---|---|---|
| Controller | Controller | UserController |
| Service | Service | UserService |
| Repository | Repository | UserRepository |
| Entity | None | User, Product |
| DTO | DTO | UserDTO, CreateUserDTO |
| Exception | Exception | ResourceNotFoundException |
| Configuration | Config | SecurityConfig |
Methods
Convention: camelCase (first letter lowercase)
getUserById() // ✅ Good
findAllUsers() // ✅ Good
GetUserById() // ❌ Bad (starts with uppercase)
get_user_by_id() // ❌ Bad (underscore)
Variables and Attributes
Convention: camelCase
String userName; // ✅ Good
int userId; // ✅ Good
String UserName; // ❌ Bad (starts with uppercase)
String user_name; // ❌ Bad (underscore)
Constants
Convention: SCREAMING_SNAKE_CASE (all uppercase, underscores)
public static final int MAX_USERS = 100; // ✅ Good
public static final String API_BASE_URL = "/api/v1"; // ✅ Good
public static final int maxUsers = 100; // ❌ Bad (camelCase)
Practical Exercises
Exercise 1: Explore the Structure
Objective: Familiarize yourself with the structure of a project
Instructions:
- Create a project with Spring Initializr (Spring Web only)
- Import it into VS Code
- Identify:
- The pom.xml file
- The main class
- The application.properties file
- The test directory
- Draw the tree structure on paper
Exercise 2: Create a Package Structure
Objective: Organize code into layers
Instructions:
- In the previous project, create the structure:
com.example.demo/
├── controller/
├── service/
├── repository/
└── model/ - Create empty classes in each package
- Check the compilation
Exercise 3: Configure Profiles
Objective: Create environment-specific configurations
Instructions:
- Create
application-dev.properties:server.port=8080
logging.level.root=DEBUG - Create
application-prod.properties:server.port=80
logging.level.root=WARN - Test activating each profile
Review Questions
-
Which file contains the Maven dependencies?
-
What is the purpose of the
target/directory? -
What is the difference between
static/andtemplates/? -
What does the
@SpringBootApplicationannotation contain? -
How do you name a configuration file for the development environment?
-
What is the naming convention for controller classes?
-
Where do you place CSS and JavaScript files?
-
What is the difference between
application.propertiesandapplication.yml?
Chapter Summary
Key Points
- Spring Boot structure follows Maven conventions
- Source code is in
src/main/java - Resources are in
src/main/resources - Layered organization: Controller → Service → Repository
- Tests are in
src/test/java - Configuration files use profiles
Best Practices
- Follow Java naming conventions
- Organize code into logical packages
- Separate configurations by environment
- Use descriptive suffixes for classes
- Comment complex code
- Maintain a clear and consistent structure
Next Steps
In the next chapter, we will delve into:
Chapter 3: Configuration with application.properties
- Available Spring Boot properties
- Database configuration
- Log configuration
- Custom properties