jueves, 21 de octubre de 2010

Reemplazar textos con Maven

En el trabajo he tenido que mostrar la versión actual del producto en el footer de la página.

Lo normal en este caso creo que sería tener un fichero de propiedades en algún sitio de la aplicación y desde el footer.jsp mostrar el valor de esa propiedad. Para que cuando generamos el war de la aplicación automaticamente en ese .properties aparezca la versión utilizada en el pom.xml nos podemos valer fácilmente de:




src/main/resources

**/*.properties
**/*.xml
**/*.xmls
**/*.sql

true




Y dentro del fichero .properties tener una propiedad que sea "version=${pom.version}".

Pero la verdad es que no lo he hecho así. Me ha dado pereza crearme un fichero de propiedades sólo para mostrar la versión.

¿Por qué no se puede hacer el filtering de los resources sobre todas las jsps? Indicándole que el sería "src/main/java/WEB-INF/jsp". Así lo pensé yo y cuando se me generó el war y lo desplegué me llevé una desagradable sorpresa.

En las jsps estabamos utilizando expresiones EL, que tienen la misma nomenclatura que las variables de maven: ${...}. Y al realizar el filtering de Maven, se me estaba modificando el valor de algunas variables EL.

Debo reconocer que llegado a este punto debería haber vuelto a la idea inicial, pero siguió dándome pereza e intenté investigar otra forma de realizar sustituciones de tokens concretos y llegué a este interesante plugin: maven-replacer-plugin.

En footer.jsp puse el siguiente código:

version: PROJECT_VERSION

y en maven configuré el plugin:




com.google.code.maven-replacer-plugin
maven-replacer-plugin
1.3.2



project_version

prepare-package

replace




target/${project.artifactId}-${project.version}/WEB-INF/**/*.jsp

false

PROJECT_VERSION

${pom.version}







De esta forma le indicamos que busque en las jsps el token exacto 'PROJECT_VERSION'.

Sólo hay que tener en cuenta una cosa más para que esto funcione. en el momento en el que se ejecuta este plugin el directorio de la aplicación todavía no se encuentra en el directorio target, por lo que no se realiza bien el replace si se ejecuta la tarea 'mvn clean package'. Es necesario ejecutar 'mvn clean war:exploded package'

lunes, 18 de octubre de 2010

Integración Spring MVC con Tiles

En el siguiente post voy a explicar los pasos necesarios para realizar una integración sencilla de Spring MVC con Tiles.

El objetivo de esta integración es que automáticamente se aplique una plantilla a una vista sin necesidad de que se tenga que definir en el fichero tiles-def.xml cada vez. Dependiendo de la url con la que se invoque a la aplicación se ejecutará una u otra-

Por ejemplo:
- http://server/appname/player/home --> Cómo la url empieza por /player automáticamente cogerá la plantilla de tiles para los jugadores
- http://server/appname/crm/home --> Cómo la url empieza por /crm automáticamente cogerá la plantilla de tiles para los usuarios del CRM.

Para hacer esto me he basado en el siguiente tutorial: Spring by Example's Dynamic Tiles 2 Spring MVC Module. Recomiendo la lectura de este enlace, ya que voy a extender la funcionalidad que se explica ahí.

Lo primero que tenemos que hacer es importar las librerías necesarias mediante Maven:



springbyexample.org
Spring by Example
http://www.springbyexample.org/maven/repo


....


org.apache.tiles
tiles-core
2.2.1


org.apache.tiles
tiles-jsp
2.2.1


org.apache.tiles
tiles-servlet
2.2.1


org.apache.tiles
tiles-servlet-wildcard
2.2.1


org.apache.tiles
tiles-el
2.2.1


org.springbyexample
org.springbyexample.dynamic.tiles2
1.2


org.springframework
org.springframework.beans


org.springframework
org.springframework.web


org.springframework
org.springframework.context


org.springframework
org.springframework.context.support


org.springframework.webflow
org.springframework.webflow


org.apache.tiles
com.springsource.org.apache.tiles.core


org.apache.commons
com.springsource.org.apache.commons.digester


org.apache.commons
com.springsource.org.apache.commons.beanutils


org.apache.commons
com.springsource.org.apache.commons.logging


org.apache.tiles
com.springsource.org.apache.tiles


org.springframework
org.springframework.core


org.springframework
org.springframework.web.servlet


org.springframework.webflow
org.springframework.js





Después de esto hay que definir en los ficheros de configuración de Spring para que se cojan las definiciones de tiles de su fichero correspondiente:



class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">


/WEB-INF/tiles-def.xml





Dentro de este fichero 'tiles-def.xml' configuramos las dos plantillas que queremos utilizar:



"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://tiles.apache.org/dtds/tiles-config_2_0.dtd">

























Vamos a crear una nueva clase en nuestro proyecto que extienda la funcionalidad que nos proporciona 'springbyexample'. En este caso vamos a prepararlo para que dependiendo de la ruta de la vista a la que vayamos a llamar se invoque a una plantilla o a la otra. La clase en cuestión es la siguiente:



public class ViewNameStartTilesUrlBasedViewResolver extends org.springbyexample.web.servlet.view.tiles2.TilesUrlBasedViewResolver{

private String viewNameStartsWith = "";

@Override
protected boolean canHandle(String viewName, Locale locale) {
if (viewName.startsWith(viewNameStartsWith)){
return super.canHandle(viewName, locale);
}
return false;
}

public void setViewNameStartsWith(String viewNameStartsWith) {
this.viewNameStartsWith = viewNameStartsWith;
}

}



Después definimos dos beans en Spring que se encarguen de evaluar si se tiene que ejecutar una plantilla o la otra.



class="com.example.ViewNameStartTilesUrlBasedViewResolver">
value="org.springbyexample.web.servlet.view.tiles2.DynamicTilesView">








class="com.example.ViewNameStartTilesUrlBasedViewResolver">
value="org.springbyexample.web.servlet.view.tiles2.DynamicTilesView">










Tal y como hemos configurado esto, cada vez que Spring devuelva una vista, se ejecutará primero la comprobación de si la vista empieza por "player/". En caso de que así sea se ejecutará la plantilla '.playerMainTemplate'. Si no es así se evaluará a ver si empieza por 'crm/' y se ejecutaría su plantilla correspondiente.

Otra cosa a tener en cuenta es donde se tiene que encontrar la jsp para que la vista se ejecute correctamente. Si Spring MVC devuelve una vista con valor 'player/account/home', se buscará una jsp en la ruta: 'WEB-INF/jsp/player/account/home.jsp' automáticamente, sin necesidad de que lo definamos nosotros en tiles-def.xml.