Novedades de la versión 0.0.7

Las novedades del arquetipo en su versión 0.0.7 se enumeran en los siguientes apartados.

La plantilla de diseño esta basada en Bootstrap 3.3. Los ficheros están en la ruta src/main/web_resources/resources del módulo Web. Donde están los ficheros de fuentes, JS, CSS, etc. que utiliza bootstrap.

Recordaros que en la carpeta src/main/web_resources es donde se ponen los ficheros JS, CSS, etc. que ya están minimizados y no queremos que pasen por el plugin Yui Compressor Maven Plugin, que tenemos configurado para el módulo Web. Que minimiza los ficheros JS y CSS para los entornos de pre-producción y producción.

Ahora vamos a describir el mecanismo de carga de estilos en la nueva plantilla.

  • bootstrap.min.css fichero con las clases de estilo de bootstrap.
  • font.css fichero con las fuentes de texto utilizadas en la parte web de la aplicación.
  • layout.css fichero con las clases de estilo que conforman el diseño de las páginas web.
  • layout_primefaces.css fichero con las clases de estilo que permiten solventar los conflictos con el CSS de PrimeFaces.
  • less.css fichero con las definiciones less para configurar estilos en la aplicación. Qué es LESS CSS y cómo funciona
  • custom.css fichero con las clases especificas para la aplicación.

Ordenación en la Carga de ficheros JS y CSS

En la nueva plantilla de la páginas (/layout/template.xhtml) se ha añadido un sistema de ordenación en la carga de recursos JS y CSS en la cabecera (<h:head>).

	<h:head>
		<f:facet name="first">
			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
			<meta http-equiv="X-UA-Compatible" content="IE=edge" />
			<meta name="viewport" content="width=device-width, initial-scale=1" />
			<title><h:outputText value="#{messages['application.title']}" /></title>
			<link rel="shortcut icon" href="#{request.contextPath}/resources/img/favicon.ico" />
			<ui:insert name="head-first" />
		</f:facet>
 
		<f:facet name="middle">
			<ui:insert name="head-middle" />
		</f:facet>
 
		<f:facet name="last">
			<!--h:outputScript library="fundeweb" name="primefaces/js/primefaces_fix.js" /-->
			<h:outputScript library="fundeweb" name="primefaces/js/locales.js"/>
			<h:outputScript library="js" name="bootstrap.min.js" />
			<h:outputScript library="fundeweb" name="js/fundeweb.js"/>
			<h:outputScript library="js" name="menu.js" />
			<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.5.3/less.min.js"></script>
 
			<!-- Personalizacion de la aplicacion -->
			<fdw:outputStylesheet library="css" name="bootstrap.min.css" />
			<fdw:outputStylesheet library="css" name="font.css" />
			<fdw:outputStylesheet library="css" name="layout.css" />
			<fdw:outputStylesheet library="css" name="layout_primefaces.css" />
			<fdw:outputStylesheet library="css" name="less.css" />
			<fdw:outputStylesheet library="css" name="custom.css" />
			<ui:insert name="head-last" />
		</f:facet>
 
		<ui:insert name="head" />
	</h:head>

Como podemos ver, tenemos dividida la cabecera en tres secciones definidas mediante <f:facet>: first, middle y last. Como su nombre indica, representan la posición donde se cargan los elementos definidos en ella.

A su vez, al final de cada una de estas tres secciones, tenemos un elemento <ui:insert>, que es el que nos permite en nuestra página añadir elementos a las secciones de la cabecera. Si por ejemplo, quiero añadir un fichero JS o CSS en la sección last, tendré que añadir en mi página lo siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:s="http://jboss.org/schema/seam/taglib"
	xmlns:p="http://primefaces.org/ui">
 
	<ui:composition template="/layout/template.xhtml">
 
		<ui:define name="head-last">
			<h:outputScript library="js" name="my_custom_js.js" />
			<fdw:outputStylesheet library="css" name="my_custom_css.css" />
		</ui:define>
 
		<ui:define name="body">
			...
		</ui:define>
 
	</ui:composition>
 
</html>

Como se puede observar, para cargar ficheros CSS mediante JSF utilizamos el componente <fdw:outputStylesheet> en lugar de <h:outputStylesheet>. Este cambio es importante, porque sino, la ordenación de los CSS no funcionara correctamente.

Antes de cerrar la cabecera (</h:head>), también disponemos de un lugar donde añadir ficheros de recursos identificado con head. Es por retro-compatibilidad con las anteriores plantillas, pero que sería igual que utilizar la sección head-last.

Nuevos Plantillas para Decoradores

Dentro de la carpeta layout se han añadido nuevas plantillas para poder utilizar facilmente bootstrap y el grid responsive.

  • editLineBs.xhtml: permite definir como anteriormente una línea, que corresponde con un form-group o row de bootstrap.
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
	  xmlns:ui="http://java.sun.com/jsf/facelets"
	  xmlns:f="http://java.sun.com/jsf/core"
	  xmlns:h="http://java.sun.com/jsf/html"
	  xmlns:s="http://jboss.org/schema/seam/taglib">
 
	<ui:composition>
 
	    <div id="#{clientId}" class="form-group #{styleClass == null ? '' : styleClass} #{ invalid ? 'has-error' : ''}"
	    	 style="#{style == null ? '' : style}">
			<ui:insert/>
	    </div>
 
	</ui:composition>
 
</html>
  • editCellBs.xhtml: permite definir los componentes que van a aparecer en la línea: etiqueta - input - mensaje como tres columnas de bootstrap. Se han añadido las variables labelStyleClas, valueStyleClass y messageStyleClass para poder definir los col-xx-yy de bootstrap. La etiqueta tiene implícita la clase CSS control-label, y el mensaje la clase has-error.
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
	  xmlns:ui="http://java.sun.com/jsf/facelets"
	  xmlns:f="http://java.sun.com/jsf/core"
	  xmlns:h="http://java.sun.com/jsf/html"
	  xmlns:s="http://jboss.org/schema/seam/taglib"
	  xmlns:fdw="http://www.um.es/atica/fundeweb">
 
	<ui:composition>
 
	        <s:label styleClass="control-label #{labelStyleClass == null ? '' : labelStyleClass}"
	        		 style="#{labelStyle == null ? '' : labelStyle}">
	            <ui:insert name="label"/>
	            <s:span styleClass="required" rendered="#{required}">*</s:span>
	        </s:label>
 
	        <span class="#{valueStyleClass == null ? '' : valueStyleClass}"
	        	  style="#{valueStyle == null ? '' : valueStyle}">
	            <s:validateAll>
	                <ui:insert name="value"/>
	            </s:validateAll>
	        </span>
 
	        <s:span styleClass="has-error #{messageStyleClass == null ? 'hidden-lg hidden-md hidden-sm hidden-xs' : messageStyleClass}"
	        	rendered="#{invalid}" style="#{messageStyle == null ? 'margin-top: 0.2em;' : messageStyle}">
				<fdw:message />
	        </s:span>
 
	</ui:composition>
 
</html>

Veamos un ejemplo:

<ui:composition
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:s="http://jboss.org/schema/seam/taglib"
	xmlns:p="http://primefaces.org/ui">
 
	<div class="container-fluid">
		<h:form id="crearObjetivosForm" styleClass="form-horizontal editFundeweb">
			<p:focus context="codigoRow" for="codigoInput" />
 
			<s:decorate id="codigoRow" template="/layout/editLineBs.xhtml" enclose="false">
				<s:decorate id="codigoCell" template="/layout/editCellBs.xhtml" enclose="false">
					<ui:param name="labelStyleClass" value="col-lg-1 col-md-1 col-sm-2 col-xs-2" />
					<ui:param name="valueStyleClass" value="col-lg-3 col-md-3 col-sm-5 col-xs-5" />
					<ui:param name="messageStyleClass" value="col-lg-8 col-md-8 col-sm-12 col-xs-12" />
 
					<ui:define name="label">#{messages['tabla.header.codigo']}</ui:define>
					<ui:define name="value">
						<p:inputText id="codigoInput" styleClass="form-control"
							value="#{manejadorAutorizacion.idObjetivo}" required="true"
							requiredMessage="#{messages['required.field']}" maxlength="20"/>
					</ui:define>
				</s:decorate>
			</s:decorate>
 
			<s:decorate id="descripcionRow" template="/layout/editLineBs.xhtml" enclose="false">
				<s:decorate id="descripcionCell" template="/layout/editCellBs.xhtml" enclose="false">
					<ui:param name="labelStyleClass" value="col-lg-1 col-md-1 col-sm-2 col-xs-2" />
					<ui:param name="valueStyleClass" value="col-lg-5 col-md-6 col-sm-9 col-xs-10" />
					<ui:param name="messageStyleClass" value="col-lg-6 col-md-5 col-sm-12 col-xs-12" />
 
					<ui:define name="label">#{messages['tabla.header.descripcion']}</ui:define>
					<ui:define name="value">
						<p:inputText id="descripcionInput" styleClass="form-control"
							value="#{manejadorAutorizacion.descripcionObjetivo}" required="true"
							requiredMessage="#{messages['required.field']}" maxlength="50"/>
					</ui:define>
				</s:decorate>
			</s:decorate>
 
			<s:decorate id="botonesRow" template="/layout/editLineBs.xhtml" enclose="false">
				<div class="col-lg-offset-1 col-md-offset-1 col-sm-offset-2 col-xs-offset-2 col-lg-1 col-md-1 col-sm-1 col-xs-1">
					<p:commandButton value="#{messages['value.add']}"
						icon="fa fa-floppy-o" global="true"
						action="#{manejadorAutorizacion.crearObjetivo}"
						update="@form, :tabPanel:gestionObjetivosForm:listaObjetivos, :messages" />
				</div>
			</s:decorate>
		</h:form>
 
		<p:separator />
 
		...	
	</div>

Para tener un grid responsive necesitamos:

  • Un elemento HTML con clase CSS container-fluid, en este caso utilizamos un <div>.
  • Que el <h:form> tenga las clases form-horizontal y editFundeweb (para que salga en dialogo por si hay cambio de página con modificaciones a medio).
  • Utilizamos el decorador (<d:decorate>) para editLineBs.xhtml con la propiedad enclose con valor false.
  • Utilizamos el decorador (<d:decorate>) para editCellBs.xhtml.xhtml con la propiedad enclose con valor false.
  • Definimos con <ui:param> los valores de las propiedades labelStyleClass, valueStyleClass y messageStyleClass.

Veamos como queda el ejemplo:

 Ejemplo de Grid Responsive

Si provocamos un error de validación de datos, obtenemos para una pantalla lg (large) según bootstrap:

{{ :fdw2.0:fundeweb2.0:gt_arquetipo:ejemplo-ii.jpg | Ejemplo de Grid Responsive - Large}

Si provocamos un error de validación de datos, obtenemos para una pantalla md (medium) según bootstrap:

 Ejemplo de Grid Responsive - Medium

Si provocamos un error de validación de datos, obtenemos para una pantalla sm (small) según bootstrap:

 Ejemplo de Grid Responsive - Small

Si provocamos un error de validación de datos, obtenemos para una pantalla xs (extra small) según bootstrap:

 Ejemplo de Grid Responsive - Extra Small

Añadida la Suplantación de Usuarios

Hemos añadido la suplantación de identidad. Podemos hacer búsquedas del usuario por el identificador (DNI) o por el correo.

 Suplantación de identidad - I

En cuanto al log, aparecerá lo siguiente en la aplicación:

20 dic 2017 11:17:54,877 DEBUG (SuplantarIdentidadBean.java:88) - Usuario: juanmiguel.bernal@ticarum.es - Cargando identidad. Correo [pedro.delgado@ticarum.es].
20 dic 2017 11:21:31,825  INFO (SuplantarIdentidadBean.java:106) - Usuario: juanmiguel.bernal@ticarum.es - Suplantando identidad del usuario pedro.delgado@ticarum.es.
20 dic 2017 11:21:31,825  INFO (UmuIdentity.java:218) - Usuario: juanmiguel.bernal@ticarum.es - Suplantando al usuario [pedrody@um.es] por parte de [juanmiguelbg@um.es]
20 dic 2017 11:21:31,826  INFO (LogManagerBean.java:38) - Usuario: juanmiguel.bernal@ticarum.es - Cambiando USERNAME: juanmiguel.bernal@ticarum.es --> pedrody@um.es
20 dic 2017 11:21:31,826  INFO (LogManagerBean.java:38) - Usuario: pedrody@um.es - Cambiando USERNAME: pedrody@um.es --> pedrody@um.es
20 dic 2017 11:21:31,827  INFO (UmuIdentityLoader.java:40) - Usuario: pedrody@um.es - Entra en loadDataLoginSuccessful
20 dic 2017 11:21:31,827  INFO (UmuIdentityLoader.java:51) - Usuario: pedrody@um.es - Usuario conectado: pedrody@um.es
20 dic 2017 11:21:31,828 DEBUG (SqlStatementLogger.java:104) - Usuario: pedrody@um.es - 
    select
        usuarios0_.LOGIN as LOGIN1_4_ 
    from
        PORTALFUNDEWEB.USUARIOS usuarios0_ 
    where
        usuarios0_.LOGIN=?
20 dic 2017 11:21:31,833 DEBUG (SqlStatementLogger.java:104) - Usuario: pedrody@um.es - 
    select
        rolesusuar0_.LOGIN as LOGIN1_4_1_,
        rolesusuar0_.ID_ROL as ID_ROL2_5_1_,
        roles1_.ID_ROL as ID_ROL1_1_0_,
        roles1_.DESCRIPCION as DESCRIPC2_1_0_,
        roles1_.ROL_PADRE as ROL_PADR3_1_0_ 
    from
        PORTALFUNDEWEB.ROLES_USUARIO rolesusuar0_ 
    inner join
        PORTALFUNDEWEB.ROLES roles1_ 
            on rolesusuar0_.ID_ROL=roles1_.ID_ROL 
    where
        rolesusuar0_.LOGIN=?
20 dic 2017 11:21:31,837  INFO (UmuIdentityLoader.java:55) - Usuario: pedrody@um.es - ROL CARGADO: ADM
20 dic 2017 11:21:31,837  INFO (UmuIdentityLoader.java:42) - Usuario: pedrody@um.es - pasa a ser el usuario:  pedrody@um.es
20 dic 2017 11:21:31,838  INFO (UmuIdentity.java:222) - Usuario: pedrody@um.es - Suplantacion correcta: [juanmiguelbg@um.es] ha suplantado a [pedrody@um.es].

Una vez hecha la suplantación, en la parte superior derecha de la pantalla, junto al nombre del usuario, aparece el botón Restaurar, para deshacer la suplantación.

 Suplantación de identidad - II

Si restauramos nuestro usuario, volvemos a aparecer en la parte superior derecha de la pantalla.

 Suplantación de identidad - III

En cuanto al log, aparecerá lo siguiente en la aplicación:

20 dic 2017 11:23:50,985  INFO (SuplantarIdentidadBean.java:122) - Usuario: pedrody@um.es - Restaurando identidad del usuario juanmiguelbg@um.es
20 dic 2017 11:23:50,986  INFO (UmuIdentity.java:240) - Usuario: pedrody@um.es - Restaurando la suplantacion del usuario [pedrody@um.es] por parte de [juanmiguelbg@um.es]
20 dic 2017 11:23:50,986  INFO (LogManagerBean.java:38) - Usuario: pedrody@um.es - Cambiando USERNAME: pedrody@um.es --> juanmiguelbg@um.es
20 dic 2017 11:23:50,987  INFO (LogManagerBean.java:38) - Usuario: juanmiguelbg@um.es - Cambiando USERNAME: juanmiguelbg@um.es --> juanmiguelbg@um.es
20 dic 2017 11:23:50,987  INFO (UmuIdentityLoader.java:40) - Usuario: juanmiguelbg@um.es - Entra en loadDataLoginSuccessful
20 dic 2017 11:23:50,988  INFO (UmuIdentityLoader.java:51) - Usuario: juanmiguelbg@um.es - Usuario conectado: juanmiguelbg@um.es
20 dic 2017 11:23:50,988 DEBUG (SqlStatementLogger.java:104) - Usuario: juanmiguelbg@um.es - 
    select
        usuarios0_.LOGIN as LOGIN1_4_ 
    from
        PORTALFUNDEWEB.USUARIOS usuarios0_ 
    where
        usuarios0_.LOGIN=?
20 dic 2017 11:23:50,992 DEBUG (SqlStatementLogger.java:104) - Usuario: juanmiguelbg@um.es - 
    select
        rolesusuar0_.LOGIN as LOGIN1_4_1_,
        rolesusuar0_.ID_ROL as ID_ROL2_5_1_,
        roles1_.ID_ROL as ID_ROL1_1_0_,
        roles1_.DESCRIPCION as DESCRIPC2_1_0_,
        roles1_.ROL_PADRE as ROL_PADR3_1_0_ 
    from
        PORTALFUNDEWEB.ROLES_USUARIO rolesusuar0_ 
    inner join
        PORTALFUNDEWEB.ROLES roles1_ 
            on rolesusuar0_.ID_ROL=roles1_.ID_ROL 
    where
        rolesusuar0_.LOGIN=?
20 dic 2017 11:23:50,997  INFO (UmuIdentityLoader.java:55) - Usuario: juanmiguelbg@um.es - ROL CARGADO: ADM
20 dic 2017 11:23:50,997  INFO (UmuIdentityLoader.java:42) - Usuario: juanmiguelbg@um.es - pasa a ser el usuario:  juanmiguelbg@um.es
20 dic 2017 11:23:50,998  INFO (UmuIdentity.java:245) - Usuario: juanmiguelbg@um.es - Restauracion de la suplantacion correcta: el usuario [pedrody@um.es] ya no esta suplantado por [juanmiguelbg@um.es].

Mejoras en la Gestión de la Autorización

Las pantallas son responsive, y utilizan las nuevas plantillas para los decoradores. Se pueden usar como guía. Por defecto, este sistema de autorización esta desactivado. Para poder activar dicho sistema, tenemos que:

  • Descomentar la anotación @Entity de las entidades del paquete es.um.atica._mi_aplicacion_.security.entities.
package es.um.atica.prueba.security.authorization.entities;
 
// Generated 18-jun-2014 10:18:26 by Hibernate Tools 4.0.0
 
import java.util.ArrayList;
import java.util.List;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Transient;
 
import org.jboss.seam.annotations.security.management.UserPassword;
import org.jboss.seam.annotations.security.management.UserPrincipal;
import org.jboss.seam.annotations.security.management.UserRoles;
import org.umu.atica.servicios.gesper.gente.entity.Persona;
 
/**
 * Usuarios generated by hbm2java
 */
 
@NamedQueries({ @NamedQuery(name = "Usuarios.obtenerUsuarios", query = "select usuario from Usuarios usuario") })
 
//@Entity
@Table(schema = "PORTALFUNDEWEB", name = "USUARIOS")
public class Usuarios implements java.io.Serializable {
 
	private static final long serialVersionUID = 5961882811529717090L;
 
	...
}
  • Descomentar en el fichero components.xml las siguientes lineas:
	<!-- Gestion de Roles y Usuarios -->
 
	<!-- <security:jpa-identity-store
		user-class="es.um.atica.ArquillianTest.security.entities.Usuarios"
		role-class="es.um.atica.ArquillianTest.security.entities.Roles" />
 
	<security:persistent-permission-resolver
		permission-store="#{umuPermissionStore}" /> -->

PrimeFaces

Con este arquetipo trabajamos con PrimeFaces 6.1 y PrimeFaces Extension 6.1.

Cuando se pone el JIRA a sistemas, hay que indicar que tiene que enlazarse con la versión de las librerías 2.0.1.


JUAN MIGUEL BERNAL GONZALEZ 19/12/2017 09:44

  • fdw2.0/fundeweb2.0/gt_arquetipo/novedades-0_0_7.txt
  • Última modificación: 20/12/2017 12:27
  • por JUAN MIGUEL BERNAL GONZALEZ