Learning Monday #1: Meine erste Spring Boot Anwendung – Von Null auf „Es läuft!“

Von Nova Trent, Junior Entwicklerin bei Java Fleet Systems Consulting in Essen-Rüttenscheid

Kurzzusammenfassung

In diesem Learning Monday teile ich meine ersten Schritte mit Spring Boot – vom Spring Initializr über die erste REST API bis hin zu meinen größten „Aha!“-Momenten. Du lernst, warum Spring Boot wie ein „Fertighaus-Bausatz“ funktioniert, was der Initializr wirklich macht und wie aus drei Dependencies plötzlich 20+ JARs werden. Plus: Meine erste Begegnung mit Spring Data JPA und die Entdeckung der „Magic“ Naming Conventions! 🚀

Hallo und willkommen zu meinem ersten Learning Monday! 👋

Ich bin Nova, seit drei Monaten Junior Entwicklerin hier bei Java Fleet, und heute war endlich der Tag – ich habe mich getraut, eine Spring Boot Anwendung komplett von Null zu starten.

Morgens bin ich wie immer mit dem Fahrrad ins Büro nach Rüttenscheid gefahren – das sind zum Glück nur 5 Minuten – und habe mich mit einem extra großen Kaffee an meinen Platz gesetzt. Heute würde ich endlich verstehen, was alle mit diesem „Spring Boot Magic“ meinen!

Schritt 1: Was ist eigentlich Spring Boot?

Elyndra hat es mir so erklärt: „Nova, stell dir vor, du willst ein Haus bauen. Spring Boot ist wie ein Fertighaus-Bausatz – alle wichtigen Teile sind schon da, du musst sie nur noch zusammensetzen.“

Ohne Spring Boot müsste ich:

  • Einen Web-Server (wie Tomcat) installieren und konfigurieren
  • Eine Datenbank aufsetzen und verbinden
  • JSON-Handling für APIs programmieren
  • Stunden mit Konfigurationsdateien verbringen

Mit Spring Boot bekomme ich das alles automatisch – und kann sofort mit dem eigentlichen Programmieren anfangen!

Schritt 2: Spring Initializr – Der Magic Project Generator

Elyndra hat mir start.spring.io gezeigt. Das ist wie ein Projekt-Konfigurator für Spring Boot!

🎯 Was macht der Initializr eigentlich?

Spring Initializr ist viel cleverer als er aussieht. Er generiert nicht nur eine pom.xml, sondern:

  • Komplette Maven-Struktur mit allen richtigen Verzeichnissen
  • Main-Klasse die sofort lauffähig ist
  • Kompatible Dependency-Versionen – kein „Dependency Hell“
  • Sinnvolle Standard-Konfiguration für 80% der Use Cases

🔧 Meine Initializr-Konfiguration:

Project Metadata:

Group: de.javafleet          // Wie ein "Firmen-Namespace"
Artifact: taskmanager-v1     // Der Projekt-Name
Name: Nova's Taskmanager     // Anzeigename
Package: de.javafleet.taskmanager  // Java-Package-Struktur
Java: 17                     // Aktuelle LTS-Version

🪄 Dependencies – Die wahre Magic!

Ich wählte nur 3 Dependencies, aber bekomme viel mehr:

1. Spring Web – Nicht nur ein JAR!

Was ich sehe: „Spring Web“ – 1 Dependency
Was ich wirklich bekomme: 20+ JARs!

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Das inkludiert automatisch:

  • Embedded Tomcat – kompletter Web-Server läuft in meiner App!
  • Spring MVC – für REST Controllers
  • Jackson – automatische JSON Serialization
  • Validation – Bean Validation für Input-Checks

„Ich dachte, ich bekomme nur ‚Web-Support‘, aber eigentlich ist da ein kompletter Web-Server mit drin! Das ist wie ein All-in-One-Paket!“

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

2. Spring Data JPA – Database Magic

Was ich sehe: „Spring Data JPA“ – 1 Dependency
Was ich wirklich bekomme: Enterprise Database Layer!

Das inkludiert:

  • Hibernate – ORM für Datenbankzugriff
  • HikariCP – Connection Pooling
  • Auto-Configuration – Datenbank wird automatisch erkannt
  • Repository Pattern – CRUD-Operations ohne SQL

3. H2 Database – Development Database

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

Embedded In-Memory-Database – perfekt zum Testen und Entwickeln!

Schritt 3: Der erste Code – Task Controller

Mein allererstes REST Controller:

package de.javafleet.taskmanager.controller;

import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.ArrayList;

@RestController
@RequestMapping("/api/tasks")
public class TaskController {
    
    private List<String> tasks = new ArrayList<>();
    
    @GetMapping
    public List<String> getAllTasks() {
        return tasks;
    }
    
    @PostMapping
    public String addTask(@RequestBody String task) {
        tasks.add(task);
        return "Task hinzugefügt: " + task;
    }
}

🤯 Spring Boot Magic in Action

Was passiert hier automatisch:

  • @RestController – Spring Boot erkennt: „Das ist ein REST API!“
  • @RequestMapping – Alle Methoden bekommen /api/tasks als Basis-URL
  • @GetMapping/@PostMapping – HTTP-Methoden werden automatisch gemappt
  • @RequestBody – JSON wird automatisch zu String konvertiert
  • Return Value – Java-Objekte werden automatisch zu JSON

Ich musste NICHTS konfigurieren! Kein XML, keine Annotations-Konfiguration, nichts!

Schritt 4: Die Spring Boot Anwendung starten – Ein magischer Moment

Main-Klasse (generiert vom Initializr):

package de.javafleet.taskmanager;

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

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

Ein Klick auf „Run“ und…

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.4.2)

INFO 1234 --- [main] d.j.t.TaskmanagerApplication: Started TaskmanagerApplication in 1.847 seconds

BOOM! Es läuft! 🎉

  • Tomcat Server läuft auf Port 8080
  • Meine REST API ist unter http://localhost:8080/api/tasks erreichbar
  • H2 Database ist automatisch gestartet
  • Alles funktioniert ohne weitere Konfiguration!

Schritt 5: Testing mit curl

Code Sentinel hat mir gezeigt, wie echte Entwickler APIs testen – mit curl im Terminal!

GET Request:

curl http://localhost:8080/api/tasks

Response: [] (Super leere Liste – perfekt!)

POST Request:

curl -X POST http://localhost:8080/api/tasks \
  -H "Content-Type: application/json" \
  -d '"Mein erster Task"'

Nochmal GET:

curl http://localhost:8080/api/tasks

ES FUNKTIONIERT! 🚀


WAIT… Aber ich will eine ECHTE Datenbank! 🤔

Nach dem ersten Erfolg dachte ich mir: „Das ist cool, aber die ArrayList ist ja nur im Speicher. Wenn ich die App neustarte, sind alle Tasks weg!“

Elyndra hat gelacht: „Nova, du hast doch Spring Data JPA hinzugefügt! Zeit für echte Database Magic!“

Schritt 6: Meine erste JPA Entity

Weg mit der ArrayList, her mit echten Database-Objekten!

package de.javafleet.taskmanager.entity;

import jakarta.persistence.*;

@Entity
@Table(name = "tasks")
public class Task {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false)
    private String title;
    
    private String description;
    
    private boolean completed = false;
    
    // Constructors
    public Task() {} // JPA braucht das!
    
    public Task(String title) {
        this.title = title;
    }
    
    public Task(String title, String description) {
        this.title = title;
        this.description = description;
    }
    
    // Getters und Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    
    public boolean isCompleted() { return completed; }
    public void setCompleted(boolean completed) { this.completed = completed; }
}

Was bedeuten diese Annotations?

  • @Entity – „Spring, das ist eine Datenbank-Tabelle!“
  • @Table(name = „tasks“) – „Nenne die Tabelle ‚tasks’“
  • @Id – „Das ist der Primary Key“
  • @GeneratedValue – „Die Datenbank soll automatisch IDs vergeben“
  • @Column(nullable = false) – „Titel darf nicht leer sein“

Das Coole: Hibernate erstellt automatisch die SQL-Tabelle aus meiner Java-Klasse! 🪄

Schritt 7: Repository Magic – Der Moment, der alles änderte!

Jetzt kommt der Teil, der mein Hirn gesprengt hat:

package de.javafleet.taskmanager.repository;

import de.javafleet.taskmanager.entity.Task;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface TaskRepository extends JpaRepository<Task, Long> {
    // Kein Code nötig! Spring Data generiert automatisch:
    // - findAll()
    // - findById(Long id) 
    // - save(Task task)
    // - deleteById(Long id)
    // - count()
    // und viele mehr!
}

WAIT… WAS?! 🤯

Ich schreibe ein Interface ohne Implementierung und bekomme trotzdem alle CRUD-Methoden?!

Dr. Cassian hat es mir erklärt: „Nova, das nennt sich ‚Code Generation zur Laufzeit‘. Spring Data analysiert dein Interface und generiert automatisch die Implementierung basierend auf den Methoden-Namen. Das ist moderne Metaprogrammierung!“

„Okay, ich verstehe es nicht komplett, aber es ist FANTASTISCH!“

🎯 Nova entdeckt Spring Data JPA Naming Conventions!

Und dann ist mir was aufgefallen… Ich habe aus Neugier eine Methode hinzugefügt:

@Repository
public interface TaskRepository extends JpaRepository<Task, Long> {
    // Die Standard-CRUD-Methoden...
    
    // Moment mal... kann ich das?
    List<Task> findByCompleted(boolean completed);
}

Das ist unglaublich: Ich schreibe eine Methodensignatur und Spring Data versteht automatisch, was ich will!

// Ich schreibe:
List<Task> findByCompleted(boolean completed);

// Spring Data JPA generiert automatisch:
// SELECT * FROM tasks WHERE completed = ?

Das ist kein Zufall – das ist ein cleveres System!

🪄 Die Naming Convention Regeln:

Basis-Pattern: findBy + PropertyName + (optionaler Operator)

// Meine Entity hat: id, title, description, completed
public interface TaskRepository extends JpaRepository<Task, Long> {
    
    // Nach einzelnen Properties suchen:
    List<Task> findByTitle(String title);           // WHERE title = ?
    List<Task> findByCompleted(boolean completed);  // WHERE completed = ?
    
    // Mit Text-Operatoren:
    List<Task> findByTitleContaining(String text);  // WHERE title LIKE %?%
    List<Task> findByTitleStartingWith(String text); // WHERE title LIKE ?%
    
    // Kombinationen:
    List<Task> findByCompletedAndTitleContaining(boolean completed, String title);
    // WHERE completed = ? AND title LIKE %?%
    
    // Mit Sortierung:
    List<Task> findByCompletedOrderByTitleAsc(boolean completed);
    // WHERE completed = ? ORDER BY title ASC
}

Das ist MIND-BLOWING! 🤯

Schritt 8: Controller-Update für echte Database

Zeit, meinen Controller von ArrayList auf Repository umzustellen:

package de.javafleet.taskmanager.controller;

import de.javafleet.taskmanager.entity.Task;
import de.javafleet.taskmanager.repository.TaskRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/api/tasks")
public class TaskController {
    
    @Autowired  // Erstmal @Autowired (Constructor Injection lerne ich später!)
    private TaskRepository taskRepository;
    
    @GetMapping
    public List<Task> getAllTasks() {
        return taskRepository.findAll();
    }
    
    @GetMapping("/{id}")
    public Optional<Task> getTaskById(@PathVariable Long id) {
        return taskRepository.findById(id);
    }
    
    @PostMapping
    public Task createTask(@RequestBody Task task) {
        return taskRepository.save(task);
    }
    
    // Hier kommt meine Naming Convention Entdeckung zum Einsatz!
    @GetMapping("/completed/{status}")
    public List<Task> getTasksByStatus(@PathVariable boolean status) {
        return taskRepository.findByCompleted(status);
    }
}

Was ist anders?

  • Weg mit ArrayList – jetzt echte Database!
  • Repository Injection – Spring gibt mir automatisch eine TaskRepository-Instanz
  • Echte Task-Objekte statt nur Strings
  • findByCompleted() – meine erste Custom Query!

Schritt 9: Die H2 Console entdecken – Database Browser im Browser!

Das coolste Feature überhaupt: http://localhost:8080/h2-console

Eine komplette Datenbank-Oberfläche im Browser!

  • JDBC URL: jdbc:h2:mem:testdb
  • Username: sa
  • Password: (leer lassen)

„Ich kann SQL-Abfragen schreiben, Tabellen anschauen, Daten einfügen – alles im Browser! Das ist wie phpMyAdmin für meine Entwicklungsumgebung!“

Schritt 10: Testing der neuen Database API

Zeit für echte Tests mit JSON-Objekten:

# Alle Tasks abrufen (erstmal leer)
curl http://localhost:8080/api/tasks
# Response: []

# Neuen Task erstellen
curl -X POST http://localhost:8080/api/tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Mein erster echter Task", "description": "Spring Data JPA lernen!"}'

# Response: 
# {"id":1,"title":"Mein erster echter Task","description":"Spring Data JPA lernen!","completed":false}

# Alle Tasks abrufen (jetzt mit Inhalt!)
curl http://localhost:8080/api/tasks
# Response: [{"id":1,"title":"Mein erster echter Task",...}]

Und jetzt kommt der Test meiner Naming Convention Entdeckung:

# Einen erledigten Task erstellen
curl -X POST http://localhost:8080/api/tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Erledigter Task", "completed": true}'

# Nur offene Tasks abrufen
curl http://localhost:8080/api/tasks/completed/false
# Response: [{"id":1,"title":"Mein erster echter Task","completed":false}]

# Nur erledigte Tasks abrufen  
curl http://localhost:8080/api/tasks/completed/true
# Response: [{"id":2,"title":"Erledigter Task","completed":true}]

ES FUNKTIONIERT! 🎉🎉🎉

Das ist mein erstes „Ich verstehe Spring Data!“ Moment! 🏆

Meine größten „Aha!“-Momente

1. „Spring Boot ist ein Framework, keine Library!“

Anfangs dachte ich, Spring Boot wäre nur eine Sammlung von Hilfsfunktionen. Aber nein – es steuert meine Anwendung, nicht umgekehrt!

Framework vs Library:

  • Library: Ich rufe Funktionen auf (z.B. List.add())
  • Framework: Das Framework ruft meinen Code auf (@GetMapping wird automatisch ausgeführt)

2. „Embedded Server = Game Changer!“

Früher: Anwendung separat auf Tomcat deployen
Spring Boot: Tomcat läuft IN meiner App!

Das bedeutet:

  • Keine separaten Server-Installationen
  • Einfaches Deployment (nur eine JAR-Datei)
  • Gleiche Umgebung für Development und Production

3. „Convention over Configuration funktioniert wirklich!“

Spring Boot errät 90% meiner Konfiguration richtig:

  • Datenbank-Connection (durch H2 Dependency)
  • JSON-Serialization (durch Jackson)
  • Port 8080 (Spring Boot Standard)
  • Component Scanning (durch @SpringBootApplication)

Ich muss nur das konfigurieren, was von der Norm abweicht!

4. „Spring Data Naming Conventions sind pure Magic!“

Das war mein größtes Aha-Moment:

  • Ich schreibe findByCompleted(boolean completed)
  • Spring Data generiert automatisch SELECT * FROM tasks WHERE completed = ?
  • Kein SQL, Type-Safe, selbsterklärend!

Warum ist das so genial?

  • Kein SQL schreiben – ich denke in Java-Properties
  • Type-Safe – Compiler checkt meine Methodensignatur
  • LesbarfindByCompleted(true) ist selbsterklärend
  • Konsistent – einmal gelernt, funktioniert überall gleich

Was ich heute gelernt habe

Erfolge:

  • Spring Initializr beherrschen
  • Erste REST API zum Laufen gebracht
  • Spring Boot Magic verstanden
  • Embedded Server Konzept kapiert
  • JPA Entities erstellt
  • Repository Pattern entdeckt
  • Spring Data Naming Conventions verstanden!

🤔 Noch Verwirrend:

  • Was passiert alles im Hintergrund? (Auto-Configuration)
  • Wie funktioniert Dependency Injection genau?
  • Constructor Injection vs @Autowired? (Elyndra hat das erwähnt)
  • Wie komme ich von H2 zu PostgreSQL?

📚 Nächste Schritte:

  • Constructor Injection lernen (Elyndra’s Tipp)
  • Validation für Input-Daten hinzufügen
  • Error Handling implementieren
  • Security hinzufügen (Code Sentinel wird mir helfen!)

Fazit – Spring Boot + Spring Data = Mind = Blown! 🤯

Heute habe ich verstanden, warum alle von „Spring Boot Magic“ reden!

Mit 3 Dependencies und 50 Zeilen Code habe ich eine funktionsfähige REST API mit echter Datenbank erstellt. Das wäre mit Plain Java mindestens 500 Zeilen gewesen!

Aber das Coolste: Die findByCompleted() Entdeckung! Spring Data versteht meine Methodennamen und generiert automatisch SQL. Das ist echte Entwickler-Magic!

Spring Boot nimmt mir 80% der Arbeit ab, so dass ich mich auf die Geschäftslogik konzentrieren kann. Perfekt für Anfänger wie mich!

Ich merke auch: Ich verstehe noch nicht alles, was im Hintergrund passiert. Aber das ist ok – ich lerne Schritt für Schritt!

Ausblick auf nächste Woche

Learning Monday #2: „Security & Validation – Meine Task API wird erwachsen!“

In der nächsten Woche werde ich meine Task-App sicherer machen:

  • Spring Security hinzufügen (Basic Authentication)
  • Validation mit @Valid und @NotBlank
  • Bessere Error Messages für ungültige Inputs
  • Security Best Practices die Code Sentinel mir gezeigt hat

Und: Elyndra hat versprochen, mir Constructor Injection zu zeigen und zu erklären, warum das besser als @Autowired ist!

Bis nächste Woche – und danke fürs Lesen! 💚


💻 Code zum Nachprogrammieren

Den kompletten Code aus diesem Learning Monday findest du hier:
👉 GitHub: nova-task-manager v1.0

Du kannst das Projekt klonen und direkt ausprobieren:

git clone https://github.com/Java-Fleet-Systems-Consulting-Ltd/nova-task-manager.git
cd nova-task-manager
./mvnw spring-boot:run

FAQ – Häufige Fragen zu Spring Boot

Frage 1: Ist Spring Boot schwer zu lernen?
Antwort: Nein! Spring Boot ist sehr anfängerfreundlich. Du kannst sofort produktive Apps bauen, auch ohne alle Details zu verstehen. Die Lernkurve ist viel flacher als bei Plain Spring.

Frage 2: Was ist der Unterschied zwischen Spring und Spring Boot?
Antwort: Spring ist das Framework, Spring Boot macht es einfacher zu verwenden. Spring Boot = Spring + Auto-Configuration + Embedded Server + Starter Dependencies.

Frage 3: Wie funktionieren Spring Data Naming Conventions?
Antwort: Spring Data parst deine Methodennamen mit einem Pattern: findBy + PropertyName + Operator. Aus findByCompleted(boolean) wird automatisch SELECT * FROM tasks WHERE completed = ?.

Frage 4: Brauche ich IntelliJ für Spring Boot?
Antwort: Nein! VS Code mit Java Extension Pack reicht völlig aus. IntelliJ ist mächtiger, aber für den Einstieg nicht nötig.


Nova Trent arbeitet als Junior Entwicklerin bei Java Fleet Systems Consulting in Essen-Rüttenscheid und dokumentiert ihre Lernreise von der Theorie zur Praxis. Folge ihrer Entwicklung jeden Montag hier im Blog!

#SpringBootAnfänger #JavaLernen #RestAPI #SpringBoot #SpringData #JPA #JavaFleetBlog #LearningMonday #JuniorDeveloper #NamingConventions #RepositoryPattern #DatabaseMagic



Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert