Introducció a Spring i Spring MVC

Spring és un framework amb mòduls basat en Java Enterprise Edition. La principal característica del seu core és la utilització del patró de disseny inversió de control (IoC, per les sigles en anglès) i també la injecció de dependències (DI, per les sigles en anglès), un tipus d’IoC.

En concret, fent servir IoC i DI al nostre codi no crearem els objectes que necessitem de les llibreries del framework; simplement definint la configuració amb fitxers XML o amb anotacions al codi, Spring ens proporcionarà l’objecte adient.

Spring MVC és un mòdul d’Spring que ens ajuda a construir aplicacions sota el patró model vista controlador (MVC, per les sigles en anglès)

El model és el conjunt d’objectes que representen les dades de la nostra aplicació, la vista correspon a la manera de presentar les dades a l’usuari, i controlador manega les peticions fetes per l’usuari, interactuant amb la vista i amb el model.

A Spring MVC, qualsevol petició de l’usuari és recollida per un controlador central (Dispatcher Servlet) que determinarà, segons la configuració, el controlador específic de la nostra aplicació que haurà de recollir la petició. El nostre controlador haurà de construir la resposta amb la vista que correspon a la petició amb el model adient. El Dispatcher Servlet tornarà a prendre el control i retornarà la resposta al client.

I per fer independent els nostres projectes de l’IDE farem servir Maven com a eina que dóna estructura als projectes i que permet baixar les llibreries que fareu servir des de repositoris centrals a partir de la configuració de dependències.

Començareu creant dos projectes amb Maven sense dependències d’Spring MVC per conèixer l’estructura dels projectes i les dependències necessàries amb Java Enterprise Edition per continuar amb projectes Spring MVC, un “Hola, Món” amb Spring MVC per apropar-nos al framework i un projecte “Estoc de medicaments” que simplement mostra una pàgina de benvinguda.

"Hola, Món" amb Maven

Maven és una eina que us permet descarregar totes aquelles llibreries que necessita un servidor extern el qual conté un repositori amb un llistat molt ampli de llibreries i components; a més de poder descarregar llibreries, també us permet la generació de projectes de manera automàtica per a aplicacions de propòsit específic. Per exemple, una aplicació web, com seria el vostre cas.

Maven es una herramienta de software para la gestión y construcción de proyectos Java creada por Jason van Zyl, de Sonatype, en 2002. Tiene un modelo de configuración basado en un formato XML (archivo pom.xml). Actualmente es un proyecto perteneciente a la Apache Software Foundation.

Maven també permet transportar un projecte des d’un entorn de desenvolupament a un altre. Per exemple, si teniu un projecte Maven creat amb Eclipse el podreu importar sense problemes a NetBeans.

Preparació de l'entorn de desenvolupament

El primer que farem per preparar el vostre entorn serà configurar Netbeans per aïllar els vostres projectes dels projectes d’altres mòduls desenvolupats amb Netbeans, i d’aquesta manera aconseguireu un espai de treball molt més net.

Per tant, aneu al directori NetBeansProjects i allà creeu el directori Spring_Projects, que serà el que fareu servir per als vostres projectes amb Spring.

Un cop creat el directori, torneu a Netbeans i aneu a File/Projects Group, això us obrirà una finestra que us permetrà definir el directori que acabeu de crear com un nou espai de treball en blanc (vegeu la figura).

Figura Creació d’un grup de projectes

Actualització dels repositoris amb Maven

Un cop definit i seleccionat el nou espai de treball, el que fareu ara serà actualitzar els repositoris amb Maven.

Per això, en el vostre entorn de Netbeans aneu a la pestanya Serveis i allà desplegueu l’apartat Maven Repositories; com podeu observar, existeixen dos repositoris: un d’extern, o repositori central, i un local.

El que fareu serà establir una connexió amb el repositori central per tal d’obtenir una llista actualitzada de tots els components emmagatzemats al repositori central.

Per fer-ho, aneu a la pestanya Services de NetBeans, desplegueu l’element Maven Repositories i, situats al node Central Repository, prement amb el botó dret, podreu actualitzar la llista (opció Update Index), tal com es pot veure en la figura.

Figura Actualització de l’índex de components

El procés d’actualització dels repositoris triga una bona estona; per tant, tingueu paciència.

Creació d'un projecte amb Maven

Un cop actualitzats els repositoris podeu procedir a la creació d’un projecte amb Maven; a partir d’aquest aprofundirem en els conceptes i l’estructura que en proporciona.

Per fer això aneu a File/New Project, en l’apartat de categories seleccioneu Maven i en l’apartat Project seleccioneu POM Projects. Ara només us resta definir el nom i la localització del vostre primer projecte amb Maven (vegeu la figura).

Figura Nou projecte Maven

Aquí haureu d’especificar tres apartats: el nom del projecte, la localització del projecte i l’identificador del grup (vegeu la figura).

  • nom del projecte: HolaMaven
  • localització del projecte: Spring_Projects
  • identificador del grup: cat.xtec.ioc

Figura Propietats del projecte

Si tot ha anat bé, tant al directori Spring_Projects com a Netbeans podreu veure que s’ha creat un nou projecte.

Definició de les dependències

Les dependències no són altra cosa que les llibreries o els components que necessita la nostra aplicació per funcionar o portar a terme una tasca determinada. Un exemple de dependència seria la llibreria JDBC per a MySQL, que ens permet obrir i tancar connexions contra una base de dades MySQL i fer diferents operacions contra aquesta.

Per desenvolupar una aplicació web necessiteu descarregar tres dependències des dels repositoris de Maven, que són:

  • l’entorn de treball Spring
  • la llibreria jstl
  • la llibreria servlet-api

Maven fa servir un fitxer de configuració XML anomenat pom.xml on podeu indicar les dependències de la vostra aplicació web; aquest fitxer el podeu localitzar a la carpeta Projects Files del vostre nou projecte. Però com podeu veure si l’obriu, no fa cap esment de Spring ni a la resta de llibreries que comentàvem.

L’edició del fitxer pom.xml per incloure aquestes tres llibreries la podem portar a terme de dues maneres: una seria fent-la directament contra el fitxer pom.xml i l’altra seria utilitzant l’assistent que ens ofereix NetBeans per tal de fer aquesta edició contra el fitxer pom.xml.

En el vostre cas, i per començar, fareu servir l’assistent, ja que us ajudarà a comprendre d’una manera més senzilla què esteu fent.

Així doncs, amb el fitxer pom.xml obert, aneu a la carpeta Dependències del vostre projecte i feu clic amb el botó dret del ratolí. Això obrirà un desplegable amb l’opció Add Dependencie…; feu clic sobre aquesta opció i s’obrirà una finestra nova.

En aquesta finestra apareixen diferents camps per omplir, però a nosaltres només ens interessen tres, que són:

  • Group Id: es correspon amb l’identificador que fa servir Maven per a un conjunt de components desenvolupats per un determinat projecte o empresa. Aquest identificador pren l’aspecte de l’espai de nom del projecte, com per exemple org.springframework.
  • Artifact Id: es correspon amb un component determinat desenvolupat per un projecte o empresa; en general, és el nom del component o llibreria.
  • Version: representa la versió del component que volem fer servir.

Ompliu els tres camps que hem comentat amb els següents valors, respectivament:

  • org.springframework
  • spring-webmvc
  • 4.0.3.RELEASE

Afegiu la dependència i observeu què ha passat amb el fitxer pom.xml i amb la carpeta Dependències.

Com podeu veure, el fitxer pom.xml s’ha modificat amb noves etiquetes i valors, i la carpeta Dependències incorpora ara noves llibreries que es corresponen amb les llibreries que ens permeten desenvolupar aplicacions web amb l’entorn de treball Spring.

Si haguéssiu tingut un error d’escriptura dels valors indicats per a la dependència, Maven seria incapaç de descarregar-la i ho indicaria amb un petit triangle groc d’advertència sobre la icona del component a la carpeta Dependències.

Un cop descarregat el primer component, descarregueu els altres dos amb l’assistent. Les dades que necessiteu són les següents:

  • Per a la llibreria jstl
    • javax.servlet
    • jstl
    • 1.2
  • Per a la llibreria servlet-api
    • javax.servlet
    • javax.servlet-api
    • 3.1

El fitxer pom.xml del projecte quedarà de la següent manera:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                                    http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>cat.xtec.ioc</groupId>
    <artifactId>A0010_Spring_Introduccio</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.0.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

'Hola, Món' web amb Maven

La creació d’aquest segon projecte la farem mitjançant un arquetipus, que és la definició d’una estructura de directoris i fitxers específics per a un projecte genèric, i el que fa és permetre la creació d’un projecte nou seguint una convenció determinada; en el vostre cas, es crearà una estructura que segueix la convenció establerta per a la creació d’aplicacions web amb Spring.

Creació d'un projecte nou

Per crear aquest nou projecte web aprofitarem la carpeta Modules del projecte Maven creat anteriorment. Si feu clic sobre la carpeta amb el botó dret de ratolí s’obrirà un menú contextual, on podreu seleccionar l’opció Create New Module. Això obrirà un nou assistent per a la creació de projectes. Aquí seleccionareu la categoria Maven, i dintre del tipus de projectes disponibles seleccionareu Project from Archetype (vegeu la figura).

Figura Nou projecte Maven from Archetype

Un cop seleccionat el nou tipus d’aplicació a desenvolupar, cercareu l’arquetipus desitjat; en el vostre cas heu de cercar el següent arquetipus: maven-archetype-webapp. Un cop localitzat l’arquetipus, el seleccionareu i polsareu el següent en l’assistent (vegeu la figura).

Figura Propietats de l’arquetipus

Això obrirà una nova finestra en l’assistent, on donareu el següent nom al projecte: A01_Maven_Web_App, i verificareu que tant la localització del projecte (Spring_Projects) com el Group Id (cat.xtec.ioc) són els correctes, i un cop fet això finalitzareu l’assistent.

En tancar l’assistent es generarà un nou mòdul, així com un nou projecte. Si el nom no es correspon amb el que li havíeu indicat prèviament podeu reanomenar-lo amb el botó dret de ratolí obrint el menú contextual i seleccionant l’opció Reanomenar. Aquest punt l’heu de fer des del projecte generat, no des del mòdul. Finalment, amb el mateix menú contextual teniu l’opció d’executar el nou projecte web clicant sobre l’apartat Run. En aquest punt s’obrirà un nou assistent on haureu d’indicar qui serà el servidor de desplegament de l’aplicació; seleccioneu GlassFish Server 4.1 (o la versió més recent) i l’opció Recorda de manera permanent (vegeu la figura).

Després d’això, Netbeans procedirà al desplegament de la nostra aplicació, engegarà el servidor d’aplicacions GlassFish, executarà l’aplicació i podreu veure el resultat a través del vostre navegador web.

Si el desplegament s’ha fet correctament podeu anar a la pestanya Services de NetBeans i veure la vostre aplicació web com a node de Servers/Glassfish Server xxx/Applications, on “xxx” és la versió del servidor que heu fet servir.

Figura Selecció del servidor d’aplicacions

Estructura típica d'una aplicació web

Si us situeu sobre el projecte A01_Maven_Web_App, la vostra primera aplicació té la següent estructura des de la pestanya projectes: Web Pages, Other Sources, Dependencies, Test Dependencies i Project Files (vegeu la figura).

Figura Estructura d’un projecte Maven WebApp

La carpeta Project Files conté el fitxer pom.xml, que és on es declaren les dependències del projecte. Com podeu observar, el fitxer pom.xml del mòdul (projecte A01_Maven_Web_App) és diferent del fitxer pom.xml del projecte arrel (projecte A00_HolaMaven); tot i això, si obriu la carpeta Dependències del projecte A01_Maven_Web_App podreu observar que fa referència a les dependències declarades en el projecte arrel.

La carpeta Test Dependencies inclourà les llibreries necessàries per fer les proves de la nostra aplicació. Other Sources és una carpeta que no farem servir per ara, i finalment Web Pages contindrà tot allò vinculat a les vistes web de l’aplicació. Dintre de Web Pages hi ha la carpeta WEB-INF, que serà l’arrel de totes les vistes generades.

Generalment, WEB-INF, a banda dels scripts jsp, contindrà el descriptor de desplegament web.xml i els fitxers de configuració de Spring que veurem més endavant.

"Hola, Món" amb Spring MVC

Fins ara heu après a crear projectes amb Maven, gestionar les dependències i crear una aplicació web molt senzilla però sense fer servir Spring.

Ara farem la nostra primera aplicació amb el framework Spring MVC amb l’objectiu de mostrar com es configura tot l’entorn d’un projecte desenvolupat amb aquest framework.

L’aplicació serà un “Hola, Món” per mostrar simplement aquest text en el navegador, però amb l’estructura d’un projecte Maven WebApp i els components de Spring MVC.

El projecte sencer de l’aplicació es pot baixar des del següent

enllaç ( 10.8 MB )
.

És convenient fer servir el projecte anterior per consultar, però és millor anar construint el vostre propi projecte amb les indicacions que es van donant. No obstant això, si voleu executar el projecte sencer segurament us obligarà a fer clean and build abans.

Creació del projecte "Hola, Món" a partir de Maven WebApp

Creeu un nou projecte Maven/Project from Archetype amb l’arquetipus maven-archetype-webapp i anomeneu-lo HolaMonSpringMVC.

Recordem l’estructura del projecte creat fins ara: només és un projecte Maven WebApp a tots els efectes (vegeu la figura).

Figura Estructura Maven d’una aplicació Spring MVC

Aquesta estructura correspon a qualsevol tipus d’aplicació, i per això, des de la pestanya Files de NetBeans o des del mateix explorador de fitxers del sistema operatiu creeu la carpeta Java dins de la carpeta src/main. Ara, si tornem a la pestanya Projects de NetBeans, veurem que ha aparegut la carpeta Source Packages on crear els nostres paquets.

Abans de continuar, canvieu el fitxer de configuració web.xml a una versió més moderna de JAVA EE.

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                                 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name>HolaMonSpringMVC</display-name>
</web-app>

Ara ja podeu executar l’aplicació seleccionant el servidor Glassfish i fent que recordi aquesta decisió permanentment (vegeu la figura).

Figura Sortida de l’aplicació “Hola, Món” Spring MVC

Afegint dependències J2EE i Spring MVC

Anem a afegir les dependències que faran que el servidor d’aplicacions Glassfish, en executar la nostra aplicació, pugui crear els objectes necessaris de J2EE i Spring MVC i així aprofitar la funcionalitat que aquests entorns ens ofereixen.

A la secció dependències de pom.xml heu d’afegir-hi les següents:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.0.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
        </dependency>

A més, aprofitareu per fer servir la codificació UTF8 en tot el projecte afegint la propietat que defineix aquesta característica en el mateix fitxer pom.xml:

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

Arquitectura i procés bàsic d'una aplicació Spring MVC

Des que un navegador fa una petició al servidor d’aplicacions, per exemple Glassfish, fins que el servidor construeix la resposta i retorna al navegador, el flux de l’aplicació és el que es mostra en la figura.

Figura Arquitectura i procés d’una petició amb Spring MVC

A continuació es descriu la seqüència del procés petició-resposta.

  1. El navegador demana (petició) un recurs a l’aplicació web.
  2. El Front Controller o Dispatcher Servlet, implementat com un servlet, intercepta la petició i la delega al controlador adient, que ha de gestionar (handler) aquesta petició. Com veurem més endavant, la determinació del controlador adient es fa mitjançant la configuració dels Handler Mappings.
  3. El controlador processa la petició i retorna al Front Controller el model i la vista. Aquest retorn es fa amb un objecte del tipus ModelAndView.
  4. El Front Controller resol la vista actual (per exemple, un jsp) consultant l’objecte ViewResolver.
  5. La vista seleccionada és retornada com a resposta al navegador que va fer la petició.

Front Controller

Front Controller és un patró de disseny que proposa la centralització de la gestió de les peticions i respostes. Cerqueu “front controller java enterprise edition” i trobareu documentació d’Oracle sobre aquest tema.

Web Application Context

Desplegar una aplicació Spring al servidor d’aplicacions, per exemple a Glassfish, és com si l’aplicació s’estigués executant en segon pla dins del servidor.

Els objectes de la nostra aplicació desplegada resideixen en contenidors.

Per a tota l’aplicació hi ha un contenidor arrel anomenat Application Context que conté els objectes definits al fitxer de configuració anomenat applicationContext.xml.

El nom del fitxer de configuració per a Application Context es pot canviar a web.xml, com mostra l’exemple següent.

<context-param>
  <param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/rootApplicationContext.xml</param-value>
</context-param>

Per a cada Dispatcher Servlet es crearà un contenidor específic anomenat Web Application Context. Per defecte, el seu fitxer de configuració s’anomena xxx-servlet.xml, on “xxx” és el nom del Dispatcher Servlet.

El nom del fitxer per a Web Application Context es configura al mateix web.xml. L’exemple següent mostra com es configura un Dispatcher Servlet amb nom Dispatcher Servlet i amb fitxer de configuració /WEB-INF/spring/DispatcherServlet-servlet.xml.

<servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/DispatcherServlet-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
</servlet>

Com es veurà més endavant, els fitxers de configuració de context, tant el de tota l’aplicació com els específics de cada Dispatcher Servlet, defineixen els objectes que es crearan al contenidor. La diferència és que els objectes a nivell d’aplicació es poder fer servir des de qualsevol contenidor, i els de nivell de Dispatcher Servlet, únicament des d’objectes del mateix contenidor. A més, els del contenidor a nivell d’aplicació poden fer servir qualsevol objecte de qualsevol contenidor específic, tal com es vol reflectir a la figura.

Figura Visibilitat d’objectes segons els nivells

En aquests fitxers de configuració es defineixen quins objectes formaran part del contenidor, tant si són propis de l’aplicació com si són proporcionats per Spring o Java Enterprise Edition. Aquests objectes s’anomenen Spring-managed beans o simplement beans, i els farem servir al nostre codi declarant-los mitjançant anotacions, és a dir, no els instanciarem, perquè farem servir els objectes del contenidor. Per això es diu que l’objecte s’injecta quan es necessita i podem fer-lo servir (injecció de dependències o inversió de control)

Quan es dissenya una aplicació és important tenir en compte que els beans que defineixen la lògica de negoci, la interacció amb la persistència i altres interaccions s’han de compartir entre tots els servlets, i per això els definirem a nivell d’Application Context (el contenidor general) En canvi, els controladors que maneguen peticions, els View Resolvers i altres com alguns que gestionen missatges, els ubicarem a nivell de Web Application Context (els específics de cada Dispatcher Servlet).

Injecció de dependències

La injecció de dependències o inversió de control aconsegueix codi més desacoblat, ens facilita els tests i, a més, ens permetrà canviar bocins de codi de manera més fiable i ràpida.

Completant 'Hola, Món' amb l'arquitectura Spring MVC

Un cop sabeu com ha de ser el flux d’una aplicació Spring MVC i els components que ha de tenir, desenvolupeu les classes i la configuració que falten a la nostra aplicació “Hola, Món”.

En el vostre cas, deixareu que Spring agafi la configuració per defecte a nivell d’Application Context. Per això no creareu cap fitxer de configuració de l’Application Context (applicationContext.xml).

El que sí que hem de crear és la configuració del Web Application Context. Com només tindreu un Dispatcher Servlet amb el nom Dispatcher Servlet, podeu crear una nova carpeta de nom spring dins de WEB-INF i dins el fitxer DispatcherServlet.xml. El contingut és el que es mostra a continuació.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-4.0.xsd
                           http://www.springframework.org/schema/mvc
                           http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">


    <mvc:annotation-driven />
    <context:component-scan base-package="cat.xtec.ioc" />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

Amb <mvc:annotation-driven/> li diem a Spring MVC que farem servir els beans DefaultAnnotationHandlerMapping, AnnotationMethodHandlerAdapter i ExceptionHandlerExceptionResolver. Aquests beans són necessaris per enviar (dispatch) les peticions als controladors que les maneguen.

Com s’ha dit a la part d’arquitectura i procés de Spring MVC, el Dispatcher Servlet ha d’identificar quin és el controlador que manegarà la petició. Per fer això cercarà tots els objectes amb l’anotació @Controller dels paquets indicats en la propietat base-package de l’etiqueta context:component-scan.

La darrera etiqueta bean indica a Spring la creació d’un objecte bean a partir de la classe InternalResourceViewResolver. Un View Resolver ajuda el Dispatcher Servlet a construir la resposta a partir de determinada vista. Spring MVC proporciona diverses implementacions de View Resolvers, i InternalResourceViewResolver és una d’aquestes.

Per definir el nostre Front Controller afegiu el següent contingut al fitxer de configuració web.xml.

    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/DispatcherServlet-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

Fixeu-vos que es fa referència al fitxer de configuració DispatcherServlet-servlet.xml que hem creat. Podem canviar el nom del fitxer de configuració, però hauríeu de canviar-lo també aquí.

Continuant la compleció de la vostra aplicació seguint l’arquitectura i el model bàsic de Spring MVC, només resta crear el controlador que manegarà les peticions.

El Controlador és el responsable de processar les peticions, construir el model apropiat i passar-lo com a resposta a la vista que calgui.

Creeu el paquet cat.xtec.ioc i a dins la classe Java HolaController amb el contingut que es mostra a continuació.

package cat.xtec.ioc;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/")
public class HolaController {

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        ModelAndView modelview = new ModelAndView("resposta");
        modelview.getModelMap().addAttribute("salutacio", "Hola a tothom");
        return modelview;
    }

    @RequestMapping(value = "/bondia", method = RequestMethod.GET)
    public ModelAndView handleRequestDia(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        ModelAndView modelview = new ModelAndView("resposta");
        modelview.getModelMap().addAttribute("salutacio", "Bon dia a tothom");
        return modelview;
    }

    @RequestMapping(value = "/bonanit", method = RequestMethod.GET)
    public ModelAndView handleRequestNit(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        ModelAndView modelview = new ModelAndView("resposta");
        modelview.getModelMap().addAttribute("salutacio", "Bona nit a tothom");
        return modelview;
    }
}

L’anotació @Controller és molt bàsica, però suficient en aquesta implementació.

L’anotació @RequestMapping serveix per determinar l’origen de la petició i així poder decidir quin mètode manegarà el retorn. Com podeu veure, es pot fer a nivell de la classe o a nivell de mètode. Els paràmetres d’aquesta anotació els podeu consultar a la documentació de referència de Spring; en aquest cas hem fet servir el tipus de petició i l’URL.

Cada mètode encarregat (handler) de construir el retorn crea un nou objecte ModelAndView amb el nom de la vista que ha de retornar. Aquest nom, en combinació amb la configuració feta a DispatcherServlet-servlet.xml (InternalResourceViewResolver), serveix perquè Spring MVC determini exactament la vista (WEB-INF/views/resposta.jsp).

Als mètodes esmentats, abans de retornar la vista, s’afegeix un atribut al model (ModelMap) que en el nostre exemple serveix per provar diferents orígens a les peticions i veure diferents respostes.

Finalment, creeu la carpeta views dins de WEB-INF, i a dins el fitxer resposta.jsp amb el contingut que es mostra a continuació.

<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ca">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
    <title>Salutació</title>
  </head>
  <body>
    <section>
          <div class="jumbotron">
              <div class="container">
                  <h1>Salutació : ${salutacio} </h1>
              </div>
          </div>
      </section>
  </body>
</html>

En aquest cas, quan es mostri la vista al navegador, el valor de la variable salutacio canviarà en funció de l’URL de petició. Executeu l’aplicació sense més, i us ha de donar la salutació estàndard (vegeu la figura).

Figura Sortida de l’aplicació “Hola, Món” amb Spring MVC

Si al navegador canvieu l’URL afegint-hi /bondia o /bonanit, les salutacions canviaran. Proveu-ho.

Conclusions del nostre 'Hola, Món' Spring MVC

L’aplicació simple Hola, Món està creada a partir d’una petició des d’un URL al navegador mostra diferents missatges. L’estructura està feta amb Maven WebApp, però després hi ha les dependències necessàries per a J2EE i Spring MVC al fitxer pom.xml.

Una aplicació Spring MVC té una arquitectura de classes i un procés determinat. Tota petició és rebuda per un Front Controller (Dispatcher Servlet) configurat a web.xml. Aquest la dirigeix cap al controlador que realment la manegarà (handler), però en realitat és el controlador (HolaController, en el nostre exemple) qui mitjançant les anotacions agafarà les peticions, construirà un ModelAndView i el retornarà al Front Controller per tal que aquest el retorni al client (el navegador).

Per tal que tot funcioni correctament hem configurat la resolució dinàmica de les anotacions i la resolució de la vista efectiva mitjançant el fitxer DispatcherServlet-servlet.xml.

Estoc de medicaments, benvinguda

Desenvoluparem la pàgina d’inici (benvinguda) d’una aplicació per gestionar estocs de medicaments que anomenarem “stmedioc”. Crearem el projecte amb l’arquitectura d’una aplicació web basada en Spring MVC i amb la configuració basada en XML.

Configuració dels 'beans'

La configuració dels beans pot ser definida via fitxers de configuració XML, com applicationContext.xml i també via classes de configuració Java (JavaConfig).

Creació i configuració inicial del projecte Estoc de medicaments

És convenient fer servir el projecte anterior per consultar, però és millor anar construint el vostre propi projecte amb els indicacions que es van donant. No obstant això, si voleu executar el projecte sencer segurament us obliga a fer clean and build abans.

El codi del projecte “stmedioc” en l’estat d’aquest apartat es pot descarregar des de l’enllaç que trobareu als annexos de la unitat.

Creeu un nou projecte Maven/Project from Archetype amb l’arquetipus maven-archetype-webapp i anomeneu-lo “stmedioc101”.

Des de la pestanya Files de NetBeans o des del mateix explorador de fitxers del sistema operatiu, creeu la carpeta Java dins de la carpeta src/main. És important fer aquest pas, perquè veureu Source Packages a la pestanya de Projectes.

Canvieu el fitxer de configuració web.xml.

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                                 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name>Estoc de Medicaments</display-name>
</web-app>

A la secció Dependències de pom.xml heu d’afegir les següents dependències:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.0.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
        </dependency>

Afegiu la propietat que defineix la utilització de la codificació UTF-8 en el mateix fitxer pom.xml.

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

Executeu l’aplicació seleccionant el servidor Glassfish i fent que recordi aquesta decisió permanentment.

Pàgina de benvinguda

Creareu una pàgina de benvinguda per a la vostra aplicació consistent a mostrar un bàner però amb el procés de Spring MVC.

Per fer això haureu de crear la pàgina jsp, configurar el Dispatcher Servlet i crear el controlador per manegar la petició de benvinguda.

Creeu el fitxer DispatcherServlet-servlet.xml en una nova carpeta de nom spring dins de WEB-INF. El contingut és el que es mostra a continuació.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-4.0.xsd
                           http://www.springframework.org/schema/mvc
                           http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <mvc:annotation-driven />
    <context:component-scan base-package="cat.xtec.ioc.controller" />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

En aquesta configuració es podrien tenir més paquets en base-package simplement separant-los amb comes.

Definim el Dispatcher Servlet (Front Controller) afegint el següent contingut al fitxer de configuració web.xml:

    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/DispatcherServlet-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

Pel que fa al controlador que gestionarà les peticions, creeu el paquet cat.xtec.ioc.controller i a dins la classe Java HomeController amb el contingut que es mostra a continuació:

package cat.xtec.ioc.controller;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HomeController {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        ModelAndView modelview = new ModelAndView("welcome");
        modelview.getModelMap().addAttribute("benvinguda", "Benvingut Estoc de Medicaments!");
        modelview.getModelMap().addAttribute("tagline", "Una aplicació de l'Institut Obert de Catalunya");
        return modelview;
    }

}

Finalment, creeu la carpeta views dins de WEB-INF i a dins el fitxer welcome.jsp amb el contingut que es mostra a continuació.

<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ca">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
    <title>Welcome</title>
  </head>
<body>
  <section>
		<div class="jumbotron">
			<div class="container">
				<h1> ${benvinguda} </h1>
				<p> ${tagline} </p>
			</div>
		</div>
	</section>
</body>
</html>

En executar l’aplicació us ha d’aparèixer el bàner que es mostra en la figura.

Figura Sortida de l’aplicació. “Estoc de medicaments”, benvinguda

Ara ja teniu el projecte amb els elements i la configuració bàsica per continuar desenvolupant el vostre estoc de medicaments.

Què s'ha après?

En aquest apartat hem fet servir Maven com a eina que dóna estructura als projectes i permet baixar les llibreries que cal fer servir des de repositoris centrals a partir de la configuració de dependències. El gran avantatge de Maven és fer independent el nostre desenvolupament de l’IDE que es fa servir.

Hem introduït el procés petició-resposta de Spring MVC, així com a l’arquitectura que en dóna suport. Heu creat dues aplicacions Spring MVC amb la mateixa estructura, és a dir, una part de vistes .jsp, la configuració del Dispatcher Servlet (o Front Controller) i la classe que fa de controlador per manegar les peticions i que retorna l’objecte ModelAndView.

Les aplicacions fetes fins ara en aquesta unitat només mostren un text variable o no, encara que amb l’arquitectura de Spring MVC. Hem d’avançar una mica més i donar més funcionalitat a “Estoc de medicaments”.

En els apartats següents veurem com afegir aquesta funcionalitat de manera ordenada, creant els paquets i les classes amb els patrons que suggereix Spring MVC.

Anar a la pàgina anterior:
Referències
Anar a la pàgina següent:
Activitats