Anda di halaman 1dari 14

Ejemplo bsico de Spring MVC con Maven

Posted by : hop2croft | On : 10/09/2011


Category:Spring, Spring MVC
Tags:GitHub, i18n, Maven, Selenium, Spring, Spring MVC

En el siguiente post vamos a hablar un poco de Spring MVC. Pero antes comentar
que tengo pensado hacer una serie de post (el primero es este) sobre Spring. En
concreto intentar hablar un poco de proyecto de SpringSource como Spring
MVC, Spring Web Flow, Spring Security (O Auth) Spring Faces. Adems voy
a hablar un poco de desarrollo e integracin continua y pruebas
(Hudson / Jenkins, Sonar,Cobertura, Selenium, Checkstyles, PMD, ).
Tambin me gustara tratar temas de Cloud Computing , siempre como absoluto
novato en la materia, analizando herramientas como Google App Engine (GAE)
Micro Cloud Foundry. Pero para ello todava queda . as que empezar
con Spring MVC.
Introduccin a Spring MVC.
Spring MVC es un proyecto de Springsource que nos permite utilizar el patrn
MVC de una forma sencilla dentro de nuestras aplicaciones desarrolladas
conSpring. En la siguiente imagen vemos el esquema de cmo funciona Spring
MVC.

Si hemos realizado previamente desarrollo web podemos identificar claramente que
en Spring MVC, nuestro DispatcherServlet funciona bajo el patrn front
controller. El patrn front controller nos da un punto de entrada nico a
nuestras peticiones. De manera que todas ellas van a pasar por un mismo Servlet,
en el caso de Spring MVC, se trata de DispatcherServlet. Este Servlet se va a
encargar de gestionar toda la lgica en nuestra aplicacin.
El flujo bsico en una aplicacin bajo Spring MVC es el siguiente:
La peticin llega a nuestro DispatcherServlet (1)
El DispatcherServlet tendr que encontrar que controlador va a tratar la peticin.
Para ello el DispatcherServlet tiene que encontrar el manejador asociado a la url de
la peticin. Todo esto se realiza en la fase de HandlerMapping (2).
Una vez encontrado ese Controller, nuestro DispatcherServlet le dejar gestionar
a ste la peticin (3). En nuestro controlador se deber realizar todo la lgica de
negocio de nuestra aplicacin, es decir, aqu llamaremos a nuestra capa de
servicios. El controlador devolver al Dispatcher un objeto de
tipo ModelAndView (4). Qu quiere decir esto? En pocas palabras Model ser
los valores que obtengamos de nuestra capa de servicio y View ser el nombre de
la vista en la que queremos mostrar la informacin que va contenida dentro de ese
Model.
Una vez pasado este objeto ModelAndView al DispatcherServlet, ser ste el que
tendr que asociar el nombre de la vista retornada por el controlador a una vista
concreta (pgina jsp, jsf, ). Este proceso viene indicado en la imagen
como ViewResolver (4).
Finalmente y una vez resuelta la vista, nuestro DispatcherServlet tendr que pasar
nuestro Model (los valores recogidos en el controlador a travs de nuestra capa de
servicios) a la vista concreta View (5).
En los pasos de HandlerMapping, seleccin de Controller y ViewResolver
podemos indicarle a nuestro DispatcherServlet qu estrategia queremos seguir. Os
dejo una entrada del blog de Alex Fuentes donde explica de manera bastante
concisa los tipos de estrategias disponibles.
Proyecto de Spring MVC con Maven
Por qe utilizar GitHub?.
Bueno, el punto anterior era teora, vamos a ver un proyecto donde explicar las
clases Java y los ficheros de configuracin bsica para empezar con Spring MVC.
Como siempre los proyectos estarn gestionados con Maven (2.2.1). Como
novedad voy a subir el cdigo a GitHub, as quien quiera probar los ejemplos
simplemente tendr que acceder mi repositorio pblico en la siguiente direccin:
git@github.com:IvanFernandez/hop2croftRepository.git
Si no conoces todava Git, puedes empezar echando un vistazo a los siguientes
post:
Git como herramienta de control de versiones
Arquitectura de Git
GitHub , repositorio remoto de Git
Las razones por la que subo el cdigo a GitHub son varias. Por un lado creo que
facilita seguir el post tener todo el cdigo disponible y poder probarlo por uno
mismo. Adems, y personalmente no me gusta nada, cuando estoy leyendo un post
y veo que por ejemplo no estn incluidos los imports en el cdigo poner todo el
cdigo de un mtodo . Subiendo el cdigo a GitHub se puede escribir un post sin
necesidad de poner los imports slo parte de una clase (y no hacer un post
kilomtrico), pero a la vez la persona que lo est leyendo no se pierde. Finalmente
y se alguien se anima con GitHub se puede hacer un fork de los distintos
proyectos, aadir funcionalidad y que est a disposicin de todos.
Explicacin del cdigo
Yendo ya al proyecto concreto y para hacer ms claro una imagen general del
proyecto creo que es bueno poner una imagen con la estructura del proyecto vista
desde Eclipse.

Como podemos ver en la anterior imagen al estar creado nuestro proyecto con
Maven se ha creado la estructura tpica de un proyecto Maven, es decir:
Carpeta src/main/java
Aqu vamos a guardar nuestras clases Java. En concreto tenemos cuatro paquetes:
Controller. estar asociado a nuestros controladores. En nuestro caso vamos a
tener dos controladores. CarController que se ejecutar cuando se solicite la pgina
car.html y CarFormController que se ejecutar cuando se solicite carForm.html
Domain. nuestras clases de dominio. Vamos a utilizar una clase que modela un
coche, Car.java. Ya hemos visto en otros post los servicios para crear, modificar y
eliminar un coche (y por ende cualquier clase) en una base de datos.
Exception. en este paquete estarn las clases que tratarn las posibles
excepciones que se generen por nuestro codigo.
Interceptor. en este paquete tenemos los interceptores de Spring MVC. Los
interceptores sirven en Spring para tratar las peticiones y aadirles cierta lgica.
Services. las clases que llaman a nuestro servicio. En lugar de utilizar los servicios
implementados en otros post, por sencillez y sobre todo para no sobrecargar los
ficheros de configuracin vamos a hacer que nuestros servicios no vayan contra la
base de datos. As el servicio CarService va a devolver una lista fija indicada en la
propia clase.
Carpeta src/main/resources
En este paquete vamos a guardar los ficheros necesarios en nuestro proyecto.
Locale. Nuestra aplicacin va a escribir sus pginas jsp en el idioma que por
defecto que venga indicado en el navegador usado. Para ello habr una serie de
ficheros de propiedades nombrados como message*.properties. En estos ficheros
estarn declaradas una serie de cadenas de texto y su valor. Cuando la pgina se
pinte har uso de estos ficheros de propiedades para escribir el texto.
Spring. En esta carpeta tendremos nuestro fichero de contexto de la
aplicacin, applicationContext.xml. En este fichero simplemente vamos a cargar en
nuestro contexto la carpeta locale que acabamos de explicar.
view_es.properties. Este fichero todava no lo vamos a utilizar. La idea es utilizar
este fichero para hacer redirecciones en nuestros navegadores.
Carpeta src/main/test
De momento slo he creado una clase de test. Esta clase de test est realizada
usando el framework Selenium. Este test nos permite hacer pruebas de regresin,
es decir, nuestra clase de test abrir nuestro navegador y ejecutar una secuencia
de acciones (rellenar una caja de texto, pulsar un botn, irnos de una pgina a
otra, ). El siguiente post que escribir ser una pequea explicacin de como
empezar con Selenium.
Carpeta src/main/webapp/WEB-INF
Tenemos una serie de carpetas y ficheros de configuracin que vamos a explicar a
continuacin:
carpeta jsp. Aqu vamos a guardar nuestras pginas jsp. Por el momento vamos a
escribir nuestra parte de vista lo ms sencilla posible. Ms adelante quiz se utilice
otro framework como ZKoss alguna de las implementaciones de JSF.
carpeta spring. Dentro de esta carpeta tenemos el fichero car-service.xml. En
este fichero lo nico que vamos a hacer es crear un bean que usar la clase de
servicio CarService.
car-servlet.xml. Vamos a explicar el contenido de este fichero a continuacin.Este
fichero incluir en el contexto de nuestroDispatcherServlet una serie de beans. Lo
primero que vemos es que cargamos el fichero car-service.xml. De manera que en
el contexto de nuestro DispatcherServlet tendremos a nuestra disposicin un
beanCarService.
El siguiente fragmento nos permite entre otras cosas poder acceder a
nuestro carService desde nuestros controller utilizando para ello la
anotacin@Autowired.
1 <context:annotation-config />
El siguiente bean se encargar de mapear las peticiones hechas desde car.html con
el controlador implementado en la clase CarController. Para el resto de peticiones
utilizaremos el mapeo hecho directamente por la
clase ControllerClassNameHandlerMapping.

1
<beanclass="org.springframework.web.servlet.mvc.support.ControllerCla
ssNameHandlerMapping">
2
<property name="caseSensitive" value="true" />
3 </bean>
Como hemos visto las vistas tienen que resolverse en un paso intermedio entre la
llamada al controlador y la generacin de la vista. Para ello vamos a utilizar el
servlet InternalResourceViewResolver. Este servlet buscar las pginas con formato
jsp en la url /WEB-INF/jsp.
1 <bean
2
class="org.springframework.web.servlet.view.InternalResourceViewR
esolver">
3
<property name="prefix" value="/WEB-INF/jsp/"></property>
4
<property name="suffix" value=".jsp"></property>
5
<property name="order" value="1" />
6 </bean>
En la siguiente parte declaramos la parte de interceptores. Vamos a declarar un
interceptor en la clase TimeResponseInterceptor que simplemente aadir un valor
a nuestra peticin el tiempo que ha pasado desde que se inicia hasta que termina.
Este valor podr ser ms tarde usado por nuestra vista. Para usar nuestro
interceptor lo tenemos que declarar utilizando la clase
BeanNameUrlHandlerMapping para poderlo usar en nuestras peticiones.
1
<bean
id="timeResponseInterceptor"class="com.hopcroft.interceptor.TimeRespo
nseInterceptor"></bean>
2 <bean
3
class="org.springframework.web.servlet.handler.BeanNameUrlHandler
Mapping">
4 <property name="interceptors">
5 <list>
6 <ref bean="timeResponseInterceptor"></ref>
7 </list>
8 </property>
9 </bean>
Este bean lo utilizaremos para resolver las excepciones. Si salta una exception de tipo
CarException se mostrar la pgina indicada, en este caso carsNotAvailable. Si se genera una
excepcin de java.lang se mostar la pgina error.jsp. Dentro de esta pgina podremos acceder a
la excepcin usando ${exception}.

1
<bean class="org.springframework.web.servlet.handler.SimpleMappingExc
eptionResolver">
2
<property name="exceptionMappings">
3 <props>
4
<propkey="com.hopcroft.exception.CarException">carsNotAva
ilable</prop>
5
<prop key="java.lang.Exception">error</prop>
6 </props>
7 </property>
8 </bean>
Finalmente el siguiente bean se encargar de gestionar un formulario para crear
nuevos coches. En lugar de inyectar el carService con @Autowired en la clase
CarFormController la pasaremos como referencia en nuestro bean. La vista de
formulario ser carForm y la vista cuando se haga el submit ser carInsertSuccess.
1
<bean id="carFormController"class="com.hopcroft.controller.CarFormCon
troller">
2
<property name="carService" ref="carService"></property>
3
<property name="formView" value="carForm"></property>
4
<property name="successView" value="carInsertSuccess"></property>
5 </bean>
web.xml. Este ser el fichero de despliegue de nuestra aplicacin. Aqu haremos lo
siguiente:
o Cargamos el fichero de contexto de nuestra aplicacin.
1 <context-param>
2 <param-name>contextConfigLocation</param-name>
3
<param-value>classpath*:spring/applicationContext.xml</param-
value>
4 </context-param>
5 <listener>
6
<listener-
class>org.springframework.web.context.ContextLoaderListener</listener
-class>
7 </listener>
o Anotamos nuestro DispatcherServlet indicaremos el formato de las peticiones al
mismo.
1 <servlet>
2 <servlet-name>car</servlet-name>
3
<servlet-
class>org.springframework.web.servlet.DispatcherServlet</servlet-
class>
4 <load-on-startup>1</load-on-startup>
5 </servlet>
6

7 <servlet-mapping>
8 <servlet-name>car</servlet-name>
9 <url-pattern>*.html</url-pattern>
10 </servlet-mapping>
o
o
Ejecutar el proyecto
Hemos agregado el plug-in de Jetty para poder probar la aplicacin sin necesidad
de tener un contenedor web aparte en nuestro equipo. Por lo tanto nos vamos a la
raz de nuestro proyecto y ejecutamos desde consola:

1
mvn clean install -DskipTests
2 mvn jetty:run
Ahora tendremos que hacer una peticin a las dos pginas principales que tenemos
en nuestra aplicacin.
o http://localhost:9080/spring-mvc/car.html El Dispatchertransladar la
peticin a nuestro controlador CarController. La lgica de nuestro CarControllerser
bastante sencilla.
1
public class CarServiceImpl implements CarService {
2
public CarServiceImpl() {
3 }
4

5
public List<Car> getCars() throws CarException {
6 List<Car> cars = initCars();
7
if ((Calendar.getInstance().getTimeInMillis() % 2) ==0) {
8
return cars;
9
} else if ((Calendar.getInstance().getTimeInMillis() % 2)
== 0) {
10
throw new CarException(1L, "Car service ", newDate());
11 } else
12
throw new RuntimeException();
13 }
14

15 // TODO: llamar al DAO de car.
16
private List<Car> initCars() {
17
List<Car> carList = new ArrayList<Car>();
18
Car car = new Car();
19 car.setBrand("Ferrari");
20 car.setName("F40");
21 car.setPrice(1000000L);
22
23
Car car2 = new Car();
24 car2.setBrand("Porsche");
25 car2.setName("Carrera");
26 car2.setPrice(200000L);
27
28
Car car3 = new Car();
29 car3.setBrand("Opel");
30 car3.setName("Astra");
31 car3.setPrice(18000L);
32

33 carList.add(car);
34 carList.add(car2);
35 carList.add(car3);
36

37
return carList;
38 }
o
CarController solicitar una lista de coches al servicio carService. En funcin de a
que hora se solicite el servicio nuestroCarControllerdevolver:
o Una lista de coches que recoger del servicio CarService.
o
o Una excepcin CarException. Como hemos visto en el anteriormente las
excepciones de este tipo tendrn su propia pgina jsp carsNotAvailabledonde
devolveremos la respuesta.
o
o Una excepcin genrica java.lang.Exception que estar asociada a la pgina error
o
o http://localhost:9080/spring-mvc/carForm.html. Tendremos un formulario
generado con Spring MVC. La parte ms interesante est en como podemos
asociar un objeto de dominio a un formulario para que sea Spring MVC el que te
genere automticamente un campo porque cada atributo del objeto de
dominio, Caren nuestro caso.
1
public class CarFormController extends SimpleFormController {
2

3
public CarFormController() {
4 setCommandClass(Car.class);
5 setCommandName("carInsert");
6 }


Esto es todo en este post, espero que os sea de ayuda para entender y comenzar
con Spring MVC.



















MVC en Spring
En el siguiente apartado voy a detallar como esta implementado el patron Model-View-Controller sobre Spring framework.
Como la mayoria de los framework que implementan el patron MVC, Spring tiene implementado un servlet que realiza las tareas
de Front Controller, esto significa que cada uno de los request que son realizados por el usuario, pasan a traves de este servlet.
El nombre que recibe este servlet es Dispatcher Servlet. Y como indicamos anteriormente, todos los request que son realizados
por los distintos usuarios pasan por este componente. Como la imagen lo indica el Request llegan al Dispatcher el cual tiene la
responsabilidad de delegar a otro componente el procesamiento del request.
Para obtener el nombre del componente que recibira el request , Spring utiliza lo que se denomina el Handler Mapping , el cual
tiene la funcion de determinar cual sera el Controller que recibira
el request.
El Handler Mapping como indicamos tiene el objetivo de indicar al
dispatcher
cual sera el componente que debe recibir el request enviado por
el usuario.
Por lo cual el Dispatcher Servlet , le pregunta a uno o mas
Handler Mapping
cual sera le Controller que recivira el Request.
Dentro del Spring existe varios Handler Mapping los cuales tiene distintas
capacidades de poder mapear a los controladores.
En el siguiente cuadro se indican los Handler Mapping que posee Spring.
Handler Mapping Como mapea el Request
BeanNameUrlHandlerMapping
Mapea controladores a URL basandose en
el nombre del Bean
SimpleUrlHandlerMapping
Mapea controladores a URL basandose en
una collecion de propiedades que se definen
en el Spring application context.
ControllerClassNameHandlerMapping
Mapea controladores a URL utilizando el
Controller Class Name
CommonsPathMapHandlerMapping Mapea controladores a URL usando
metadatas en el codigo del controlador. Esta
metadata es definida usando Jakarta
Commons Atributes.
Luego de que el Handler Mapping le entrega nombre del Controller que se hara cargo del Request , el Distpacher Servlet le
envia el
request al Controller.Para poder implementar un Controller sobre Spring es necesario que se cree una clase que herede de los
Controller que han sido implementados por Spring, los cuales dependiendo de la funcionalidad a realizar es el Controller que se
debera utilizar. En el siguiente cuadro se puede ver que tipos de Controller estan disponibles sobre Spring.

Controller type Classes Usarlo cuando ...
View
ParameterizableViewController
UrlFilenameViewController
Para cuando un
controlador solo necesita
desplegar informacin
Simple
Controller (interface)
AbstractController
Para controladores
simples que solo se
utilizan como Simples
Servlet
Throwaway ThrowawayController
Para manejar los request
como un Comando
Multiaction MultiActionController Para implementar una
serie de acciones con
similar lgica
Command BaseCommandController
AbstractCommandController
Si tus controladores
reciben parmetros estos
son manejados dentro de
un objeto
Form AbstractFormController
SimpleFormController
Para desplegar y procesar
un formulario, bajo el
mismo componente
Wizard AbstractWizardFormController Para realizar una
interaccin ms rica con el
usuario a travs de varias
pantallas

Luego que el Controller recibe el Request , se construye un Objeto que se denomina ModelAndView ,este componente tiene
como funcion la de :
1- Entregar un nombre logica a la vista que debera realizar el despliegue del Model
2- Entregar un nombre logico al Model que esta asociado a este componente
3- Inyectar el objeto Model el cual tiene los datos que seran desplegados en la Vista.
Luego que el objeto ModelAndView es regresado al dispatcher y este componente delega la responsabilidad de la mapping del
nombre logico de la vista, con el componente a utilizar al ViewResolver.El ViewResolver es el encargado de realizar el mapping
entre el nombre logico de la vista y el componente. En el siguiente cuadro se indican los ViewResolver disponibles a ser
configurados sobre Spring.
View Resolver Como trabaja....
InternalResourceViewResolver Resuelve el nombre logico utilizando el mapping a velocity y JSP
BeanNameViewResolver Resuleve el nombre logico utilizando Bean definidos en el Spring Context
ResourceBundleViewResolver Define el mapping entre los nombres logicos y las vistas asociadas , definiendolo en un archivo
de propiedades
XmlViewResolver Define el mapping entre los nombres logicos y las vistas asociadas , definiendolo en un archivo
XML

Anda mungkin juga menyukai