Back to blog

Getting Started with Spring Boot: Your First Project

javaspring-bootbackendweb developmentrest-api
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 -version

Option 2: Download from Adoptium

  1. Visit https://adoptium.net/
  2. Select version 21 (LTS) and macOS
  3. Download and run the installer
  4. 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 -version

Option 2: Manual Installation

  1. Visit https://adoptium.net/
  2. Select version 21 (LTS) and Windows
  3. Download the .msi installer
  4. Run installer and follow wizard
  5. Ensure "Set JAVA_HOME variable" is checked
  6. Verify by opening Command Prompt:
java -version

Installation 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_HOME

For RHEL/CentOS/Fedora:

# Install Java 21
sudo dnf install java-21-openjdk-devel -y
 
# Verify installation
java -version

Verifying 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% # Windows

Step 2: Setting Up Development Tools

Install an IDE

While you can use any text editor, an IDE significantly improves productivity:

Best for Spring Boot development

# macOS (using Homebrew)
brew install --cask intellij-idea-ce  # Community Edition (Free)
 
# Windows (using Chocolatey)
choco install intellijidea-community

Or 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 vscode

Required 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 -version

Windows:

choco install maven
mvn -version

Linux:

sudo apt install maven -y
mvn -version

Gradle (Alternative)

# macOS
brew install gradle
 
# Windows
choco install gradle
 
# Linux
sudo apt install gradle -y

Step 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)

  1. Visit https://start.spring.io/

  2. 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
  3. Add Dependencies:

    • Spring Web
    • Spring Boot DevTools
    • Lombok (optional, for reducing boilerplate)
  4. Click "Generate" - Downloads a ZIP file

  5. Extract and open:

unzip demo.zip
cd demo

Method 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 demo

Method 3: Using IntelliJ IDEA

  1. Open IntelliJ IDEA
  2. Click "New Project"
  3. Select "Spring Initializr" from left sidebar
  4. Configure project settings (same as Spring Initializr web)
  5. Select dependencies
  6. Click "Create"

Method 4: Using Maven Archetype (Command Line)

mvn archetype:generate \
  -DgroupId=com.example \
  -DartifactId=demo \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DinteractiveMode=false
 
cd demo

Then 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)
└── .gitignore

Key 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=DEBUG

Step 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:run

Windows:

mvnw.cmd spring-boot:run

Option 2: Using IDE

IntelliJ IDEA:

  1. Open DemoApplication.java
  2. Click the green play button next to main() method
  3. Or press Ctrl+Shift+F10 (Windows/Linux) or Cmd+Shift+R (macOS)

VS Code:

  1. Open DemoApplication.java
  2. Click "Run" above the main() method
  3. 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.jar

Expected 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 seconds

Your 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/1

Using Postman

  1. Download Postman from https://www.postman.com/downloads/
  2. Create a new request
  3. Test endpoints:
    • GET http://localhost:8080/api/books
    • POST http://localhost:8080/api/books with JSON body
    • PUT http://localhost:8080/api/books/1 with JSON body
    • DELETE 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 exceptions

2. 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: DEBUG

7. 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=8081

Issue 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 -U

Next Steps

Now that you have a working Spring Boot application, explore:

  1. Database Integration: Add Spring Data JPA with PostgreSQL/MySQL
  2. Security: Implement authentication with Spring Security
  3. Testing: Write unit and integration tests
  4. Caching: Add Redis for performance
  5. Messaging: Integrate RabbitMQ or Kafka
  6. Deployment: Deploy to AWS, Azure, or Heroku
  7. 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.