Sei lì, con l'idea di un'applicazione web in Java. Hai letto di Spring Boot 3, ma i tutorial che trovi o sono troppo datati (Java 8, Spring Boot 1.x) o ti parlano di configurazioni chilometriche. Il problema è uno: perdere tempo a montare l'impalcatura invece di costruire ciò che conta. Noi di Meteora Web lo vediamo ogni giorno: sviluppatori che passano ore a cercare lo starter giusto, a capire perché l'application context non parte, a combattere con versioni incompatibili. Questa guida ti prende per mano e ti porta da zero a un'applicazione web Spring Boot 3 completa, funzionante e pronta per essere estesa. Niente fronzoli, solo codice che puoi copiare e modificare subito.
Perché Spring Boot 3 e non la versione 2
Spring Boot 3 è un salto generazionale. Basato su Spring Framework 6, richiede Java 17 o superiore. Questo significa record, pattern matching, sealed class, text blocks – roba che rende il codice più leggibile e sicuro. Sotto il cofano, usa Jakarta EE 9+ (non più javax.servlet), supporta nativamente GraalVM per native image, e ha una gestione delle dipendenze molto più pulita. Se parti da zero con Spring Boot 3, non devi fare alcun back-porting. E se arrivi da Spring Boot 2.x, la migrazione è lineare – ma noi costruiamo da zero, quindi via libera.
Setup del progetto: 60 secondi con Spring Initializr
Dimentica di scaricare zip e importare a mano. Noi usiamo Spring Initializr: seleziona Maven (o Gradle, a scelta), Java 17+, Spring Boot 3.x. Le dipendenze minime per un'applicazione web completa:
- Spring Web – per REST e MVC
- Spring Data JPA – per accedere al database
- H2 Database – per sviluppo (poi lo sostituisci con PostgreSQL o MySQL)
- Spring Boot DevTools – hot reload, non farne a meno
- Lombok – riduce la verbosità del boilerplate
- Thymeleaf – template engine per le view HTML (se ti serve frontend integrato)
- Validation – jakarta.validation per validare input
Genera il progetto, estrai in una cartella e aprilo con l'IDE che preferisci (IntelliJ o VS Code con estensione Spring Boot).
La struttura del package
Non lasciare tutto nel package root. Organizza per feature: controller, service, repository, model, dto. Esempio:
com.meteoraweb.demo
├── controller
├── service
├── repository
├── model
└── dto
Primo REST controller: Hello World che fa sul serio
Creiamo un controller che restituisce un JSON. Usiamo una classe record per il DTO, perché Java 17 ce lo permette e toglie boilerplate.
package com.meteoraweb.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1")
public class GreetingController {
@GetMapping("/greeting")
public GreetingResponse greet() {
return new GreetingResponse("Ciao da Meteora Web");
}
public record GreetingResponse(String message) {}
}
Avvia l'applicazione con mvn spring-boot:run e chiama http://localhost:8080/api/v1/greeting. Vedi JSON? Funziona. Hai appena costruito un endpoint in 10 righe.
Aggiungere logica di business e persistenza
Ora creiamo un'entità JPA per memorizzare i messaggi. Partiamo da un modello semplice: Greeting con id, testo e data creazione.
package com.meteoraweb.demo.model;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "greetings")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Greeting {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String text;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@PrePersist
public void prePersist() {
this.createdAt = LocalDateTime.now();
}
}
Repository:
package com.meteoraweb.demo.repository;
import com.meteoraweb.demo.model.Greeting;
import org.springframework.data.jpa.repository.JpaRepository;
public interface GreetingRepository extends JpaRepository<Greeting, Long> {
}
Service:
package com.meteoraweb.demo.service;
import com.meteoraweb.demo.model.Greeting;
import com.meteoraweb.demo.repository.GreetingRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class GreetingService {
private final GreetingRepository repository;
public Greeting save(String text) {
Greeting greeting = Greeting.builder().text(text).build();
return repository.save(greeting);
}
public List<Greeting> findAll() {
return repository.findAll();
}
}
Aggiorna il controller per usare il service:
@RestController
@RequestMapping("/api/v1")
@RequiredArgsConstructor
public class GreetingController {
private final GreetingService service;
@PostMapping("/greeting")
public Greeting create(@RequestBody GreetingRequest request) {
return service.save(request.text());
}
@GetMapping("/greeting")
public List<Greeting> getAll() {
return service.findAll();
}
public record GreetingRequest(String text) {}
}
Ora hai una API CRUD di base con database H2 in memoria. Puoi testare con curl o Postman.
Frontend con Thymeleaf: una pagina semplice
Se ti serve un'interfaccia web integrata, Thymeleaf è la scelta più rapida. Crea un controller MVC:
package com.meteoraweb.demo.controller;
import com.meteoraweb.demo.service.GreetingService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
@RequiredArgsConstructor
public class HomeController {
private final GreetingService service;
@GetMapping("/")
public String home(Model model) {
model.addAttribute("greetings", service.findAll());
return "home";
}
}
Template src/main/resources/templates/home.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Meteora Web - Greetings</title>
</head>
<body>
<h1>Messaggi ricevuti</h1>
<ul>
<li th:each="g : ${greetings}" th:text="${g.text} + ' (' + ${g.createdAt} + ')'"></li>
</ul>
<form method="post" action="/api/v1/greeting">
<input type="text" name="text" placeholder="Scrivi un messaggio" />
<button type="submit">Invia</button>
</form>
</body>
</html>
Attenzione: il form POST deve essere gestito dal controller REST. Per semplicità, aggiungi un metodo POST anche nel controller MVC o usa JavaScript. Noi suggeriamo di usare un form che chiama l'API via fetch, ma per questa guida ci fermiamo qui.
Validazione e gestione degli errori
Non fidarti mai dell'input utente. Aggiungi validation sul DTO:
public record GreetingRequest(@NotBlank String text) {}
E attiva @Valid nel controller:
@PostMapping("/greeting")
public Greeting create(@Valid @RequestBody GreetingRequest request) { ... }
Per gestire gli errori in modo uniforme, crea un @ControllerAdvice:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidation(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(e -> errors.put(e.getField(), e.getDefaultMessage()));
return ResponseEntity.badRequest().body(errors);
}
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<String> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.notFound().build();
}
}
Test: non aspettare la produzione
Spring Boot 3 facilita i test con @SpringBootTest e @WebMvcTest.
@WebMvcTest(GreetingController.class)
class GreetingControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void shouldReturnGreetings() throws Exception {
mockMvc.perform(get("/api/v1/greeting"))
.andExpect(status().isOk());
}
}
Integrazione con database: usa @DataJpaTest e @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.ANY). Scrivi test per ogni repository e service. Se non testi, non sai se funziona.
Configurazione per produzione
Prima di andare in produzione: cambia il profilo. Usa application-prod.properties con database reale (PostgreSQL), attiva il logging, disabilita DevTools, imposta un server servlet container robusto (Tomcat embedded è già presente). Aggiungi sicurezza con Spring Security (non trattata qui, ma indispensabile). E non dimenticare di configurare CORS se hai un frontend separato.
Ecco un esempio di configurazione per PostgreSQL:
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=user
spring.datasource.password=pass
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=false
Usa spring.jpa.hibernate.ddl-auto=validate in produzione – non far generare lo schema a Hibernate se non sei in sviluppo.
In sintesi — cosa fare adesso
- Genera il progetto su start.spring.io con le dipendenze elencate.
- Crea le entità e i repository per il tuo dominio.
- Scrivi i service con la logica di business, non negli endpoint.
- Implementa validazione e gestione errori prima di scrivere la UI.
- Testa ogni strato – unità, integrazione, API con MockMvc.
- Configura profili per sviluppo e produzione.
- Non dimenticare sicurezza e CORS – Spring Security è il prossimo passo.
Hai appena costruito un'applicazione web Spring Boot 3 completa. Ora è tua. Modificala, estendila, falla crescere. Noi di Meteora Web usiamo Spring Boot nei progetti reali perché dà controllo, performance e una community solida. Se vuoi approfondire, guarda la documentazione ufficiale.
Sponsored Protocol