Tutorials

Spring Boot Tutorial

Key Takeaways

  • Build a minimal Maven project with Spring Boot 4.1.1 and a Java 21 JDK.
  • Keep HTTP endpoint code in WebAppController and application startup code in Application.
  • Package an executable JAR and verify that GET / returns Hello World.
  • Add an automated controller test and a JSON endpoint without introducing a database.

To create a minimal Spring Boot HTTP endpoint with Maven, add the web starter, write a @RestController, and launch an application class annotated with @SpringBootApplication. This Spring Boot tutorial walks through each file, then shows you how to build, run, and test the application.

The first milestone is deliberately small: return Hello World as plain text. After that works, you'll add a structured JSON response—the more useful starting point for a REST API.

1. Check Your Java and Maven Installation

Install a Java Development Kit (JDK), not just a Java runtime. According to the Spring Boot system requirements, Spring Boot 4.1.1 requires at least Java 17 and Maven 3.6.3. The POM below targets Java 21, so use a Java 21 JDK to follow this tutorial exactly.

Open a terminal and check your tools:

java -version
javac -version
mvn --version

Both Java commands should report version 21 for this setup. Check the Java version reported by Maven too: it can differ from the Java executable your shell finds. If Maven isn't installed, follow the official Maven installation instructions.

2. Create the Spring Boot Maven Project

You can generate a Maven/Java project with the Spring Web dependency through Spring Initializr. It also offers Gradle, but this tutorial uses Maven throughout. To make every file and dependency visible, we'll create the project manually.

In a Bash-compatible terminal, create the project directory and source directories:

mkdir hello-spring-boot
cd hello-spring-boot
mkdir -p src/main/java/com/example
mkdir -p src/test/java/com/example

These commands create directories only; you'll create the files below in your editor. After adding the controller test later, your project will have this structure:

hello-spring-boot/
|-- pom.xml
`-- src/
    |-- main/java/com/example/
    |   |-- Application.java
    |   `-- WebAppController.java
    `-- test/java/com/example/
        `-- WebAppControllerTest.java

Add the Complete pom.xml

Create pom.xml directly inside hello-spring-boot:

<?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>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.1.1</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>hello-spring-boot</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>21</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webmvc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webmvc-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

The important pieces are:

  • spring-boot-starter-parent supplies Maven defaults and manages dependency versions, so the managed dependencies don't need individual version declarations.
  • spring-boot-starter-webmvc brings in Spring MVC, the framework that routes HTTP requests to controller methods, plus embedded Tomcat and Jackson JSON support.
  • The test-scoped spring-boot-starter-webmvc-test supplies MVC testing support and the general Spring Boot test libraries.
  • spring-boot-maven-plugin provides the build integration used to create an executable application JAR.

Older tutorials use spring-boot-starter-web. Spring Boot 4 deprecates that starter in favor of spring-boot-starter-webmvc; the official starter catalog documents the replacement.

3. Add the Hello World Controller

Create src/main/java/com/example/WebAppController.java:

package com.example;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WebAppController {

    @GetMapping(value = "/", produces = MediaType.TEXT_PLAIN_VALUE)
    public String mainPage() {
        return "Hello World";
    }
}

@GetMapping routes HTTP GET requests for / to mainPage(). Its produces attribute declares a plain-text response. See Spring MVC's request-mapping documentation for the available mapping options.

@RestController tells Spring MVC to write the method's return value into the HTTP response body rather than interpret it as a view name. Here, that body is the string Hello World, not JSON. The annotation's name doesn't turn a returned string into a JSON object.

4. Add the Application Entry Point

Create src/main/java/com/example/Application.java, in the same package directory as the controller—not beside pom.xml:

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

SpringApplication.run(Application.class, args) starts the Spring application and, with this web configuration, the embedded server. @SpringBootApplication enables auto-configuration and component scanning, which discovers application components such as controllers.

With Application in com.example, the default component scan covers that package and its child packages. Keep the main application class above your other components in the package hierarchy, as the Spring Boot code-structure guide recommends.

The distinction matters: Application starts the application; WebAppController answers HTTP requests after startup.

5. Build, Run, and Verify the Application

Build and Run the Executable JAR

From the directory containing pom.xml, run:

mvn clean package

This builds the project, runs its tests, and creates the packaged application. With the parent and plugin configured above, the parent's inherited repackage execution makes the JAR executable and includes its runtime dependencies. The Maven plugin documentation explains that integration.

After a successful build, start the application:

java -jar target/hello-spring-boot-1.0.0.jar

The filename comes from the project's artifact ID and version. Leave this terminal running and wait for the startup log to confirm that the application has started. The default HTTP port is 8080; you don't need a separate Tomcat installation.

Check the Endpoint with curl

In another terminal, send a request:

curl -i http://localhost:8080/

The curl -i option includes response headers alongside the body. Relevant parts of the expected response are shown below; other headers are omitted:

HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8

Hello World

You can also open http://localhost:8080/ in a browser. Stop the application with Ctrl+C when you're finished.

Run Directly Through Maven During Development

As an alternative to launching the packaged JAR, use:

mvn spring-boot:run

Choose one launch method at a time. Starting both application instances on the same port will cause a conflict.

6. Test the Spring MVC Endpoint

A browser check is useful, but a repeatable assertion is better. Create src/test/java/com/example/WebAppControllerTest.java:

package com.example;

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(WebAppController.class)
class WebAppControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void rootReturnsHelloWorld() throws Exception {
        mockMvc.perform(get("/"))
                .andExpect(status().isOk())
                .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_PLAIN))
                .andExpect(content().string("Hello World"));
    }
}

@WebMvcTest(WebAppController.class) loads a focused MVC test configuration and auto-configures MockMvc. It exercises request mapping and response handling without starting a listening HTTP server. Spring Boot's MVC testing documentation covers this test setup.

Run the test from the project root:

mvn test

The assertions check HTTP status 200, a content type compatible with text/plain, and the exact response body. Subsequent mvn clean package builds will run this test too.

7. Return JSON Instead of Plain Text

Keep the original endpoint as your first-run check. To add a structured response, create src/main/java/com/example/GreetingController.java:

package com.example;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

    @GetMapping(value = "/greeting", produces = MediaType.APPLICATION_JSON_VALUE)
    public Greeting greeting() {
        return new Greeting("Hello World");
    }

    public record Greeting(String message) {
    }
}

This method returns a Java record rather than a string. With the web starter's Jackson support, Spring converts that object into JSON. You don't need to concatenate JSON strings or serialize the object yourself; Spring's RESTful web service guide demonstrates the same object-to-JSON approach.

Stop the running application, rebuild with mvn clean package, and restart the JAR. Then request the new endpoint:

curl -i http://localhost:8080/greeting

Expect HTTP status 200, a content type of application/json, and this body:

{"message":"Hello World"}

To add more endpoints, create additional mapped methods in a discovered controller: use @GetMapping for GET requests and @PostMapping for POST requests. Choose the response format deliberately rather than assuming every controller response is JSON.

Choose a Concrete Next Step

For an API, continue with the Spring Data JPA tutorial to add persistence, then work through a Spring Data JPA CRUD example. Before handling private data, review the Spring Security authentication example; this quickstart doesn't configure authentication.

If your goal is server-rendered HTML instead, Thymeleaf is a template engine for that separate use case. It isn't required to return JSON from this API.

Common Mistakes

Port 8080 Is Already in Use

Another application—or an earlier instance of this one—may already be using port 8080. Stop the conflicting process, or launch the packaged application on another port:

java -jar target/hello-spring-boot-1.0.0.jar --server.port=8081

Then request http://localhost:8081/. Spring Boot's embedded-server guide documents the default port and the server.port setting.

The Maven Build Fails

  • Wrong directory: Run Maven commands from the directory containing pom.xml.
  • Wrong JDK: If compilation reports that Java release 21 isn't supported, check mvn --version and correct the JDK Maven uses, including JAVA_HOME where applicable.
  • Dependency download failure: Check repository access and any corporate proxy configuration before changing dependency versions.
  • Test import failure: Use the Boot 4 WebMvcTest import shown above and include the MVC test starter. Don't copy the Boot 3 test package into this project.

The Endpoint Returns 404 or Old Content

Check the requested path and ensure the controller is in com.example or a child package. If you're running a JAR, editing source files doesn't update that running artifact: rebuild and restart it after changes.

FAQ

How do I create a Spring Boot project with Maven?

Generate a Maven/Java project with Spring Web in Spring Initializr, or create the pom.xml and source files shown in this tutorial. Keep the application class in the root package so component scanning can discover your controllers.

Which Java version does Spring Boot require?

Spring Boot 4.1.1 has a minimum requirement of Java 17; this tutorial's POM targets Java 21. Use a Java 21 JDK for these examples, and check the system requirements for any different Spring Boot release you select.

How do I run a Spring Boot application with Maven?

From the directory containing pom.xml, run mvn spring-boot:run. Alternatively, build with mvn clean package and launch this tutorial's executable JAR with java -jar target/hello-spring-boot-1.0.0.jar.

How can I test a Spring Boot endpoint with curl?

Run curl -i http://localhost:8080/ while the application is running. This tutorial's root endpoint returns HTTP status 200, a text/plain response, and the body Hello World; after adding the JSON controller, /greeting returns application/json.

Why does my Spring Boot application fail to start on port 8080?

Another process may already be using port 8080. Stop the conflicting process or pass --server.port=8081 when launching the JAR, then send requests to localhost:8081 instead.

Further Reading

Written by Sam Erickson

Software engineer. I write every article on StackChief myself. Author of Mastering the Tech Interview. More about me