2. Introducció a Spring
1. Spring and Spring Boot
El Spring Framework simplifica el desenvolupament d'aplicacions Java, independentment de si són aplicacions web ordinàries o aplicacions web fora de línia. Els seus majors avantatges són un codi font més simplificat i menys dificultat en els ajustos. Per oferir aquestes comoditats al programador, el framework es basa en els següents principis:
-
Injecció de dependències (DI): tècnica o patró de disseny utilitzat com una de les formes d'inversió de control (IOC) per promoure un acoblament feble. És a dir, quan una classe necessita una altra classe (dependència), en lloc de crear l'objecte dins de la classe mateixa, Spring el subministra o l'injecta. Aquesta forma d'IOC segueix el principi de Hollywood (no ens truquis, ja et trucarem) en què l'aplicació pren el control en lloc del codi, proporcionant els següents beneficis:
- Proporciona modularitat.
- Escalabilitat de l'aplicació sense necessitat de modificar les classes.
- Evita la dependència entre classes.
-
Desenvolupament senzill amb POJOs (Plain Old Java Objects).
- Minimitza el codi boilerplate.
- Simplifica l'accés a les dades gràcies a l'ORM (Object Relational Mapping).
- Programació Orientada a Aspectes (AOP): Permet una modularització molt més alta per fer una separació molt clara de les diferents tasques que cada classe ha de realitzar a la nostra aplicació.
1.1. Mòduls principals del Spring Framework
Gràcies a la seva estructura modular per al desenvolupament de les aplicacions més diverses en Java, Spring és l'elecció perfecta, ja que pots triar lliurement quins dels components necessites utilitzar per a les teves aplicacions i quins no. En l'arquitectura estàndard, els diferents mòduls es divideixen en sis categories principals:
-
Core Container: El contenidor principal proporciona els mòduls bàsics:
- Core i Beans formen l'esquelet del framework, contenint la funció d'injecció de dependències i donant suport als objectes POJO. Cal aclarir que un Bean és un POJO, tot i que té algunes característiques addicionals.
- Context hereta les seves característiques del mòdul Beans i es pot complementar amb funcions per a la internacionalització o la càrrega de recursos. A més, dóna suport a característiques de Java Enterprise com EJB i JMX (Java Management Extensions). Context-support facilita la integració de biblioteques d'altres proveïdors en Spring.
- Spring-expression conté el Spring Expression Language (SPeL), una extensió del Unified Expression Language de l'especificació JSP-2.1 (Java Server Pages).
-
AOP i instrumentació: Per permetre la programació orientada a aspectes, el Spring Framework conté el mòdul spring-aop. El component spring-instrument proporciona suport per a la implementació de càrrega d'objectes i classes de manipulació per al seu ús en alguns servidors.
- Missatgeria: Per servir com a base per a aplicacions basades en missatges, el Spring Framework es basa en algunes de les funcions d'encriptació del projecte Spring Integration, com Message, MessageChannel o MessageHandler. Aquest mòdul té el nom de spring-messaging.
-
Accés a Dades/Integració: Els mòduls d'aquesta categoria estan dissenyats per donar a les aplicacions Java les eines per interactuar amb altres aplicacions, així com controlar l'accés a les dades.
- spring-jdbc proporciona una capa d'abstracció que defineix la manera com un client accedeix a la base de dades i estalvia la codificació complicada típica de JDBC.
- spring-orm ofereix capes d'integració per accedir a bases de dades relacionals en interfícies ORM populars.
- spring-tx (dóna suport a la gestió de transaccions programàtiques per a totes les classes i POJOs).
- spring-oxm (capa d'abstracció per al mapatge d'objectes o XML).
- spring-jms, un mòdul amb funcions per a la producció i processament de missatges.
-
Web: en aquesta categoria es troben els mòduls específics per a aplicacions web: spring-web, spring-webmvc i spring-websocket. A més, aquesta aplicació Java ha afegit funcions d'integració típiques orientades al web com una funció de càrrega multipart o un client HTTP. El mòdul spring-webmvc també és conegut com a web servlet i és el que conté les implementacions de Spring per a l'execució del patró d'arquitectura model-vista-controlador (MVC) i serveis web REST.
- Test: el mòdul spring-test permet comprovar la funcionalitat dels components de la teva aplicació Java. Així, amb l'ajuda de frameworks addicionals com JUnit o TestNG, pots realitzar proves unitàries (centrades en un sol component) així com proves d'integració.
2. Spring vs Spring Boot
Spring Boot va aparèixer fa uns anys amb la idea de complementar Spring, és a dir, afegir a Spring, no amb la idea de substituir-lo. Com es pot interpretar a la imatge següent, Spring Boot realment funciona amb Spring per sota, però d'una manera més fàcil.
Podríem definir Spring Boot com un accelerador per a la creació de projectes Spring, que es basa principalment en el concepte de convenció abans de la configuració. Una altra manera de definir Spring Boot podria ser com un accelerador de creació de projectes Spring. Per tant, l'objectiu és crear projectes Spring, però d'una manera més àgil, a través d'una sèrie de convencions que prevalen sobre la configuració. Estalviant-nos haver de perdre temps fent configuracions pesades en fitxers.
Cal destacar que Spring Boot no es considera un Framework com a tal, en canvi, Spring sí que té el privilegi de categoritzar-se com a tal. Amb Spring Boot, podem fer el mateix que amb Spring. Però d'una manera més ràpida que si desenvolupem exclusivament amb Spring només. Però amb tots dos, podríem tenir el mateix desenvolupament, tot i que la diferència entre els dos seria el temps invertit.
Per explicar les diferències entre els dos, és essencial introduir el concepte de convenció de configuració, que juga un paper tan important en el camp de l'enginyeria de programari.
2.1. Què és la convenció de configuració?
Aquest principi especifica/detalla una sèrie de convencions (conjunt de regles) que estaran per sobre de la configuració, tret que s'especifiqui el contrari. És a dir, s'aplicaran per defecte si no especifiquem el contrari.
Un exemple d'una convenció abans de la configuració podria ser quan creem una aplicació MVC amb Spring, hem de dur a terme moltes configuracions, incloent-hi el port. D'altra banda, si creem l'aplicació utilitzant Spring Boot, gràcies a la convenció de configuració, el port per defecte de l'aplicació en iniciar-la serà 8080. Però si volem canviar-lo, només hem de modificar un fitxer i afegir una sola instrucció on detallarem el port, per exemple, 8888. D'aquesta manera, realitzarem un desenvolupament més àgil, ja que evitarem haver de fer configuracions, excepte que vulguem modificar la configuració d'alguna convenció.
3. Requisits i Instal·lació
Spring funciona amb moltes tecnologies integrades (a continuació), així que aconsellem tenir el següent per assegurar-nos que tot funcioni correctament. Els requisits són:
- Java instal·lat, és aconsellable tenir la versió 8, degut a la seva estabilitat. I que Spring no suporta algunes de les versions més noves de Java.
- Apache Maven instal·lat.
- Un IDE compatible (en aquest cas serà Spring Tool Suite).
Spring Tool Suite 4, que és el proporcionat des del lloc web de Pivotal (pàgina oficial dels creadors i mantenidors de Spring). Es pot descarregar des de https://spring.io/tools.
4. Primer projecte i execució
Per crear un projecte Spring, ho podem fer de dues maneres:
- Crear un projecte des de Spring Boot Initializer, l'eina web proporcionada per Pivotal aquí https://start.spring.io. Aquest assistent genera un fitxer zip amb l'estructura del projecte maven. Necessitem importar aquest fitxer zip al nostre IDE per començar a programar.
- Crear el projecte des de l'IDE utilitzant l'eina de línia de comandes (CLI), en el nostre cas l'IDE escollit serà Spring Tool Suite 4. No necessitem passos addicionals per començar a programar.
4.1. Initializr
Visitem https://start.spring.io i omplim el formulari:
A la part de dependències, hauríem d'afegir els aspectes del nostre programa. Inicialment aplicació web, però podríem afegir Lombok, Thymeleaf i altres aspectes.
Aquí trobareu diverses captures de pantalla amb el procés. Des de STS, creeu un nou projecte:
I seleccioneu un Spring starter project:
Seleccioneu un projecte maven, la versió de Java instal·lada i escriviu informació sobre la versió de l'artifact i altres dades:
I finalment seleccioneu les dependències. En el nostre projecte inicial, seleccioneu Spring web.
I quan el procés acabi, trobareu una estructura de projecte amb un pom.xml configurat.
i l'estructura:
4.2. Primera execució
Vegem quins fitxers s'han creat en el nostre projecte. Com podeu veure, només una classe amb una funció principal:
| Java | |
|---|---|
S'executarà una SpringApplication, de la mateixa manera que s'executa un Thread. Aquesta classe inicialitza i llança l'aplicació Spring, amb arguments, si n'hi ha.
Consell
Spring com a aplicació web, no interactua amb l'usuari, i esperarà i servirà a molts clients. Per aquesta raó, no és una bona idea fer programes interactius amb usuaris.
Per executar la nostra aplicació Spring:
I apareixerà a la consola un registre similar a:
La primera cosa important que heu de veure és el port al qual el servidor Tomcat està escoltant. Per defecte és el port 8080:
| Bash | |
|---|---|
I quan aturem el nostre programa:
Consell
Recordeu que és molt útil llegir tots aquests missatges, especialment quan alguna cosa no funciona com s'espera
Per mostrar que el nostre programa funciona correctament, necessitem provar el port específic, i després, anar al nostre navegador i escriure http://localhost:8080.
El missatge d'error que obtenim Whitelabel Error Page, no és un error en absolut, ja que no hem programat cap controlador, és a dir, el servidor està funcionant, però no està servint res.
4.3. El fitxer application.properties
Aquest fitxer conté moltes configuracions útils que establirem al llarg del nostre cicle de desenvolupament. Les estudiarem a mesura que apareguin, però totes les configuracions que vam establir al fitxer hibernate.cfg.xml a la unitat 3 es configuraran en aquest fitxer.
Aquest fitxer, com tots els fitxers de propietats, té una estructura de parella atribut-valor. El primer valor important és canviar el port que escolta el nostre servidor. Aquest fitxer es troba a la carpeta src/main/resources. Hem d'afegir, per exemple:
Si tornem a executar la nostra aplicació, hem de canviar el port al navegador per accedir al nostre servidor.
Consell
Podeu veure (gairebé) totes les propietats visitant aquesta pàgina web
Podríem afegir qualsevol valor que vulguem utilitzar, com ara constants per utilitzar en els nostres programes. Després podem carregar-lo en els nostres programes. Per exemple:
| Bash | |
|---|---|
per carregar-ho als nostres programes, necessitem utilitzar l'anotació @Value:
| Java | |
|---|---|
4.4. Anotació @SpringBootApplication
A Spring Boot, és molt comú aplicar múltiples anotacions a la classe principal. Però comunament, la majoria dels desenvolupadors principalment apliquen 3 anotacions.
@Configuration: Disponible des de la versió 3 de Spring, ens ofereix la possibilitat de fer una anotació que s'encarregarà de definir la classe que la posseeix com una classe de configuració. Aquesta configuració per al framework Spring es basarà en anotacions. I no com en els seus orígens, que es basava en XML, cosa que ho feia més complex. Un altre propòsit d'aquesta anotació serà permetre la injecció de dependències.@EnableAutoConfiguration: La configuració automàtica de Spring Boot intenta configurar automàticament la teva aplicació Spring en funció de qualsevol dependència de jar que hagis afegit. Si, per exemple, si poses un HSQLDB (sistema de gestió de bases de dades) al teu classpath, i no has configurat manualment cap bean de connexió a la base de dades, Spring Boot configura automàticament una base de dades en memòria.@ComponentScan: S'utilitza juntament amb@Configurationper dir a Spring on buscar els components, i serà dins del paquet que hem anotat. Només havent d'escriure-ho una vegada, podent fer que tots els paquets siguin fills del paquet de la classe pare (la que conté el main). Bàsicament, això diu a Spring on ha de buscar tots els components.
Per poder utilitzar aquest paquet de tres anotacions, Spring Boot ens ofereix @SpringBootApplication com la unió de les tres anotacions explicades anteriorment.
5. MVC amb Spring
5.1. Controladors
Un controlador és responsable de respondre a esdeveniments. Normalment, aquests esdeveniments són accions (més tècnicament conegudes com a sol·licituds) que solen ser realitzades per l'usuari, tot i que també poden ser sol·licituds més automatitzades com API, pàgines frontals Ajax, etc.
En un context de la vida real, un controlador és com un cambrer; Ell o ella està esperant darrere de la barra fins que arribi un client. El client demana una coca-cola, i el cambrer, si en té, la servirà. Després arriba un altre client, i demana un cafè, i llavors el cambrer el serveix. Un altre client arriba, i demana un te verd, i el cambrer diu que no el pot servir, perquè no en té. Una vegada i una altra... El cambrer servirà tot el que el client vulgui, si pot.
Tornant a Spring, hem d'afegir al nostre programa un mòdul que funcioni com un controlador, escoltant totes les sol·licituds dels clients, i responent (si pot) amb les dades que el client sol·licita.
Recordeu l'error en la primera execució de Spring: l'aplicació Spring funciona bé, però encara no tenim un controlador. Som-hi.
5.2. Paquet controllers
Anem a crear un controlador, però primer, hem de crear un paquet que contingui aquest controlador. Abans parlàvem de l'anotació @SpringBootApplication que vam dir que era equivalent a tenir 3 anotacions. Una d'elles era @ComponentScan. Si no volem haver de dir-li que escanegi diversos paquets (que normalment és la millor idea), normalment posem tota l'estructura de paquets dins del paquet pare, que serà el paquet on tenim el main.
Per fer això, feu clic dret sobre el paquet que conté el main. D'aquesta manera, quan anem a posar el nom directament ens apareixerà el com.example i només haurem d'afegir un . i el nom del paquet fill. Si no, hauríem d'escriure el nom complet del paquet. Com podeu veure, el paquet blanc ens indica que és un paquet buit en lloc del paquet marró.
Anem a crear una classe senzilla que controli l'índex de la nostra aplicació. Per aquesta raó, hem de nomenar la nostra classe com indexController.java. Recordeu que índex es refereix al domini principal del nostre servidor/app.
Consell
És una bona pràctica establir noms de classes seguint regles senzilles per entendre el comportament de la classe. Així, una classe anomenada clientController és el controlador que mapatge informació sobre Client, i filmController.java tracta sobre Films.
Un cop la nostra classe ha estat creada, dins del paquet controlador, l'hem de configurar. Vegem un exemple de indexController.java:
| Java | |
|---|---|
Mireu les nostres anotacions:
@Controller→ diu a Spring que aquesta classe és un controlador. És una especialització de@Component, i com que Spring explora tot el classpath, es detecta automàticament.@GetMapping("/")→ és el controlador. Definim un camí ("/") al nostre servidor, i escoltem el mètodeGET. En parlarem més endavant.@ResponseBody→ diu al controlador que serialitzi el valor de retorn (una cadena en el nostre exemple) a JSON i l'enviï a través dehttp_responseal client que crida el controlador.
Ara, si intentem recarregar la pàgina al navegador, en lloc d'un missatge d'error, obtindrem el valor retornat pel controlador:


Una altra manera d'obtenir el mateix resultat seria:
| Java | |
|---|---|
on:
@RestController→ indica que en aquesta classe tots els mètodes inclouen l'anotació@ResponseBody. Tingueu cura, ja que tots els mètodes retornaran un objecte JSON, i en alguns casos (quan enviem dades a vistes en un altre format), pot ser una mala idea.
5.3. Sol·licituds i Paràmetres
Atenció
Per provar la nostra sol·licitud, a partir d'ara utilitzarem POSTMAN https://www.postman.com/downloads/. Hi ha un apèndix sobre l'ús de postman.
Afegim una mica d'intel·ligència a una ruta del controlador, donant-li una mica de dinamisme a través del pas de paràmetres. Aquests paràmetres seran acceptats gràcies a l'anotació @RequestParam.
El nombre de paràmetres que rebrem serà igual al nombre de paràmetres que hem definit dins de l'anotació @RequestParam del mètode de la ruta del controlador, de la següent manera:
| Java | |
|---|---|
Això significa que una sol·licitud de GET /hola necessitarà un paràmetre (name) amb el seu valor. Per exemple http://localhost:9090/hola?name=Joange.
Tingueu en compte que si no afegim el paràmetre, la sol·licitud serà incorrecta. Podríem solucionar-ho, establint aquest paràmetre com a no requerit i un valor per defecte, de la següent manera:
| Java | |
|---|---|
5.4. Logger
Una bona idea també és utilitzar Logger per mostrar què està passant al nostre servidor. Podem utilitzar-lo com suggerim:
| Java | |
|---|---|
Logger ens ofereix mostrar cada tipus de missatge:
void error(String msg)void warn(String msg)void info(String msg)
5.5. Paràmetres múltiples
Anem a estudiar com obtenir diversos paràmetres, tot i que no es recomana més de tres o quatre, perquè els camins augmenten molt, i hi ha millors mètodes per passar dades al servidor, com objectes en la sol·licitud BODY des de formularis o dades dins dels camins. Un exemple clàssic és el següent:
tingues en compte que:
- Tot i que els valors per defecte podrien ser enters o reals, els hem de definir com a cadenes.
- La variable
HttpServletRequestdefinida s'utilitza per obtenir informació addicional sobre la sol·licitud http rebuda.
Important
@Autowired és una de les anotacions més utilitzades. Aquesta anotació permet fer la injecció de dependències. Això significa que Spring buscarà una classe dins del context de l'aplicació que coincideixi amb el bean desitjat, crearà una nova instància i la injectarà dins del bean que posseeix la injecció.
5.6. Sol·licitud POST
Apart de GET, podem fer sol·licituds POST, PUT, DELETE i més al nostre servidor. Simplement hem de substituir @GetMapping per @PostMapping, amb la corresponent importació. De fet, com que són rutes diferents, fins i tot si es diuen igual, podrien estar al mateix fitxer sense cap problema.
| Java | |
|---|---|
Com que les sol·licituds POST solen ser cridades dins d'un formulari, és una bona idea establir el paràmetre a la secció del cos de la sol·licitud. Per fer això, hem de configurar la secció BODY de POSTMAN, seleccionar www-form-urlencoded i establir els paràmetres.
Si volem un nombre il·limitat de paràmetres, podem crear una matriu i crear múltiples paràmetres a POSTMAN amb el mateix nom:
5.7. Variables en el camí
Si volem obtenir un valor específic, en forma de valor en el camí, per exemple GET films/1 en lloc de GET films?idFilm=1, la manera és la següent:
| Java | |
|---|---|
La petició respon:
Com podem veure:
- A l'aplicació establim en el camí el paràmetre
idWho. - Al controlador definim el paràmetre com a String per a poder accedir des del nostre mètode.
- Al fer la petició, el valor s'assigna des de la petició al paràmetre de la funció.