Study Notes
Spring Boot Frameworkfoundation

Introduction to Spring Boot

Why Spring Boot exists, Spring vs Spring Boot, the core Spring concepts, scaffolding a project with the Spring Initializr (start.spring.io), and writing your first Hello World controller.

30 min read·verified Spring Boot 4.x·reviewed 2026-08-28

After this you should be able to

  • Explain what Spring Boot automates
  • Create a starter application
Spring InitializrAuto-configFirst Controller

Java · Spring Boot

Why the framework that runs most of the Java web exists, what it fixed about the Spring it grew out of, and how you get from an empty folder to a running web endpoint in one afternoon.

Session 3 · JAVA-301 · Updated July 2026 · Read ~14 min


Choose your route#

Problem: a useful Java service should start with a small, runnable shape instead of a day of wiring. This is a lesson: budget 30 minutes to build it deeply or 12 minutes to revise it for interviews.

Learning goal

Recall first: before reading, name the four pieces Boot supplies around a controller. Prerequisite guidance: be comfortable reading an HTTP request; you may still continue now.

  • Explain what Spring Boot automates.
  • Create a starter application.
  • Run and diagnose a first endpoint.

Shared core: a runnable web application#

Boot combines Spring’s container with opinionated dependency management, auto-configuration, and an embedded server. A starter describes a capability; Boot uses the classpath and properties to assemble a sensible default, while leaving the decision reversible.

Do not blur Spring and Spring Boot: Spring is the underlying framework and programming model; Boot is the convention-led layer that chooses common setup so you can begin quickly.

Failure trace: returning "OK" from @Controller looks like a response but is treated as a view name. Use @RestController (or @ResponseBody) when the value is the HTTP body.

Decision rule: start with a Boot starter and the embedded server for a new service; override configuration only when the default conflicts with a real constraint.

Version note: examples are reviewed against Spring Boot 4.x on 2026-08-28. Confirm migration notes before copying API details into a production upgrade.

Learn deeply: make the first request real#

Mission (20 minutes): generate a Spring Web project, add StatusController, and serve GET /status with a plain-text health message. Work in src/main/java and application.properties.

Acceptance checks: ./gradlew bootRun starts once; curl localhost:8080/status returns your message; changing server.port moves the endpoint deliberately.

  1. Start with one @RestController and one @GetMapping.
  2. If startup fails, identify whether it is a port clash or a compilation problem.
  3. Only then add a query parameter with a default value.
Solution shape, not a script

A single controller receives no dependencies yet, returns a value directly, and keeps transport concerns at the edge. Add a service only when behaviour deserves its own seam.

Transfer: change the status endpoint into /greeting?name=... and explain why missing input should have either a default or a 400 response.

Prepare for interviews: Boot in two minutes#

Two-minute summary: Boot is not a replacement for Spring; it packages common Spring choices into starters, auto-configuration, and an executable app with an embedded server.

Explain in 60 seconds: why does Boot reduce setup without removing control?

Primary question: what happens from adding spring-boot-starter-web to serving a controller? Follow-ups: how does auto-configuration back off, and when would you deploy a WAR instead?

Debug exercise: a method returns "UP" but the browser searches for a template called UP. Diagnose the annotation mismatch and state the trade-off between JSON APIs and server-rendered views.

Strong-answer outline

State the problem first, name the three Boot conveniences, show that classpath conditions and properties drive choices, then give one override rather than reciting annotations.

Timed mock: in 90 seconds, sketch a first endpoint and say how you would prove the embedded server is listening.

Exit check#

  1. Which Boot feature selects common configuration from the classpath?
  2. What does a web starter provide beyond one library jar?
  3. Why does @RestController change a String response?
  4. What is the first distinction to make when port 8080 fails?
  5. When is overriding a Boot default justified?

Learn next: Use explain what spring boot automates as the base, then name the main application layers in The Layer Map. Interview next: Use explain what spring boot automates as the base, then explain inversion of control in Spring Core — IoC & Dependency Injection.

Continue this path · Switch paths from this topic · Review first: HTTP request flow

// the big idea

Spring gave Java power but demanded endless setup. Spring Boot is Spring with the setup done for you — it makes opinionated defaults, bundles a web server inside your app, and auto-wires the plumbing, so you write business code on day one instead of XML on day three.

// scope of this note

Built from the Session 3 slide deck. It covers the first half of the agenda in depth: the case for Spring Boot, Spring vs Spring Boot, Spring Initializr, and your first controller. The deck's later sections — Spring Boot architecture (MVC/MVCS), building full REST APIs with DTOs and validation, and testing with Postman — were listed on the agenda but not present in the captured slides, so they are outlined here as a roadmap, not taught in full. [!] Ask again with those slides or the session transcript and this page will absorb them.

Section 1Notebook Summary#

Hand-copyable revision sheet · fully derivable from the detailed notes below

Why Spring Boot exists#

  • Traditional Java pain → XML config + boilerplate + manual server setup + WAR deploy + dependency hell
  • Spring (2003, Rod Johnson + Juergen Hoeller) → solved a lot via IoC + DI; gave data/web layers
  • Catch → Spring itself still needed heavy config, manual servers, framework integration
  • Spring Boot (2014) → Spring + defaults done for you

Spring vs Spring Boot#

  • Spring = framework, fine-grained control, you configure
  • Spring Boot = opinionated layer on Spring, convention over config
    • Auto-configuration → wires beans from the classpath
    • Embedded server → Tomcat/Jetty/Undertow inside the jar (no external server)
    • Starters → one dependency pulls a curated, version-matched set
    • Actuator → production monitoring/health endpoints
  • Aid: Spring = raw ingredients; Boot = meal-kit, pre-measured.

Core Spring concepts#

  • IoC (Inversion of Control) → framework creates & owns objects, not you
  • DI (Dependency Injection) → framework hands an object what it needs
  • Aid: don't new your dependencies — ask and receive.

Spring Initializr — start.spring.io#

  • Web tool → generates project skeleton + build file + deps as a .zip
  • Pick: build (Gradle/Maven) · language · Boot version · group/artifact · deps
  • Flow: configure → Generate → unzip → open in IDE → run
  • Spring Web dep → brings MVC + embedded Tomcat for building web/REST APIs

First controller (Hello World)#

  • @RestController → class returns data straight to the HTTP response body
  • @GetMapping("/path") → maps HTTP GET on that path to a method
  • @RequestParam → pulls ?name=... from the query string into an argument
  • Run → ./gradlew bootRun → hits localhost:8080

Box these#

  • ⭐Never new a dependency in Spring — declare it, let DI inject it. Testability lives here.
  • ⚠@Controller ≠ @RestController. Plain @Controller returns a view name; @RestController returns the body (adds @ResponseBody).
  • ⚠Port 8080 already in use = app won't start. Free the port or set server.port.
  • 💡"Opinionated" = Boot's sane defaults you can still override — it's a starting posture, not a cage.

Doodle · Boot layers: draw 3 stacked boxes — [Your code] on top of [Spring Boot: auto-config + embedded server] on top of [Spring core: IoC/DI]. Arrow up the left: "less config."


Section 2Detailed Study Notes#

Picture your first week on a Java team in 2010. Before you write a single line that does anything a user cares about, you're editing three XML files to tell the framework which objects to build, downloading a Tomcat server and pointing your project at it, and chasing a version conflict between two libraries that refuse to agree. A day gone, and the app still just prints "hello." That friction — real, daily, and universal — is the entire reason Spring Boot exists. This lesson is the story of how Java web development stopped feeling like assembling furniture with no instructions.

2.1The problem: Java web development used to be mostly setup#

Before frameworks, building a serious Java application meant hand-wiring an enormous amount of plumbing before any real work began. A team spent its early days on four recurring chores, none of which delivered a feature:

  • Complex configuration. Behaviour lived in XML files and repetitive boilerplate, not in readable code.
  • Time-consuming setup. Servers, dependencies, and frameworks all had to be configured by hand before anything ran.
  • Deployment headaches. The app had to be packaged and shipped to a separate server that someone else configured and maintained.
  • Maintenance drag. As a project grew, keeping dependencies and configuration coherent became its own full-time tax.

Every one of these stole time from the actual product. Two engineers, Rod Johnson and Juergen Hoeller, wrote the Spring Framework to take that weight off developers. [+] Spring first appeared in 2003; the deck introduces it as the direct answer to this pain.

Analogy · the tax before the work

Traditional Java setup is like renting an empty commercial kitchen and, before you can cook, installing the ovens, running the gas line, and negotiating with the power company. Spring, and then Spring Boot, is the difference between that and walking into a kitchen where the appliances are already plumbed in and warm.

2.2Spring: the problem solver — and its catch#

Spring is a framework that takes over the tedious lifecycle work of creating and connecting your objects, so your code can focus on behaviour. It did the heavy lifting through two ideas that sit at its core, plus a set of ready-made infrastructure layers.

Inversion of Control (IoC)#

Normally your code is in charge: when it needs a helper object, it builds that object itself with new. Inversion of Control flips that — the framework, not your code, is in charge of creating and owning objects. You describe what should exist; Spring builds it, holds it, and hands it over when needed. The "control" over object lifecycle has been inverted from you to the framework.

Dependency Injection (DI)#

Dependency Injection is the delivery mechanism for IoC: instead of an object fetching the things it depends on, those things are handed to it from the outside. If your OrderService needs a PaymentClient, you don't build the client inside the service — you declare that you need one, and Spring injects a ready-made instance. The two terms travel together: IoC is the principle, DI is how Spring does it.

Analogy · the film set

Think of a movie shoot. An actor (your class) doesn't go buy their own costume, props, and coffee. They show up, and the production crew (the framework) hands them exactly what the scene needs. The actor just acts. That hand-off is dependency injection; the crew being in charge of all of it is inversion of control.

WITHOUT DI · you build it OrderService new PaymentClient() PaymentClient builds own WITH DI · Spring hands it in OrderService needs a PaymentClient Spring container injects
fig 2.2 · the object either builds its dependency, or is handed one
⭐ TRICK

The moment you stop writing new SomeDependency() inside a class and start accepting it as a constructor parameter, that class becomes trivially testable — in a test you just pass a fake. IoC/DI isn't abstract architecture astronautics; its everyday payoff is that your code can be tested and swapped without editing the class itself.

The catch. Spring gave excellent features and fine-grained control, but that control came at a price. As projects grew, the deck names three fresh pains that Spring alone didn't solve:

  • Complex project setup — multiple configuration files, manual dependency management, and version-compatibility issues between libraries.
  • Server configuration — you still set up an external server (Tomcat, Jetty, …) by hand and deployed a WAR file to it.
  • Integration challenges — stitching multiple frameworks together, on top of a complex build process.

These are what "paved the way" for Spring Boot in 2014.

2.3Spring Boot: Spring with the assumptions made for you#

Spring Boot is a layer built on top of Spring that removes the setup by taking an "opinionated" view — it makes reasonable assumptions about what most developers need and configures them automatically. You still get all of Spring underneath; you just stop paying the setup tax to reach it.

"Opinionated" is the key word. It means Boot ships with sensible defaults already chosen — a default server, default configuration, default project layout — so you can run immediately. Crucially these are defaults, not walls: you can override any of them when your case is unusual.

auto-configuration

Wires itself#

Looks at what's on your classpath and configures common components automatically, so you don't write the wiring by hand.

embedded server

Server inside the app#

Bundles Tomcat, Jetty, or Undertow into the application itself — no separate server to install or deploy a WAR to.

production-ready

Actuator & config#

Ships monitoring and management endpoints (Actuator) and easy externalized configuration for real deployments.

Analogy · the meal kit

Plain Spring is a well-stocked pantry: everything a great cook could want, but you measure and combine it all yourself. Spring Boot is the meal kit — the same quality ingredients, pre-measured, with a default recipe — so dinner is on the table fast, and you can still swap an ingredient if you want to.

Your business code Spring Boot auto-config · embedded server · starters · Actuator Spring core IoC container · dependency injection · data & web layers less config as you go up
fig 2.3 · Boot sits on Spring; your code sits on Boot
// why it matters

A very common interview question is simply "what's the difference between Spring and Spring Boot?" The clean answer: Spring is the framework; Spring Boot is an opinionated way of using Spring that auto-configures defaults, embeds a server, and manages dependencies through starters. Boot doesn't replace Spring — it packages it. Say that and you've answered it.

2.4Spring vs Spring Boot, side by side#

The deck presents this contrast as its own overview slide. The distinction is about who does the configuring.

DimensionSpringSpring Boot
ConfigurationManual — you write it (historically XML)Auto-configured from the classpath
ServerExternal; you set up Tomcat/Jetty and deploy a WAREmbedded inside the app; runs as a self-contained jar
DependenciesManaged by hand; version conflicts are yoursStarters bundle curated, version-matched sets
Setup speedSlow; lots of upfront wiringFast; runnable almost immediately
StanceFlexible, fine-grained controlOpinionated defaults you can override
RelationshipThe underlying frameworkA layer built on top of Spring
⚠ PITFALL

Don't describe Spring Boot as "a replacement for Spring" or "a different framework." It is Spring, with configuration and packaging handled for you. In an interview, calling them competing frameworks signals you don't understand the relationship — Boot depends on Spring entirely.

2.5Starting a project: Spring Initializr#

Spring Initializr is a web tool from the Spring team that generates a ready-to-run project skeleton for you. You describe the project in a form; it hands back a zip with the folder structure, the build file, and your chosen dependencies already wired in. It lives at start.spring.io.

It exists so that "start a new Spring Boot project" doesn't mean "hand-assemble a build file and a directory tree from memory." You pick your options and the correct, version-compatible skeleton is generated for you — the same convention-over-configuration philosophy, applied to the very first step.

What you choose on the form#

FieldWhat it decides
ProjectBuild tool — Gradle or Maven
LanguageJava, Kotlin, or Groovy
Spring Boot versionWhich Boot release to target
Group / ArtifactYour package name and project name (project metadata)
DependenciesThe starters to include — e.g. Spring Web for web/REST work
Configure form→ Generate (.zip)→ Extract→ Open in IDE→ ./gradlew bootRun
💡 TIP · what "Spring Web" pulls in

The Spring Web dependency is the one that turns a bare project into something that can answer HTTP requests. It brings in Spring MVC (the request-handling machinery) and an embedded Tomcat server. Without it, annotations like @RestController and @GetMapping won't exist on your classpath. It's the near-universal first dependency for any API project.

2.6Your first controller: Hello World#

A controller is the class that receives incoming web requests and decides what to send back. It's the front door of your application: a URL arrives, the controller matches it to a method, the method runs, and its return value becomes the response. The Hello World exercise builds exactly one.

The workflow from the deck: create a class such as HelloWorldController under src/main/java/..., paste the controller code and resolve imports, run ./gradlew bootRun in the terminal, then visit the endpoint in a browser with a query parameter attached.

HelloWorldController.java
@RestController
public class HelloWorldController {

    @GetMapping("/helloworld")
    public String getMethodName(@RequestParam String name) {
        return new String("Hello World, I am " + name + "!");
    }
}

Three annotations do all the work here. Read plainly, before the jargon:

  • The "answer-with-data" marker (@RestController) tells Spring this class handles web requests and that whatever a method returns should be written straight into the HTTP response body — no separate view or template step.
  • The "when this URL is GET-ed" marker (@GetMapping("/helloworld")) maps an HTTP GET request on /helloworld to this method. Visit that path and this method runs.
  • The "read a value from the URL" marker (@RequestParam) pulls a value out of the query string — the ?name=Groot part — and hands it to the method as the name argument.

So a request to http://localhost:8080/helloworld?name=Groot runs the method with name = "Groot" and returns the text Hello World, I am Groot! straight to the browser. [!] The deck's screenshot text shows the placeholder name as both "Goot" and "Groot"; the intended name is Groot — the "Goot" is a slide typo.

Browser GET ?name=Groot Embedded Tomcat localhost:8080 @GetMapping /helloworld → method @RequestParam name returns String to response body
fig 2.6 · one GET request, routed by annotations, answered as plain text
⚠ PITFALL · @Controller vs @RestController

@RestController is @Controller + @ResponseBody rolled into one. A plain @Controller treats a returned string as the name of a view to render; @RestController treats it as the actual response body. Use @RestController for APIs that return data. Mixing them up gives you a confusing "template not found" error instead of your text.

⚠ PITFALL · port 8080 in use

Spring Boot's embedded server defaults to port 8080. If another process already holds that port, the app fails to start with a bind error. Either stop the other process or set a different port in application.properties with server.port=8081. This is the single most common "why won't it run" moment for beginners.

💡 TIP · new String(...) is redundant

The deck's example returns new String("Hello World, I am " + name + "!"). The new String(...) wrapper does nothing useful here — string concatenation already produces a String, so return "Hello World, I am " + name + "!"; is equivalent and cleaner. [+] Worth noticing so you don't copy the habit into your own code.

2.7What comes next (agenda roadmap)#

The session agenda continues past this point; the following were listed but not present in the captured slides. Treat this as a map of where the lesson heads, not as taught material. [!]

next · architecture

Spring Boot MVC / MVCS#

How a request flows through layers — Controller → Service → (Repository) → Database — and why splitting responsibilities keeps an app maintainable.

next · REST APIs

DTOs, validation, exceptions#

Building real endpoints: shaping data with DTOs, validating incoming requests, and handling errors gracefully instead of leaking stack traces.

next · testing

Postman#

Exercising your API by hand — sending GET/POST requests, setting query params and bodies, and reading responses without a front end.

next · project

QEats · Module 2 · Customer Registration API#

The applied project: a REST API to manage customer registration for an e-commerce platform, pulling all of the above together.

2.8Interview & practice questions#

The natural follow-ups this material invites. Answer each aloud before expanding it.

What is the difference between Spring and Spring Boot?

Spring is the underlying framework that provides IoC, dependency injection, and infrastructure layers. Spring Boot is an opinionated layer built on top of Spring that auto-configures common components from the classpath, embeds a web server, and manages dependencies through starters. Boot doesn't replace Spring — it packages it so you can start building immediately instead of hand-wiring configuration.

What do Inversion of Control and Dependency Injection mean, and how do they relate?

Inversion of Control is the principle that the framework — not your code — is responsible for creating and managing objects and their lifecycles. Dependency Injection is the mechanism that implements it: instead of an object building its own dependencies, they are supplied to it from outside. IoC is the "what," DI is the "how." The practical payoff is looser coupling and far easier testing.

What does "opinionated" mean in the context of Spring Boot?

It means Spring Boot ships with sensible default choices already made — a default embedded server, default configuration, a conventional project layout — based on assumptions about what most applications need. This lets you run immediately without deciding everything upfront. The defaults are overridable, so "opinionated" is a fast starting posture, not a restriction.

What is an embedded server and why is it useful?

An embedded server is a web server such as Tomcat, Jetty, or Undertow bundled directly inside your application, so the app runs as a single self-contained jar. It removes the need to install and configure an external server and deploy a WAR file to it. This simplifies both local development and deployment, since running the app is the same as starting the server.

What is Spring Initializr and what does it produce?

Spring Initializr is a web tool at start.spring.io that bootstraps a new Spring Boot project. You choose the build tool, language, Boot version, project metadata, and dependencies, and it generates a downloadable zip containing the folder structure, the build file, and the selected dependencies already wired in. You extract it, open it in an IDE, and run it.

What is the role of @RestController, @GetMapping, and @RequestParam?

@RestController marks a class as a web request handler whose method return values become the HTTP response body directly. @GetMapping("/path") maps an HTTP GET on that path to a specific method. @RequestParam binds a query-string value (like ?name=Groot) to a method argument. Together they route a request to code and shape the response.

What is the difference between @Controller and @RestController?

@RestController is a convenience combination of @Controller and @ResponseBody. With a plain @Controller, a returned string is interpreted as a view name to render. With @RestController, the return value is serialized straight into the response body. Use @RestController for REST APIs that return data rather than rendered pages.

Which dependency lets a Spring Boot app handle web requests, and what does it include?

The Spring Web starter. It brings in Spring MVC — the request-mapping and handling machinery behind annotations like @RestController and @GetMapping — along with an embedded Tomcat server. It's the standard first dependency for building web applications or REST APIs.

Your Spring Boot app fails to start with a port-in-use error. What happened and how do you fix it?

The embedded server defaults to port 8080, and another process is already bound to it, so the server can't start. Either stop the process occupying 8080, or change your app's port by setting server.port (for example server.port=8081) in application.properties. Then restart.

2.9Key takeaways#

  1. Traditional Java development lost days to configuration, manual servers, and dependency conflicts before any feature got written.
  2. Spring (Rod Johnson & Juergen Hoeller) solved much of this through Inversion of Control and Dependency Injection, but still demanded heavy setup of its own.
  3. Spring Boot (2014) is Spring made opinionated: auto-configuration, an embedded server, dependency starters, and production-ready Actuator features.
  4. Spring Boot doesn't replace Spring — it's a convenience layer on top of it. That relationship is the most common interview trap.
  5. Spring Initializr at start.spring.io generates a runnable project skeleton so you never hand-assemble the first setup.
  6. A controller is your app's front door: @RestController returns data as the response body, @GetMapping routes a URL, @RequestParam reads the query string.
IoC Dependency Injection opinionated defaults auto-configuration embedded server starters Actuator Spring Initializr start.spring.io Spring Web @RestController @GetMapping @RequestParam ./gradlew bootRun localhost:8080 @Controller vs @RestController

Section 3Microexercises — Build the Muscle#

Spring Boot's whole promise is that you write business code on day one. So the practice is writing controllers, not reading about them. Attempt each drill before opening the walkthrough — type the controller, predict the error — then check yourself. Muscle memory beats recognition.

EX 1Extend the controller: an optional parameter with a default#

// your task

Building on the Hello World controller, write a GreetController exposing GET /greet that takes a required name and an optional lang (default en), returning a localized greeting. Support en, es, hi; anything else falls back to English.

  • @RestController returning plain text.
  • name required; a missing name should be a client error.
  • lang optional, via @RequestParam(defaultValue = "en").

URLs to satisfy:

  • /greet?name=Ada → Hello, Ada!
  • /greet?name=Ada&lang=es → ¡Hola, Ada!
  • /greet?name=Ada&lang=hi → नमस्ते, Ada!
Show the full walkthrough

Step 1 — class + mapping. Mark the class @RestController so returns become the response body directly, and map the path with @GetMapping("/greet").

Step 2 — the required param. @RequestParam String name is required by default. If name is absent, Spring returns 400 Bad Request automatically — you don't write that check yourself.

Step 3 — the optional param with a default. @RequestParam(defaultValue = "en") String lang makes lang optional; when the query omits it, Spring supplies "en". (Setting a defaultValue also implies required = false.)

Step 4 — pick the greeting. A small switch, defaulting to English for any unknown language code.

GreetController.java
@RestController
public class GreetController {

    @GetMapping("/greet")
    public String greet(@RequestParam String name, @RequestParam(defaultValue = "en") String lang) {

        String hello = switch (lang) {
            case "es" -> "¡Hola";
            case "hi" -> "नमस्ते";
            default   -> "Hello";
        };
        return hello + ", " + name + "!";
    }
}

Trace the URLs:

  • /greet?name=Ada → lang defaults to "en" → Hello, Ada!
  • /greet?name=Ada&lang=es → ¡Hola, Ada!
  • /greet?name=Ada&lang=hi → नमस्ते, Ada!
  • /greet (no name) → Spring returns 400 before your method even runs.

Run it with ./gradlew bootRun, then hit the URLs in a browser or with curl. Because Spring Web bundles embedded Tomcat, there's no separate server to start.

// why defaultValue beats an if

Pushing "optional with a fallback" into the annotation keeps the method body about the greeting, not about argument-plumbing. The framework does the parsing and defaulting — the same convention-over-configuration spirit, applied one parameter at a time.

EX 2Diagnose two "why won't it work" moments#

// your task

A teammate's endpoint returns an error page instead of text, and later the app won't boot at all. Diagnose both from the symptoms — these are the two most common beginner traps.

Symptom 1 — the wrong base annotation. Hitting /status gives a 500 / "Whitelabel Error Page" / "template not found" instead of the text OK.

StatusController.java
@Controller                       // ← note: not @RestController
public class StatusController {

    @GetMapping("/status")
    public String status() {
        return "OK";
    }
}

Symptom 2 — the app fails to start with:

startup log
Web server failed to start. Port 8080 was already in use.
Show the full walkthrough

Symptom 1 — diagnose. @Controller treats the returned String as a view name: Spring goes looking for a template called OK to render, finds none, and errors. @RestController is @Controller + @ResponseBody; it treats the return value as the response body.

Fix: change the annotation to @RestController (or add @ResponseBody to the method). Now /status returns OK as plain text.

StatusController.java — fixed
@RestController                   // ← now the return value IS the body
public class StatusController {

    @GetMapping("/status")
    public String status() {
        return "OK";
    }
}

Symptom 2 — diagnose. Boot's embedded server defaults to port 8080, and another process already holds it — very often a previous run of this very app that never shut down. Two fixes:

  • Free the port: find and stop the other process (lsof -i :8080 to identify it).
  • Move your app: set server.port=8081 in src/main/resources/application.properties.
⚠ the pattern

One bug bites at request time (@Controller vs @RestController), the other at boot time (port clash). When a Spring Boot app misbehaves, first ask which phase failed — it narrows the cause immediately.

@RequestParam required by default defaultValue = "en" missing required → 400 @Controller → view name @RestController → response body port 8080 in use server.port=8081 ./gradlew bootRun