Getting Started with Spring Boot: Your First Project

Introduction
Spring Boot is one of the most popular frameworks for building enterprise-grade Java applications. It simplifies the development of production-ready applications with minimal configuration, making it an excellent choice for microservices, REST APIs, and web applications.
In this comprehensive guide, we'll cover:
- Installing Java Development Kit (JDK)
- Setting up development tools
- Creating your first Spring Boot project
- Understanding project structure
- Building a simple REST API
- Running and testing your application
- Best practices for Spring Boot development
Prerequisites
Before we begin, you'll need:
- A computer running Windows, macOS, or Linux
- Basic understanding of Java programming (see our Java Learning Roadmap)
- Command line familiarity
- A text editor or IDE
Recommended Java knowledge: Complete at least Phase 1: Java Fundamentals and Phase 2: Object-Oriented Programming before starting with Spring Boot. Phase 3: Core Java APIs covers collections, streams, and exception handling that you'll use frequently in Spring Boot projects.
Step 1: Installing Java (JDK)
Spring Boot requires Java Development Kit (JDK) version 17 or higher. Let's install it for your operating system.
Choosing the Right JDK
There are several JDK distributions available:
- Eclipse Temurin (formerly AdoptOpenJDK) - Recommended for most users
- Oracle JDK - Official Oracle distribution
- Amazon Corretto - AWS-optimized distribution
- Microsoft Build of OpenJDK - Optimized for Azure
Recommendation: We'll use Eclipse Temurin as it's free, open-source, and widely supported.
Installation on macOS
Option 1: Using Homebrew (Recommended)
# Install Homebrew if you haven't already
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install Java 21 (LTS)
brew install openjdk@21
# Add to PATH
echo 'export PATH="/opt/homebrew/opt/openjdk@21/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
# Verify installation
java -versionOption 2: Download from Adoptium
- Visit https://adoptium.net/
- Select version 21 (LTS) and macOS
- Download and run the installer
- Follow the installation wizard
Installation on Windows
Option 1: Using Chocolatey (Recommended)
# Install Chocolatey (run PowerShell as Administrator)
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Install Java 21
choco install temurin21
# Verify installation
java -versionOption 2: Manual Installation
- Visit https://adoptium.net/
- Select version 21 (LTS) and Windows
- Download the
.msiinstaller - Run installer and follow wizard
- Ensure "Set JAVA_HOME variable" is checked
- Verify by opening Command Prompt:
java -versionInstallation on Linux (Ubuntu/Debian)
# Update package index
sudo apt update
# Install Java 21
sudo apt install openjdk-21-jdk -y
# Verify installation
java -version
# Check JAVA_HOME (should be set automatically)
echo $JAVA_HOMEFor RHEL/CentOS/Fedora:
# Install Java 21
sudo dnf install java-21-openjdk-devel -y
# Verify installation
java -versionVerifying Java Installation
After installation, verify Java is correctly installed:
# Check Java version
java -version
# Expected output (version numbers may vary):
# openjdk version "21.0.1" 2023-10-17 LTS
# OpenJDK Runtime Environment Temurin-21.0.1+12 (build 21.0.1+12-LTS)
# OpenJDK 64-Bit Server VM Temurin-21.0.1+12 (build 21.0.1+12-LTS, mixed mode)
# Check Java compiler
javac -version
# Check JAVA_HOME
echo $JAVA_HOME # macOS/Linux
echo %JAVA_HOME% # WindowsStep 2: Setting Up Development Tools
Install an IDE
While you can use any text editor, an IDE significantly improves productivity:
IntelliJ IDEA (Recommended)
Best for Spring Boot development
# macOS (using Homebrew)
brew install --cask intellij-idea-ce # Community Edition (Free)
# Windows (using Chocolatey)
choco install intellijidea-communityOr download from https://www.jetbrains.com/idea/download/
Features:
- Excellent Spring Boot support
- Smart code completion
- Built-in Maven/Gradle support
- Integrated debugger
- Git integration
Visual Studio Code
Lightweight alternative
# macOS
brew install --cask visual-studio-code
# Windows
choco install vscodeRequired Extensions:
- Extension Pack for Java
- Spring Boot Extension Pack
- Spring Initializr Java Support
Eclipse IDE
Traditional Java IDE
Download from https://www.eclipse.org/downloads/
Choose "Eclipse IDE for Enterprise Java and Web Developers"
Install Maven or Gradle
Spring Boot projects use build tools for dependency management:
Maven (We'll use this)
macOS:
brew install maven
mvn -versionWindows:
choco install maven
mvn -versionLinux:
sudo apt install maven -y
mvn -versionGradle (Alternative)
# macOS
brew install gradle
# Windows
choco install gradle
# Linux
sudo apt install gradle -yStep 3: Creating Your First Spring Boot Project
There are multiple ways to create a Spring Boot project. Let's explore the most popular methods.
Method 1: Using Spring Initializr (Web-based)
-
Visit https://start.spring.io/
-
Configure your project:
- Project: Maven
- Language: Java
- Spring Boot: 3.2.2 (or latest stable)
- Group: com.example
- Artifact: demo
- Name: demo
- Package name: com.example.demo
- Packaging: Jar
- Java: 21
-
Add Dependencies:
- Spring Web
- Spring Boot DevTools
- Lombok (optional, for reducing boilerplate)
-
Click "Generate" - Downloads a ZIP file
-
Extract and open:
unzip demo.zip
cd demoMethod 2: Using Spring Boot CLI
# Install Spring Boot CLI (macOS)
brew tap spring-io/tap
brew install spring-boot
# Create project
spring init --dependencies=web,devtools --build=maven --java-version=21 demo
cd demoMethod 3: Using IntelliJ IDEA
- Open IntelliJ IDEA
- Click "New Project"
- Select "Spring Initializr" from left sidebar
- Configure project settings (same as Spring Initializr web)
- Select dependencies
- Click "Create"
Method 4: Using Maven Archetype (Command Line)
mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=demo \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
cd demoThen manually add Spring Boot dependencies to pom.xml.
Step 4: Understanding Project Structure
After creating your project, you'll see this structure:
demo/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── demo/
│ │ │ └── DemoApplication.java
│ │ └── resources/
│ │ ├── application.properties
│ │ ├── static/ # Static files (CSS, JS, images)
│ │ └── templates/ # HTML templates (Thymeleaf)
│ └── test/
│ └── java/
│ └── com/
│ └── example/
│ └── demo/
│ └── DemoApplicationTests.java
├── target/ # Compiled classes (generated)
├── pom.xml # Maven configuration
├── mvnw # Maven wrapper (Unix)
├── mvnw.cmd # Maven wrapper (Windows)
└── .gitignoreKey Files Explained
pom.xml - Maven Configuration
<?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 POM provides dependency management -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.2</version>
<relativePath/>
</parent>
<!-- Project coordinates -->
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<!-- Java version -->
<properties>
<java.version>21</java.version>
</properties>
<!-- Dependencies -->
<dependencies>
<!-- Spring Web (REST APIs, MVC) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- DevTools (auto-reload during development) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Build configuration -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>DemoApplication.java - Main Application Class
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // Combines @Configuration, @EnableAutoConfiguration, @ComponentScan
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}application.properties - Configuration
# Server configuration
server.port=8080
# Application name
spring.application.name=demo
# Logging level
logging.level.root=INFO
logging.level.com.example.demo=DEBUGStep 5: Building Your First REST API
Let's create a simple REST API with CRUD operations.
Create a Model Class
Create src/main/java/com/example/demo/model/Book.java:
package com.example.demo.model;
public class Book {
private Long id;
private String title;
private String author;
private Integer year;
// Constructors
public Book() {}
public Book(Long id, String title, String author, Integer year) {
this.id = id;
this.title = title;
this.author = author;
this.year = year;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Integer getYear() {
return year;
}
public void setYear(Integer year) {
this.year = year;
}
}Using Lombok (Optional): If you added Lombok dependency, you can simplify:
package com.example.demo.model;
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@Data // Generates getters, setters, toString, equals, hashCode
@NoArgsConstructor // No-argument constructor
@AllArgsConstructor // All-arguments constructor
public class Book {
private Long id;
private String title;
private String author;
private Integer year;
}Create a Controller
Create src/main/java/com/example/demo/controller/BookController.java:
package com.example.demo.controller;
import com.example.demo.model.Book;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController // Combines @Controller and @ResponseBody
@RequestMapping("/api/books") // Base URL for all endpoints
public class BookController {
// In-memory storage (replace with database in production)
private List<Book> books = new ArrayList<>();
private Long nextId = 1L;
// Initialize with sample data
public BookController() {
books.add(new Book(nextId++, "Clean Code", "Robert C. Martin", 2008));
books.add(new Book(nextId++, "Effective Java", "Joshua Bloch", 2018));
}
// GET /api/books - Get all books
@GetMapping
public List<Book> getAllBooks() {
return books;
}
// GET /api/books/{id} - Get book by ID
@GetMapping("/{id}")
public ResponseEntity<Book> getBookById(@PathVariable Long id) {
Optional<Book> book = books.stream()
.filter(b -> b.getId().equals(id))
.findFirst();
return book.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// POST /api/books - Create new book
@PostMapping
public ResponseEntity<Book> createBook(@RequestBody Book book) {
book.setId(nextId++);
books.add(book);
return ResponseEntity.status(HttpStatus.CREATED).body(book);
}
// PUT /api/books/{id} - Update book
@PutMapping("/{id}")
public ResponseEntity<Book> updateBook(@PathVariable Long id, @RequestBody Book updatedBook) {
Optional<Book> existingBook = books.stream()
.filter(b -> b.getId().equals(id))
.findFirst();
if (existingBook.isPresent()) {
Book book = existingBook.get();
book.setTitle(updatedBook.getTitle());
book.setAuthor(updatedBook.getAuthor());
book.setYear(updatedBook.getYear());
return ResponseEntity.ok(book);
}
return ResponseEntity.notFound().build();
}
// DELETE /api/books/{id} - Delete book
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteBook(@PathVariable Long id) {
boolean removed = books.removeIf(b -> b.getId().equals(id));
if (removed) {
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
}Add a Welcome Endpoint
Create src/main/java/com/example/demo/controller/HomeController.java:
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class HomeController {
@GetMapping("/")
public Map<String, String> home() {
Map<String, String> response = new HashMap<>();
response.put("message", "Welcome to Spring Boot API!");
response.put("version", "1.0.0");
response.put("docs", "http://localhost:8080/api/books");
return response;
}
}Step 6: Running Your Application
Option 1: Using Maven
# Clean and compile
./mvnw clean compile
# Run application
./mvnw spring-boot:runWindows:
mvnw.cmd spring-boot:runOption 2: Using IDE
IntelliJ IDEA:
- Open
DemoApplication.java - Click the green play button next to
main()method - Or press
Ctrl+Shift+F10(Windows/Linux) orCmd+Shift+R(macOS)
VS Code:
- Open
DemoApplication.java - Click "Run" above the
main()method - Or use "Run and Debug" panel
Option 3: Using JAR File
# Build JAR
./mvnw clean package
# Run JAR
java -jar target/demo-0.0.1-SNAPSHOT.jarExpected Output
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.2.2)
2024-01-24T10:30:00.123 INFO 12345 --- [main] c.e.demo.DemoApplication: Starting DemoApplication
2024-01-24T10:30:01.456 INFO 12345 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer: Tomcat started on port(s): 8080 (http)
2024-01-24T10:30:01.789 INFO 12345 --- [main] c.e.demo.DemoApplication: Started DemoApplication in 2.1 secondsYour application is now running at http://localhost:8080
Step 7: Testing Your API
Using cURL
# Get welcome message
curl http://localhost:8080/
# Get all books
curl http://localhost:8080/api/books
# Get book by ID
curl http://localhost:8080/api/books/1
# Create new book
curl -X POST http://localhost:8080/api/books \
-H "Content-Type: application/json" \
-d '{"title":"Spring in Action","author":"Craig Walls","year":2022}'
# Update book
curl -X PUT http://localhost:8080/api/books/1 \
-H "Content-Type: application/json" \
-d '{"title":"Clean Code (Updated)","author":"Robert C. Martin","year":2008}'
# Delete book
curl -X DELETE http://localhost:8080/api/books/1Using Postman
- Download Postman from https://www.postman.com/downloads/
- Create a new request
- Test endpoints:
GET http://localhost:8080/api/booksPOST http://localhost:8080/api/bookswith JSON bodyPUT http://localhost:8080/api/books/1with JSON bodyDELETE http://localhost:8080/api/books/1
Using Browser
Open your browser and visit:
Best Practices
1. Use Proper Package Structure
com.example.demo/
├── controller/ # REST endpoints
├── service/ # Business logic
├── repository/ # Data access
├── model/ # Domain entities
├── dto/ # Data transfer objects
├── config/ # Configuration classes
└── exception/ # Custom exceptions2. Separate Business Logic
Create a service layer:
package com.example.demo.service;
import com.example.demo.model.Book;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class BookService {
// Business logic here
public List<Book> findAll() { /* ... */ }
public Optional<Book> findById(Long id) { /* ... */ }
public Book save(Book book) { /* ... */ }
public void deleteById(Long id) { /* ... */ }
}3. Use DTOs for API Responses
package com.example.demo.dto;
public class BookDTO {
private Long id;
private String title;
private String author;
// Only fields you want to expose to API
}4. Add Validation
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Min;
public class Book {
@NotBlank(message = "Title is required")
private String title;
@NotBlank(message = "Author is required")
private String author;
@Min(value = 1000, message = "Year must be at least 1000")
private Integer year;
}Add spring-boot-starter-validation to pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>Use @Valid in controller:
@PostMapping
public ResponseEntity<Book> createBook(@Valid @RequestBody Book book) {
// ...
}5. Add Exception Handling
package com.example.demo.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BookNotFoundException.class)
public ResponseEntity<ErrorResponse> handleBookNotFound(BookNotFoundException ex) {
ErrorResponse error = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
ex.getMessage()
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}6. Use application.yml Instead of .properties
Create src/main/resources/application.yml:
server:
port: 8080
spring:
application:
name: demo
logging:
level:
root: INFO
com.example.demo: DEBUG7. Add API Documentation with Swagger
Add dependency to pom.xml:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>Access documentation at: http://localhost:8080/swagger-ui.html
Common Issues and Solutions
Issue 1: Port Already in Use
Error: Port 8080 was already in use
Solution:
# Find process using port 8080 (macOS/Linux)
lsof -i :8080
# Kill process
kill -9 <PID>
# Or change port in application.properties
server.port=8081Issue 2: JAVA_HOME Not Set
Error: JAVA_HOME not found
Solution:
# macOS/Linux - Add to ~/.zshrc or ~/.bashrc
export JAVA_HOME=$(/usr/libexec/java_home -v 21)
# Windows - Set environment variable
setx JAVA_HOME "C:\Program Files\Java\jdk-21"Issue 3: Maven Build Fails
Error: Failed to execute goal
Solution:
# Clear Maven cache
./mvnw dependency:purge-local-repository
# Clean rebuild
./mvnw clean install -UNext Steps
Now that you have a working Spring Boot application, explore:
- Database Integration: Add Spring Data JPA with PostgreSQL/MySQL
- Security: Implement authentication with Spring Security
- Testing: Write unit and integration tests
- Caching: Add Redis for performance
- Messaging: Integrate RabbitMQ or Kafka
- Deployment: Deploy to AWS, Azure, or Heroku
- Microservices: Build distributed systems with Spring Cloud
Conclusion
You've successfully installed Java, set up Spring Boot, and created your first REST API. Spring Boot's convention-over-configuration approach makes it easy to build production-ready applications quickly.
Key takeaways:
- JDK 21 provides the latest Java features
- Spring Initializr simplifies project setup
- Maven manages dependencies efficiently
- @RestController creates REST APIs with minimal code
- DevTools enables fast development with auto-reload
- Proper structure keeps code maintainable
Keep practicing by building more complex applications, and you'll master Spring Boot in no time!
References
📬 Subscribe to Newsletter
Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.
We respect your privacy. Unsubscribe at any time.
💬 Comments
Sign in to leave a comment
We'll never post without your permission.