Ejemplo básico con Spring MVC Portlet
0. Índice de
contenidos.
- 1. Entorno
- 2. Introducción
- 3. Creando el proyecto con Maven
- 4. Configurando las dependencias del proyecto
- 5. Configurando el
web.xml - 6. Configurando el applicationContext.xml
- 7. Configurando el portlet.xml
- 8. Configurando el spring-mvc-prueba-portlet.xml
- 9. Creando la clase controladora
- 10. Creando la vista por defecto (view.jsp)
- 11. Configurando el portlet para hacerlo funcionar
en Liferay
- 12. Desplegando el portlet en Liferay
- 13. Conclusiones
1. Entorno
Este tutorial está escrito usando el siguiente entorno:
- Hardware: Portátil Mac Book Pro 17″ (2,6 Ghz Intel Core
i7, 8 GB
DDR3) - Sistema Operativo: Mac OS X Snow Leopard 10.6.4
- Spring MVC Portlet 3.0.4
- Maven 2.2.1
- Eclipse 3.6 (Helios) con M2Eclipse
- Liferay 6.0.5
2. Introducción
En este tutorial vamos a ver paso a paso cómo crear un portlet
muy básico con la ayuda de Spring MVC Portlet, desde su
creación con Maven hasta su despliegue en Liferay.
Servirá como base para la creación de portlets más
complejos utilizando esta tecnología.
3. Creando el proyecto con Maven
En este tipo de proyectos en los que vamos a utilizar librerías
de
terceros como Spring, se hace especialmente útil la
utililización de
una herramienta de gestión de dependencias como Maven. Teniendo
Maven
ya instalado en nuestra máquina lo único que tenemos que
hacer es abrir
un terminal y situarnos en el directorio donde vayamos a crear el
proyecto de tipo web con el siguiente comando:
1 |
mvn archetype:create -DgroupId=com.autentia -DartifactId=spring-mvc-portlet-prueba -DarchetypeId=maven-archetype-webapp |
NOTA: para los usuarios de Liferay, existe un arquetipo que crea el
proyecto con el ficheros necesarios de despliegue para Liferay. En este
caso el comando sería:
1 |
mvn archetype:create -DgroupId=com.adictos.portlet -DartifactId=maven-portlet -DarchetypeArtifactId=liferay-portlet-archetype -DarchetypeGroupId=com.liferay.maven.archetypes -DarchetypeVersion=6.0.5 |
Podréis encontrar más detalles en este tutorial: http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=mavenliferay
4. Configurando las dependencias del proyecto
Con el fin de que la edición del proyecto sea más
cómoda podemos
importarlo a un IDE como Eclipse. Para hacer esto, contamos con el
plugin M2Eclipse que es la evolución del conocido EclipseIAM.
Para configurar las dependencias editamos el fichero pom.xml del
proyecto, añadiendo las siguientes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc-portlet</artifactId> <version>3.0.4.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javax.portlet</groupId> <artifactId>portlet-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> |
La librería portlet-api tiene el scope a provided porque es
necesaria
para compilar el proyecto, pero debe ser proporcionada por el gestor de
portales donde vayamos a desplegar nuestro proyecto. Utilizamos una
versión a partir de la 3.0.x para poder hacer uso del
estándar JSR-286 o más conocido como Portlet 2.0.
5. Configurando el web.xml
Ahora tenemos que editar el fichero web.xml de nuestro proyecto para
intregar nuestro desarrollo con Spring MVC Portlet, de tal modo que
tenemos que añadir los siguientes elementos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>spring-mvc-prueba-portlet</display-name> <!-- Define la localización de los ficheros de configuración de Spring --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/context/applicationContext.xml</param-value> </context-param> <!-- Listener de Contexto --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Servlet de Spring MVC Portlet --> <servlet> <servlet-name>ViewRendererServlet</servlet-name> <servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>ViewRendererServlet</servlet-name> <url-pattern>/WEB-INF/servlet/view</url-pattern> </servlet-mapping> </web-app> |
En primer lugar definimos el parámetro contextConfigLocation
para
establecer donde vamos a almacenar el fichero de configuración
de
Spring de nuestro proyecto, en este caso será dentro de la
carpeta
WEB-INF/context con el nombre applicationContext.xml. Luego tenemos que
crear
el listener y el servlet necesarios para trabajar con Spring MVC.
6. Configurando el applicationContext.xml
Si no lo hemos hecho, ya este es un buen momento para instalar el
plugin Spring IDE en nuestro Eclipse, ya que nos va a facilitar la
tediosa tarea de tener que generar los encabezados de los ficheros de
configuración de Spring.
Creamos el fichero WEB-INF/applicationContext.xml donde vamos a
determinar el comportamiento de Spring dentro de nuestro proyecto. Para
ello añadimos el siguiente contenido:
1 2 3 4 5 6 7 8 9 10 11 12 |
<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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" default-autowire="byName"> <!-- Para que Spring sepa que vamos a usar anotaciones --> <context:annotation-config /> <!-- Desde donde tiene que escanear --> <context:component-scan base-package="com.autentia.springmvcpruebaportlet" /> </beans> |
Estamos determinando que vamos a utilizar anotaciones y que Spring
tiene que comenzar a escanear cuando tenga que localizar un bean, a
partir de la ruta del paquete que establezcamos en el valor
base-package.
7. Configurando el portlet.xml
La gente que ya está acostumbrada al desarrollo de portlet ya
sabe que en este fichero se definen las características de
nuestro portlet: cuál es su ID, que modos de trabajo va a tener,
cuál va a ser el fichero de internacionalización, … y
sobre todo que clase se va a encargar de implementar la lógica
del portlet.
Pues bien, en este caso, todo va a ser igual, sólo que la clase
encargada de implementar el portlet siempre va a ser la misma
org.springframework.web.portlet.DispatcherPortlet que requiere la
inicialización del parámetro contextConfigurationLocation
con la ruta del fichero de Spring que se va a encargar de manejar
nuestro portlet. Este es un posible código de ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<portlet-app version="2.0" xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"> <portlet> <portlet-name>spring-mvc-prueba-portlet</portlet-name> <display-name>spring-mvc-prueba-portlet</display-name> <portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class> <init-param> <name>contextConfigLocation</name> <value>/WEB-INF/context/portlet/spring-mvc-prueba-portlet.xml</value> </init-param> <expiration-cache>0</expiration-cache> <supports> <mime-type>text/html</mime-type> </supports> <portlet-info> <title>spring-mvc-prueba-portlet</title> <short-title>spring-mvc-prueba-portlet</short-title> <keywords>spring-mvc-prueba-portlet</keywords> </portlet-info> </portlet> </portlet-app> |
8. Configurando el spring-mvc-prueba-portlet.xml
Ahora tenemos que crear el fichero de configuración de Spring
para nuestro portlet. La información más importante de
este fichero es qué controlador se va a encargar de manejar las
peticiones y cómo se va a mostrar la vista. En este caso vamos a
tener un controlador para todas las peticiones que se realicen en el
estado de la vista del portlet y vamos a mostrar el contenido a
través de páginas JSP.
Estas definiciones se corresponden con el siguiente contenido:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="portletModeHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeHandlerMapping"> <property name="portletModeMap"> <map> <entry key="view" value-ref="springMVCPruebaPortletViewController" /> </map> </property> </bean> <!-- Default View Resolver --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="cache" value="false" /> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/jsp/spring-mvc-prueba-portlet/" /> <property name="suffix" value=".jsp" /> </bean> </beans> |
9. Creando la clase controladora
Para la creación del controlador utilizamos la convención
frente a la configuración por lo que vamos a crear una clase
controladora del mismo nombre (salvo empezando por mayúsculas)
que el id del bean referenciado en la entrada key=»view».
Por lo tanto vamos a crear la clase
SpringMVCPruebaPortletViewController dentro de un paquete que este en
el alcance del escaneado de Spring, por ejemplo,
com.autentia.springmvcpruebaportlet.controllers con el siguiente
contenido:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.autentia.springmvcpruebaportlet.controllers; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("VIEW") public class SpringMVCPruebaPortletViewController { public SpringMVCPruebaPortletViewController() { } @RequestMapping protected String defaultView() { return "view"; } } |
Este es el contenido mínimo que tiene que tener nuestro
controlador. Con la anotación @Controller estamos definiendo que
es un controlador manejado por Spring y por tanto implícitamente
estamos creando el bean asociado dentro de nuestro fichero de
configuración. Con la anotación @RequestMapping(«VIEW»)
estamos estableciendo que este controlador se va a encargar de la vista
del portlet y con la anotación @RequestMapping sin ningún
parámetro adicional estamos estableciendo que ese método
es el que se va a ejecutar por defecto.
En Spring MVC Portlet, tenemos que dintiguir dos tipos de
métodos: lo que devuelven String y los que no devuelven nada
(void). Los del primer caso se corresponden con métodos Render
donde el String que devuelven le indica a Spring que tiene que buscar
un .jsp dentro de la carpeta establecida con ese nombre, para mostrarlo
en la vista del portlet. Los del segundo caso se corresponden con
métodos Action que reciben las peticiones del usuarios, ejecutan
la lógica asociada y establecen que método Render va a
ser el siguiente a ejecutar, en caso de no establecer ninguno, se
ejecutaría el de por defecto, anotado con @RequesMapping sin
parámetros adicionales.
10. Creando la vista por defecto (view.jsp)
Como se puede ver en el código anterior estamos definiendo que
la vista por defecto muestre el fichero view.jsp. Por tanto tenemos que
crear este fichero dentro de la ruta configurado en el ViewResolver de
nuestro portlet con el siguiente contenido, por ejemplo:
1 2 3 4 5 |
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %> <portlet:defineObjects /> This is the <b>spring-mvc-prueba-portlet</b>. |
11. Configurando el portlet para hacerlo
funcionar en Liferay
Hasta este punto nuestro desarrollo es perfectamente portable a
cualquier gestor de portales que queramos utilizar (a no ser que se
haya utilizado el arquetipo de Liferay definido en el punto 3, en cuyo
caso podemos obviar este punto).
Para hacer funcionar nuestro desarrollo en Liferay tenemos que crear
los siguientes ficheros de configuración dentro de la carpeta
WEB-INF de nuestro proyecto:
liferay-display.xml: que define la categoría del árbol de
portlets donde vamos a encontrarlo a la hora de instanciarlo en una
página. Este es un contenido de ejemplo:
1 2 3 4 5 6 7 |
<!DOCTYPE display PUBLIC "-//Liferay//DTD Display 6.0.0//EN" "http://www.liferay.com/dtd/liferay-display_6_0_0.dtd"> <display> <category name="category.sample"> <portlet id="spring-mvc-prueba-portlet" /> </category> </display> |
liferay-portlet.xml que le da información extra de
características sólo aplicables a Liferay como si va a
llevar un icono, si va a ser instanciable, que ficheros CSS y
Javascript tiene que cargar, …
1 2 3 4 5 6 7 8 9 10 11 |
<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 6.0.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_6_0_0.dtd"> <liferay-portlet-app> <portlet> <portlet-name>spring-mvc-prueba-portlet</portlet-name> <icon>/icon.png</icon> <instanceable>true</instanceable> <header-portlet-css>/css/main.css</header-portlet-css> <footer-portlet-javascript>/js/main.js</footer-portlet-javascript> </portlet> </liferay-portlet-app> |
liferay-plugin-package.properties: que determina información del
tipo autoría del plugin, versión, compatibilidad con
otras versiones, etc …
1 2 3 4 5 6 7 8 9 |
name=spring-mvc-prueba-portlet module-group-id=liferay module-incremental-version=1 tags= short-description= change-log= page-url=http://www.liferay.com author=Liferay, Inc. licenses=LGPL |
12. Desplegando el portlet en Liferay
Para probar el resultado en Liferay basta con empaquetar nuestro
desarrollo a través del plugin de Eclipse o a través del
terminal, ejecutando dentro de la carpeta del proyecto el comando:
1 |
mvn clean package |
Y ahora trasladar el .war resultante a la carpeta deploy de nuestro
Liferay. En caso de que esté en ejecución el despliegue
se realizará en caliente y ya podremos instanciar nuestro con
Spring MVC dentro de la página que queramos.
Los que estén utilizando el arquetipo de Maven para Liferay, se
pueden ahorrar este paso ejecutando el siguiente comando por el terminal:
1 |
mvn liferay:deploy |
Pero es muy importante indicar que esto sólo hace el traslado
del .war a la carpeta que le indicamos en la propiedad
<liferay.auto.deploy.dir> del pom.xml y que no generá el
empaquetado, por lo que antes de ejecutarlo, siempre hay que hacer, un
empaquetado para que se despliegue la última versión del
plugin.
13. Conclusiones
Cómo véis no es díficil crear un portlet con
Spring MVC y las ventajas que nos reporta van a ser muchas. Por
ejemplo, nos facilita la navegación cuando nuestro portlet tiene
muchas pantallas, nos permite hacer pruebas unitarias de nuestros
controladores a través de Mocks, implementación de
validadores y buena forma de desacoplar nuestros desarrollos del gestor
de portales. Pero esto lo iremos viendo en sucesivos tutoriales, donde
crearemos un portlet para la gestión CRUD de una entidad
utilizando Spring MVC Portlet e iremos viendo otras anotaciones
fundamentales y técnicas necesarias.
Saludos.
Hola rubenagui, gracias por contestar.
El proyecto simplemente no tiene naturaleza Web segun eclipse y por lo tanto no lo puedo añadir a mi servidor, por supuesto es ejecutado el comando mvn eclipse:eclipse. Incluso he mirado los ficheros de configuracion del proyecto que genera eclipse y dice que es natuleza Web. Y he probado en varios eclipse distintos.
Muy interesante Rubén!
Hola Rubén,
por tu experiencia en el desarrollo de portlets para liferay 6, dirias que Spring MVC es la mejor opcion frente a otras como jsf, vaadin, etc?
Gracias y un saludo!
Hola davijim,
Mi experiencia es que Spring MVC Portlet es el framework que mejor se adapta al ciclo de vida de un portlet, y que lo trata como lo que es, la parte de la vista en una aplicación MVC. Es mucho más artesanal.
De las otras dos alternativas que planteas, he hecho pruebas con Vaadin y para ahorrarte el trabajar directamente con GWT está bien, pero no he pasado de \\\»Primer Portlet\\\».
El problema que plantea JSF dentro de un portlet, es que tiene que hacer uso de lo que se conoce como \\\»bridge\\\», he hecho pruebas con JSF 2.0 y no creas que han sido muy satisfactorias.
Espero que haya sido de utilidad.
Saludos.
Hola Ruben, primero felicitarte por tu gran aporte xke son muy pocos los que se encuentran en la web. Por otro parte tengo que aprender a desarrollar Porlets para Liferay usando Spring como Framework. Cree el proyecto usando Maven como esta descrito en el tutorial, pero tengo algunas dudad con respecto al archivo \\\»web.xml\\\» no me aparece en el proyecto. Otra cosa no se si pueda generar las clases de spring de una manera automatica o no se si me puedes explicar mejor. Mucgas Gracias!
Que pena ruben como tengo tu pagina guardada en Mozilla como pestaña al abrirla se repitieron los comentarios :$
La generacion del portlets es totalmente correcta, pero no soy capaz arrancarlo desde el entorno eclipse. ¿ Alguien sabe como hacerlo?
Hola Khain,
¿Puedes detallar el problema que te da Eclipse para arrancar el servidor?
Saludos.
Hola rubenagui, gracias por contestar.
Simplemente el proyecto generado por el comando:
Hola Khain,
Para solucionar el problema de no poder añadir el proyecto al servidor configurado dentro de Eclipse. La mejor solución es que instales el plugin M2Eclipse junto con sus extras. Es muy importante que instales los extras porque son los que tienen la integración con el WTP de Eclipse. Toda la información la puedes encontrar en esta URL: http://m2eclipse.sonatype.org/installing-m2eclipse.html
Espero que esto te ayude.
Saludos.
Hola!
En primer lugar felicitarte por el artículo, me es de gran utilidad.
Solo tengo un problema a la hora de arrancarlo en eclipse con Oracle Portal, me da el siguiente error:
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/context/applicationContext.xml]; nested exception is java.lang.NoSuchMethodError: getBeanDefinitionDefaults
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:375)
No se como solucionarlo, muchas gracias!
Despues de hacer el tutorial, volvi a empezar para ir pillando mecanica y en este paso me encuentro con esto:
09:19:24,378 ERROR [jsp:154] javax.portlet.PortletException: No adapter for hand
ler [com.autentia.springmvcpruebaportlet.controllers.SpringMVCPruebaPortletViewC
ontroller@1bb66df]: Does your handler implement a supported interface like Contr
oller?
Buenas,
Estoy buscando información de como securizar un portlet (para websphere) con spring, no encuentro información. Sabrias decirme que tengo que hacer?
Para una aplicación hay mucho información de spring-security, para un portlet no.
Saludos!!
Sergio