Key Takeaways
- Build a minimal Maven project with Spring Boot 4.1.1 and a Java 21 JDK.
- Keep HTTP endpoint code in
WebAppControllerand application startup code inApplication. - Package an executable JAR and verify that
GET /returnsHello 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 --versionBoth 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/exampleThese 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.javaAdd 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-parentsupplies Maven defaults and manages dependency versions, so the managed dependencies don't need individual version declarations.spring-boot-starter-webmvcbrings 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-testsupplies MVC testing support and the general Spring Boot test libraries. spring-boot-maven-pluginprovides 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 packageThis 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.jarThe 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 WorldYou 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:runChoose 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 testThe 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/greetingExpect 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=8081Then 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 --versionand correct the JDK Maven uses, includingJAVA_HOMEwhere applicable. - Dependency download failure: Check repository access and any corporate proxy configuration before changing dependency versions.
- Test import failure: Use the Boot 4
WebMvcTestimport 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
- Spring Boot system requirements — Java and build-tool compatibility.
- Developing your first Spring Boot application — the official Maven quickstart and executable-JAR walkthrough.
- Spring Boot build systems and starters — dependency management and current starter names.
- Using the Spring Boot Maven plugin — parent configuration and repackaging integration.
- Spring MVC request mappings — HTTP methods, paths, and response media types.
- Testing Spring Boot applications — focused MVC tests and MockMvc.
- Building a RESTful web service — returning Java objects as JSON.
- Configuring embedded web servers — ports and server configuration.
