Controladors a Spring Boot
Els controladors són els responsables de gestionar les peticions dels usuaris, invocar la lògica de negoci necessària i retornar una resposta adequada.
1. Què és un controlador?
Un controlador és una classe Java que gestiona la interacció entre l’usuari i l’aplicació. La seua principal responsabilitat és:
- Rebre peticions HTTP des d’un client (navegador, aplicació mòbil, etc.).
- Invocar serveis o lògica de negoci per processar les dades de la petició.
- Retornar una resposta adequada al client:
- Dades en formats com JSON o XML per a APIs REST.
- Pàgines HTML renderitzades al servidor, quan s’utilitzen motors de plantilles com Thymeleaf.
Spring Boot ofereix dos tipus principals de controladors:
-
Controladors REST (
@RestController
): Ideals per exposar dades en format JSON o XML, utilitzats principalment per aplicacions frontend o mòbils. -
Controladors MVC (
@Controller
): Dissenyats per generar pàgines HTML al servidor mitjançant motors de plantilles.
2. Components principals dels controladors
Els controladors a Spring Boot fan ús de diverses anotacions per gestionar les rutes, tipus de peticions i paràmetres. Ací tens una explicació detallada de cada component amb exemples:
1. @Controller
- Marca una classe com un controlador que retorna pàgines HTML utilitzant un motor de plantilles (com Thymeleaf).
- S’utilitza per a aplicacions web tradicionals amb contingut renderitzat al servidor.
- Indica que aquesta classe és part de la capa de presentació.
Exemple:
@Controller
@RequestMapping("/localitzacions") // Defineix la ruta base per a aquesta classe
public class LocalitzacioMvcController {
@GetMapping("/paisos") // Defineix una ruta específica
public String veurePaisos(Model model) {
model.addAttribute("paisos", List.of("Espanya", "França", "Itàlia"));
return "paisos"; // Retorna la plantilla HTML "paisos.html"
}
}
2. @RestController
- És una variant de
@Controller
que retorna dades directament al client (en format JSON o XML). - Combina les funcionalitats de
@Controller
i@ResponseBody
, fent que cada mètode retorne dades serialitzades en el cos de la resposta HTTP.
Exemple:
@RestController
@RequestMapping("/api/localitzacions") // Defineix la ruta base de l'API
public class LocalitzacioController {
@GetMapping("/paisos") // Defineix un endpoint
public List<String> obtenirPaisos() {
return List.of("Espanya", "França", "Itàlia"); // Retorna la llista en format JSON
}
}
3. @RequestMapping
- Defineix rutes a nivell de classe o mètode.
- Permet especificar:
- Rutes estàtiques o dinàmiques.
- Tipus de peticions HTTP que es gestionen (GET, POST, PUT, DELETE, etc.).
Exemple:
@Controller
@RequestMapping("/localitzacions") // Ruta base per a tots els mètodes d'aquesta classe
public class LocalitzacioMvcController {
@RequestMapping("/ciutats") // Ruta específica, s'acedeix amb /localitzacions/ciutats
public String veureCiutats(Model model) {
model.addAttribute("ciutats", List.of("València", "Barcelona", "Madrid"));
return "ciutats"; // Retorna la plantilla "ciutats.html"
}
}
4. @GetMapping
, @PostMapping
, @PutMapping
, @DeleteMapping
- Variants especialitzades de
@RequestMapping
per simplificar la definició de rutes segons el tipus de petició HTTP. - Permeten gestionar peticions GET, POST, PUT, DELETE, entre d’altres.
Exemple:
@RestController
@RequestMapping("/api/localitzacions")
public class LocalitzacioController {
@GetMapping("/provincies") // Per a peticions GET
public List<String> obtenirProvincies() {
return List.of("València", "Sevilla", "Granada"); // Retorna en JSON
}
@PostMapping("/afegir") // Per a peticions POST
public String afegirLocalitzacio(@RequestBody String localitzacio) {
return "Localització afegida: " + localitzacio; // Retorna un missatge
}
@DeleteMapping("/eliminar") // Per a peticions DELETE
public String eliminarLocalitzacio(@RequestParam String nom) {
return "Localització eliminada: " + nom; // Retorna un missatge
}
@PutMapping("/actualitzar") // Per a peticions PUT
public String actualitzarLocalitzacio(@RequestParam String nom) {
return "Localització actualitzada: " + nom; // Retorna un missatge
}
}
5. @RequestParam
- Captura paràmetres de consulta enviats en l’URL, com ara
/provincies?nomPais=Espanya
. - Útil per filtrar resultats o obtenir valors específics enviats pel client.
Exemple:
@GetMapping("/provincies")
public List<String> obtenirProvincies(@RequestParam String nomPais) {
if (nomPais.equalsIgnoreCase("Espanya")) {
return List.of("València", "Madrid", "Barcelona");
} else {
return List.of(); // Retorna una llista buida si el país no coincideix
}
}
6. Model
(Controladors MVC)
- És una eina que permet passar dades des del controlador fins a les plantilles HTML per mostrar-les al client.
- Aquestes dades s’injecten a la plantilla HTML per a ser processades i renderitzades.
Exemple:
@GetMapping("/ciutats")
public String veureCiutats(Model model) {
model.addAttribute("ciutats", List.of("València", "Barcelona", "Madrid"));
return "ciutats"; // Retorna la plantilla "ciutats.html" amb el model
}
on:
model.addAttribute("ciutats", List.of("València", "Barcelona", "Madrid"))
: Afegeix una llista de ciutats al model.List.of("València", "Barcelona", "Madrid")
: Són les ciutats que es mostraran a la plantilla.return "ciutats";
: Retorna la plantillaciutats.html
amb les dades del model.ciutats
: És el nom de la variable que s’utilitzarà a la plantilla per accedir a la llista de ciutats.ciutats.html
: És una plantilla Thymeleaf que processarà les dades del model.Model model
: És l’objecte que conté les dades que es passaran a la plantilla.
3. Tipus de controladors
* Controladors REST
- Són ideals per a APIs que han d’exposar dades en formats estructurats com JSON o XML.
- Es fan servir per interactuar amb aplicacions frontend (React, Angular, etc.) o mòbils.
Exemple:
@RestController
@RequestMapping("/api/localitzacions")
public class LocalitzacioController {
@GetMapping("/paisos")
public List<String> obtenirPaisos() {
return List.of("Espanya", "França", "Itàlia");
}
}
*Controladors MVC
- Són útils per a aplicacions on es generen pàgines HTML dinàmicament.
- Fan ús de motors de plantilles com Thymeleaf.
Exemple:
@Controller
@RequestMapping("/localitzacions")
public class LocalitzacioMvcController {
@GetMapping("/paisos")
public String veurePaisos(Model model) {
model.addAttribute("paisos", List.of("Espanya", "França", "Itàlia"));
return "paisos";
}
}
Diferències entre @RestController
i @Controller
**
Característica | @RestController | @Controller |
---|---|---|
Format de resposta | JSON o XML | HTML |
Ús principal | Exposar dades per a APIs | Generar pàgines HTML |
Anotació complementària | Inclou @ResponseBody per defecte | Necessita Model per passar dades |
Usar els serveis en controladors REST i MVC
Els serveis (PaisService
, ProvinciaService
, i CiutatService
) encapsulen la lògica de negoci de la nostra aplicació. Per mostrar els resultats, aquests serveis han de ser utilitzats en controladors que gestionen les peticions dels usuaris i retornen respostes.
Spring Boot permet implementar:
- Controladors REST (
@RestController
) per exposar dades en format JSON o XML. - Controladors MVC (
@Controller
) per generar pàgines HTML renderitzades amb Thymeleaf.
Serveis
Abans de crear els controladors, recordem breument el que fan els serveis.
1. CiutatService
Aquest servei filtra les ciutats que tenen una població superior a un mínim especificat.
@Service
public class CiutatService {
@Autowired
private CiutatRepository ciutatRepository;
public List<Ciutat> obtenirCiutatsAmbPoblacioMinima(int poblacioMinima) {
List<Ciutat> totesLesCiutats = ciutatRepository.findAll();
List<Ciutat> ciutatsFiltrades = new ArrayList<>();
for (Ciutat ciutat : totesLesCiutats) {
if (ciutat.getPoblacio() > poblacioMinima) {
ciutatsFiltrades.add(ciutat);
}
}
return ciutatsFiltrades;
}
}
2. PaisService
El servei següent ens permet obtenir tots els països o buscar-ne un per identificador.
@Service
public class PaisService {
@Autowired
private PaisRepository paisRepository;
public List<Pais> obtenirTotsElsPaisos() {
return paisRepository.findAll();
}
public Optional<Pais> obtenirPaisPerId(Long id) {
return paisRepository.findById(id);
}
}
3. ProvinciaService
El servei filtra les províncies pertanyents a un país específic.
@Service
public class ProvinciaService {
@Autowired
private ProvinciaRepository provinciaRepository;
public List<Provincia> obtenirProvinciesPerPais(String nomPais) {
List<Provincia> provincies = provinciaRepository.findAll();
List<Provincia> resultat = new ArrayList<>();
for (Provincia provincia : provincies) {
if (provincia.getPais().getNom().equalsIgnoreCase(nomPais)) {
resultat.add(provincia);
}
}
return resultat;
}
}
1. Creació d’un controlador REST
Els controladors REST s’utilitzen per exposar dades en format JSON o XML, ideals per a aplicacions frontend o mòbils.
Exemple de controlador REST
@RestController
@RequestMapping("/api/localitzacions") // Defineix la URL base
public class LocalitzacioRestController {
@Autowired
private PaisService paisService;
@Autowired
private ProvinciaService provinciaService;
@Autowired
private CiutatService ciutatService;
// Endpoint per obtenir tots els països
@GetMapping("/paisos")
public List<Pais> obtenirTotsElsPaisos() {
return paisService.obtenirTotsElsPaisos();
}
// Endpoint per obtenir les províncies d’un país concret
@GetMapping("/provincies")
public List<Provincia> obtenirProvinciesPerPais(@RequestParam String nomPais) {
return provinciaService.obtenirProvinciesPerPais(nomPais);
}
// Endpoint per obtenir ciutats amb més de X habitants
@GetMapping("/ciutats")
public List<Ciutat> obtenirCiutatsAmbPoblacioMinima(@RequestParam int poblacioMinima) {
return ciutatService.obtenirCiutatsAmbPoblacioMinima(poblacioMinima);
}
}
Funcionament dels endpoints del controlador REST
- URL Base:
- El controlador està mapejat a
/api/localitzacions
.
- El controlador està mapejat a
- Endpoints disponibles:
GET /api/localitzacions/paisos
:- Retorna tots els països en format JSON.
GET /api/localitzacions/provincies?nomPais=Espanya
:- Retorna les províncies del país “Espanya”.
GET /api/localitzacions/ciutats?poblacioMinima=100000
:- Retorna totes les ciutats amb més de 100.000 habitants.
- On veure els resultats?
- Usa eines com Postman o un navegador per accedir a:
http://localhost:8080/api/localitzacions/paisos
http://localhost:8080/api/localitzacions/provincies?nomPais=Espanya
http://localhost:8080/api/localitzacions/ciutats?poblacioMinima=100000
- Usa eines com Postman o un navegador per accedir a:
2. Creació d’un controlador MVC amb Thymeleaf
Un controlador MVC s’utilitza per generar pàgines HTML dinàmiques que poden ser servides al navegador. En aquest cas, usarem Thymeleaf com a motor de plantilles per mostrar els resultats dels serveis que hem creat.
Controlador MVC
Aquest controlador utilitzarà els serveis PaisService
, ProvinciaService
i CiutatService
per gestionar les peticions i passar les dades al motor de plantilles Thymeleaf.
Controlador MVC:
@Controller
@RequestMapping("/localitzacions") // URL base per a totes les peticions
public class LocalitzacioMvcController {
@Autowired
private PaisService paisService;
@Autowired
private ProvinciaService provinciaService;
@Autowired
private CiutatService ciutatService;
// Mostra tots els països en una pàgina HTML
@GetMapping("/paisos")
public String veurePaisos(Model model) {
List<Pais> paisos = paisService.obtenirTotsElsPaisos();
model.addAttribute("paisos", paisos); // Afegeix la llista de països al model
return "paisos"; // Retorna la plantilla "paisos.html"
}
// Mostra les províncies d'un país concret en una pàgina HTML
@GetMapping("/provincies")
public String veureProvincies(@RequestParam String nomPais, Model model) {
List<Provincia> provincies = provinciaService.obtenirProvinciesPerPais(nomPais);
model.addAttribute("provincies", provincies); // Afegeix la llista de províncies al model
model.addAttribute("pais", nomPais); // Afegeix el nom del país seleccionat al model
return "provincies"; // Retorna la plantilla "provincies.html"
}
// Mostra les ciutats amb més de X habitants en una pàgina HTML
@GetMapping("/ciutats")
public String veureCiutats(@RequestParam int poblacioMinima, Model model) {
List<Ciutat> ciutats = ciutatService.obtenirCiutatsAmbPoblacioMinima(poblacioMinima);
model.addAttribute("ciutats", ciutats); // Afegeix la llista de ciutats al model
model.addAttribute("poblacioMinima", poblacioMinima); // Afegeix el valor de població mínima al model
return "ciutats"; // Retorna la plantilla "ciutats.html"
}
}
Plantilles Thymeleaf
Les plantilles Thymeleaf són fitxers HTML que contenen placeholders o expressions que s’omplin amb dades proporcionades pel controlador.
- 1. Plantilla
paisos.html
Aquesta plantilla mostra una llista de tots els països retornats pel servei.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Llista de Països</title>
</head>
<body>
<h1>Llista de Països</h1>
<ul>
<!-- Itera per cada país en la llista i mostra el seu nom -->
<li th:each="pais : ${paisos}" th:text="${pais.nom}"></li>
</ul>
</body>
</html>
- 2. Plantilla
provincies.html
Aquesta plantilla mostra les províncies d’un país concret.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Províncies de <span th:text="${pais}"></span></title>
</head>
<body>
<h1>Províncies del país: <span th:text="${pais}"></span></h1>
<ul>
<!-- Itera per cada província i mostra el seu nom -->
<li th:each="provincia : ${provincies}" th:text="${provincia.nom}"></li>
</ul>
</body>
</html>
- 3. Plantilla
ciutats.html
Aquesta plantilla mostra les ciutats que tenen més habitants que el valor proporcionat.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Ciutats amb més de <span th:text="${poblacioMinima}"></span> habitants</title>
</head>
<body>
<h1>Ciutats amb més de <span th:text="${poblacioMinima}"></span> habitants</h1>
<ul>
<!-- Itera per cada ciutat i mostra el seu nom -->
<li th:each="ciutat : ${ciutats}" th:text="${ciutat.nom}"></li>
</ul>
</body>
</html>
Funcionament de les plantilles als controladors
- Model:
- El
Model
s’utilitza per passar dades des del controlador a la plantilla. - Exemples:
model.addAttribute("paisos", paisos);
: Afegeix la llista de països perquè puga ser utilitzada a la plantilla.
- El
th:each
:- Aquesta instrucció Thymeleaf s’utilitza per iterar una llista d’elements.
- Exemples:
<li th:each="pais : ${paisos}" th:text="${pais.nom}"></li>
: Itera per cada país i mostra el seu nom.
th:text
:- Substitueix el contingut d’un element HTML amb el valor proporcionat.
- Exemple:
<span th:text="${pais}"></span>
: Mostra el nom del país seleccionat.
@RequestParam
:- Captura els paràmetres proporcionats en la URL de la petició.
- Exemple:
@RequestParam String nomPais
: Captura el valor del paràmetrenomPais
en una URL com ara/provincies?nomPais=Espanya
.
- Retorn de la vista:
- Les plantilles Thymeleaf es corresponen amb noms que el controlador retorna com a cadenes de text, com ara
"paisos"
,"provincies"
o"ciutats"
. El motor de plantilles busca els fitxerspaisos.html
,provincies.html
ociutats.html
en el directori de plantilles.
- Les plantilles Thymeleaf es corresponen amb noms que el controlador retorna com a cadenes de text, com ara
Per visulitzar els resultats
- Endpoints del controlador:
GET /localitzacions/paisos
:- Mostra la plantilla
paisos.html
amb la llista de països.
- Mostra la plantilla
GET /localitzacions/provincies?nomPais=Espanya
:- Mostra la plantilla
provincies.html
amb les províncies del país “Espanya”.
- Mostra la plantilla
GET /localitzacions/ciutats?poblacioMinima=100000
:- Mostra la plantilla
ciutats.html
amb les ciutats amb més de 100.000 habitants.
- Mostra la plantilla
- Exemple de navegació:
http://localhost:8080/localitzacions/paisos
:- Veurem una llista de països.
http://localhost:8080/localitzacions/provincies?nomPais=Espanya
:- Veurem una llista de províncies del país “Espanya”.
http://localhost:8080/localitzacions/ciutats?poblacioMinima=50000
:- Veurem una llista de ciutats amb més de 50.000 habitants.