Your first Spring Boot application
Time to make the pieces concrete. This lesson builds a running Spring Boot application from nothing — the
start of Dakiya, the courier and parcel-tracking API you build across the course — and traces every part
so that when it responds to a request, you know exactly what happened and why. Everything here is verified
against a real Spring Boot 3.4 application; the /ping endpoint below genuinely returns its response.
Creating the project
You generate a Spring Boot project from Spring Initializr (start.spring.io) —
pick Maven, Java, and add the starters you need. For Dakiya's start: Spring Web (REST), and we will add
Spring Data JPA, Validation, Security and others as the course needs them. Initializr gives you a
zip with the project structure, the Maven wrapper (mvnw — so you do not need Maven installed), and a
pom.xml listing your starters. This course uses Spring Boot 3.x on Java 17+ — the versions running in
most production and hiring today.
You run it with the wrapper — no separately installed Maven or server needed:
./mvnw spring-boot:run # compiles and starts the app with its embedded server
The main class
Every Spring Boot app has one entry point:
package com.riztech.dakiya;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // the one annotation that starts it all
public class DakiyaApplication {
public static void main(String[] args) {
SpringApplication.run(DakiyaApplication.class, args);
}
}
@SpringBootApplication is three annotations in one: @SpringBootConfiguration (this is a configuration
class), @EnableAutoConfiguration (turn on the auto-configuration from the previous lesson), and
@ComponentScan (scan this package and its sub-packages for your components). That last part is why your
components must live under com.riztech.dakiya (or a sub-package) — the scan starts here. SpringApplication.run(...)
boots the whole thing: it creates the application context, scans and wires your beans, applies
auto-configuration, and starts the embedded server.
A service and a controller, wired by the container
Now the two beans, using exactly the DI you learnt. A service holds logic:
@Service // a bean the container manages
public class GreetingService {
public String greet() {
return "Dakiya is running.";
}
}
And a controller exposes an HTTP endpoint, with the service injected through its constructor:
@RestController // a web controller; returns data, not a view
public class PingController {
private final GreetingService greetingService;
public PingController(GreetingService greetingService) { // constructor injection
this.greetingService = greetingService;
}
@GetMapping("/ping") // GET /ping calls this method
public String ping() {
return greetingService.greet();
}
}
Run the app and request the endpoint:
curl http://localhost:8080/ping
# Dakiya is running.
Verified: this returns Dakiya is running. with HTTP 200. Trace what happened: at startup, component
scanning found GreetingService and PingController; the container created both and, seeing
PingController's constructor needs a GreetingService, injected the one it made; auto-configuration
started an embedded Tomcat; a request to /ping was routed by Spring MVC to the ping() method, which
called the injected service and returned its string, which @RestController wrote to the response as the
body. Every concept from this module, in one working request — and none of it magic.
@RestController and @GetMapping
Two web annotations you will use constantly:
@RestControllermarks a class as a web controller whose methods return data (serialised to the response body, as JSON for objects) rather than the name of an HTML page. For a REST API — Dakiya — this is what you want. (Plain@Controllerreturns view names, for server-rendered HTML; not our case.)@GetMapping("/ping")maps HTTPGET /pingto the method. Its siblings —@PostMapping,@PutMapping,@DeleteMapping— map the other HTTP methods. The next module goes deep on these; for now,@GetMappingturns a method into a GET endpoint.
Return a Java object instead of a string and Spring serialises it to JSON automatically (via Jackson, pulled
in by starter-web):
@GetMapping("/health")
public Map<String, String> health() {
return Map.of("status", "up"); // becomes {"status":"up"} in the response
}
A note on security starting locked-down
If you add spring-boot-starter-security, you will find every endpoint suddenly requires a login (Boot
auto-configures a locked-down default with a generated password printed at startup). That is
auto-configuration being safe by default — secure until you say otherwise. The security module configures
it properly; early on, a minimal security configuration that permits your endpoints lets you develop, and
this is itself a bean that replaces Boot's default (the "your config wins" rule from the previous lesson).
Knowing this saves the common "why is my endpoint asking for a password?" confusion — it is Spring Security's
safe default, not a bug.
Check your work
How you create and run a project. From Spring Initializr (Maven + starters); run with ./mvnw spring-boot:run — the wrapper and embedded server mean nothing else to install. Boot 3.x on Java 17+.
@SpringBootApplication. Three annotations in one — configuration, enable-auto-configuration, and
component-scan (this package and sub-packages, which is why components live under it); SpringApplication.run
creates the context, wires beans, and starts the server.
The wired request. @Service and @RestController become beans; the controller's constructor gets the
service injected; a request to @GetMapping("/ping") runs the method, which calls the service and returns
its result. Verified: /ping → "Dakiya is running." (200).
@RestController vs @Controller. @RestController returns data (JSON) for an API; @Controller
returns view names for server-rendered HTML. Objects returned are serialised to JSON automatically.
Security's locked-down default. Adding starter-security locks endpoints by default (a safe
auto-configuration); you replace it with your own security bean.
Practice
- Generate a Spring Boot project from Initializr with
Spring Web, and run it with./mvnw spring-boot:run; confirm the embedded server starts. - Add
GreetingServiceandPingControlleras shown;curl /pingand confirm "Dakiya is running." with 200. - Move
PingControllerto a package outsidecom.riztech.dakiya; restart and observe it is not found (component scanning) — then move it back. - Add a
/healthendpoint returning aMap; confirm Spring serialises it to JSON automatically. - Add
spring-boot-starter-security, restart, and watch every endpoint demand a login; read the generated password in the startup log. Then add a minimal security bean permitting requests and confirm access returns. - Break the constructor injection (remove the
GreetingServiceparameter but still use the field) and read the compile/startup error — reconnecting the DI lesson to a running app.
Official documentation
- Spring Boot — Developing your first Spring Boot application — The official first-app walkthrough.
- Spring — @RestController and request mapping — Controllers and
@GetMapping. - Spring Initializr — Generate a project with the starters you need.
Next: controllers and request mapping.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship