2. Build Your First Spring Boot Web Application
Goal
Create a simple web application with a static landing page and a dynamic “Hello World” page using Spring MVC and Thymeleaf templates.
What you’ll learn:
- How to serve static content with Spring Boot
- When to use server-side rendering with Thymeleaf
- Best practices for the Model-View-Controller pattern
Prerequisites
Before starting, ensure you have:
- ✓ Completed the “Set Up Your Local Spring Boot Development Environment” tutorial
- ✓ Spring Boot project running successfully
- ✓ Basic understanding of HTML
Exercise Steps
Overview
- Create Static Landing Page
- Add Thymeleaf Dependency
- Create Hello Controller
- Create Hello Template
- Test Your Application
Step 1: Create Static Landing Page
Build a simple landing page with Bootstrap styling as the entry point to your application. Spring Boot automatically serves static content from the static directory, making it easy to add HTML, CSS, JavaScript, and images without any configuration.
Navigate to the
src/main/resources/staticdirectoryCreate a new file named
index.htmlAdd the following HTML code:
src/main/resources/static/index.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>HelloJava - Home</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <div class="row min-vh-100 align-items-center"> <div class="col-lg-8 mx-auto text-center"> <h1 class="display-1 fw-bold mb-4">Welcome to HelloJava</h1> <p class="lead mb-4"> A simple Spring Boot web application demonstrating static and dynamic content. </p> <a href="/hello" class="btn btn-primary btn-lg">Hello</a> </div> </div> </div> </body> </html>
ℹ Concept Deep Dive
Spring Boot automatically serves static resources from
src/main/resources/staticat the root path (/). This meansindex.htmlbecomes your default homepage athttp://localhost:8080/. Static content is served directly by the embedded Tomcat server without involving Spring MVC controllers, making it very fast. This approach is perfect for landing pages, CSS files, JavaScript, and images that don’t require server-side processing.⚠ Common Mistakes
- Placing
index.htmlin the wrong directory (liketemplates/) prevents it from being served- Using
src/main/webappinstead ofsrc/main/resources/staticwon’t work with Spring Boot’s embedded server- Not including the viewport meta tag makes the page look poor on mobile devices
✓ Quick check: File created at
src/main/resources/static/index.htmlwith proper HTML structure
Step 2: Add Thymeleaf Dependency
Add the Thymeleaf template engine to enable server-side HTML rendering with dynamic content. Thymeleaf integrates seamlessly with Spring Boot and allows you to create dynamic web pages using natural HTML templates.
Open the
pom.xmlfile in your project rootLocate the
<dependencies>section (around line 32)Add the Thymeleaf starter dependency after the existing
spring-boot-starter-webdependency:pom.xml<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Add this dependency --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>Save the file and let Maven download the dependency
ℹ Concept Deep Dive
Thymeleaf is a server-side template engine that processes HTML templates on the server before sending them to the browser. Unlike static HTML, Thymeleaf templates can include dynamic data from your Java code using special attributes (like
th:text). Spring Boot auto-configures Thymeleaf when it detects the dependency, setting up default locations (src/main/resources/templates/) and file extensions (.html). This zero-configuration approach is a key benefit of Spring Boot’s convention-over-configuration philosophy.⚠ Common Mistakes
- Forgetting to save
pom.xmlmeans Maven won’t download the dependency- Typos in the artifactId will cause “artifact not found” errors
- If your IDE doesn’t auto-import, you may need to manually refresh Maven dependencies
✓ Quick check: Maven successfully downloads the dependency (check for errors in the Maven output or IDE)
Step 3: Create Hello Controller
Build a Spring MVC controller to handle requests to the /hello endpoint and pass data to the view. Controllers are the entry point for HTTP requests in Spring MVC, acting as the “C” in the Model-View-Controller pattern.
Navigate to
src/main/java/com/jin/hellojavaCreate a new directory named
controllerCreate a new file named
HelloController.javainside thecontrollerdirectoryAdd the following code:
src/main/java/com/jin/hellojava/controller/HelloController.javapackage com.jin.hellojava.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class HelloController { @GetMapping("/hello") public String hello(@RequestParam(value = "name", defaultValue = "World") String name, Model model) { // Add the name to the model so it's available in the view model.addAttribute("name", name); // Return the view name (Spring resolves this to templates/hello.html) return "hello"; } }
ℹ Concept Deep Dive
The
@Controllerannotation marks this class as a Spring MVC controller, making it eligible for component scanning and request mapping. The@GetMapping("/hello")annotation maps HTTP GET requests to this method. The@RequestParamannotation extracts thenamequery parameter from the URL (e.g.,/hello?name=Alice) with a default value of “World” if not provided. TheModelobject acts as a container for data passed from the controller to the view. Returning “hello” tells Spring to render thetemplates/hello.htmltemplate.Code Formatting Note: This code follows the K&R style (Kernighan and Ritchie style), which is the standard Java formatting convention. Method parameters are kept on the same line when they fit comfortably (under ~90-120 characters), and the opening curly brace
{stays on the same line as the method signature rather than on a new line. This style is used by the Oracle Java Style Guide, Google Java Style Guide, and Spring Framework Code Style.⚠ Common Mistakes
- Using
@RestControllerinstead of@Controllercauses the method to return the string “hello” as plain text instead of rendering the template- Forgetting
defaultValuemeans the parameter becomes required, causing errors when accessing/hellowithout parameters- Placing the controller outside the
com.jin.hellojavapackage prevents Spring Boot from discovering it- Not adding data to the Model means the view won’t have access to it
✓ Quick check: No compilation errors and IntelliSense recognizes Spring annotations
Step 4: Create Hello Template
Create a Thymeleaf template to display the dynamic greeting message. Templates combine static HTML structure with dynamic data from your controller, enabling server-side rendering.
Navigate to
src/main/resources/templatesCreate a new file named
hello.htmlAdd the following template code:
src/main/resources/templates/hello.html<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hello - HelloJava</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <div class="row"> <div class="col-lg-8 mx-auto text-center"> <h1 class="display-4 mb-4" th:text="|Hello, ${name}!|">Hello, World!</h1> <p class="lead mb-4"> This message is dynamically generated using Spring MVC and Thymeleaf. </p> <a href="/" class="btn btn-secondary">Back to Home</a> </div> </div> </div> </body> </html>
ℹ Concept Deep Dive
The
xmlns:th="http://www.thymeleaf.org"namespace declaration enables Thymeleaf attributes in your HTML. Theth:textattribute replaces the element’s text content with the dynamic value. The pipe syntax|Hello, ${name}!|is Thymeleaf’s literal substitution, combining static text with variable values. The${name}expression accesses the “name” attribute from the Model. The content “Hello, World!” inside the tag is shown only when viewing the template directly (not processed by Thymeleaf), making it a natural template that designers can preview.⚠ Common Mistakes
- Forgetting the Thymeleaf namespace declaration causes
th:attributes to be ignored- Using
templatesdirectory without the.htmlextension prevents Spring from finding the template- Misspelling the Model attribute name (e.g.,
${Name}instead of${name}) shows empty or error text- Placing template in
static/instead oftemplates/causes it to be served as static HTML✓ Quick check: File created at
src/main/resources/templates/hello.htmlwith valid HTML and Thymeleaf syntax
Step 5: Test Your Application
Verify that both the static landing page and dynamic hello page work correctly. Testing ensures all components are properly connected and functioning as expected.
Run the application using Maven wrapper:
./mvnw spring-boot:runOn Windows, use:
mvnw.cmd spring-boot:runWait for the application to start. Look for the “Started HelloJavaApplication” message
Test the landing page:
- Open your browser and navigate to:
http://localhost:8080/ - Verify the Bootstrap hero section displays correctly
- Confirm the “Hello” button is visible
- Open your browser and navigate to:
Test the Hello button:
- Click the “Hello” button on the landing page
- Verify you’re redirected to
/hello - Confirm the page displays “Hello, World!”
Test with query parameters:
- Navigate to:
http://localhost:8080/hello?name=Alice - Verify the page displays “Hello, Alice!”
- Try different names:
http://localhost:8080/hello?name=Spring - Confirm each shows the correct personalized greeting
- Navigate to:
Test navigation:
- Click “Back to Home” on the hello page
- Verify you return to the landing page
- Confirm the navigation flow works both directions
✓ Success indicators:
- Landing page loads at
http://localhost:8080/with proper Bootstrap styling- “Hello” button navigates to
/helloendpoint- Default greeting shows “Hello, World!” at
/hello- Custom name parameter displays correctly (e.g., “Hello, Alice!” at
/hello?name=Alice)- Navigation between pages works smoothly
- No errors in browser console or application logs
✓ Final verification checklist:
- ☐
index.htmlexists insrc/main/resources/static/- ☐ Thymeleaf dependency added to
pom.xml- ☐
HelloController.javaexists incontrollerpackage- ☐
hello.htmltemplate exists insrc/main/resources/templates/- ☐ Application runs without errors
- ☐ Static landing page displays correctly
- ☐ Dynamic hello page shows personalized greeting
- ☐ Query parameters work as expected
Common Issues
If you encounter problems:
“Whitelabel Error Page” at /hello: Controller not found - verify
HelloController.javais in thecom.jin.hellojava.controllerpackage and has@ControllerannotationTemplate not found error: Check that
hello.htmlis insrc/main/resources/templates/(notstatic/) and Thymeleaf dependency is inpom.xml“Hello, World!” doesn’t change with name parameter: Verify
th:textattribute syntax is correct and uses${name}to reference the Model attribute404 error on landing page: Confirm
index.htmlis insrc/main/resources/static/directoryBootstrap styles not loading: Check internet connection (CDN link requires network access) or download Bootstrap locally
Still stuck? Check the console logs for specific error messages and stack traces
Summary
You’ve successfully created a Spring Boot web application with both static and dynamic content:
- ✓ Static landing page served from the
staticdirectory - ✓ Dynamic hello page using Spring MVC and Thymeleaf
- ✓ Query parameter handling with default values
Key takeaway: Spring Boot makes it simple to serve both static content (for performance) and dynamic content (for personalization) in the same application. Static resources are served directly, while controllers and templates enable server-side rendering of dynamic pages. This pattern is fundamental to traditional web applications and provides excellent SEO and initial page load performance.
Going Deeper (Optional)
Want to explore more?
- Try adding CSS styling in
static/css/style.cssand linking it in your templates- Add multiple request parameters (e.g.,
?name=Alice&greeting=Welcome)- Create additional controller methods for different pages
- Explore Thymeleaf’s conditional rendering with
th:if- Add a form that submits data to a controller method
Done! 🎉
Excellent work! You’ve learned the basics of Spring MVC, server-side rendering with Thymeleaf, and how Spring Boot serves static content. You can now build web applications that combine static pages for performance with dynamic pages for personalized content.