Login desplegable con jQuery

Resulta bastante sencillo hacer un menú desplegable con jQuery que además de funcional sea bonito. En este caso vamos a ver un menú que se despliega hacia abajo cuando pulsamos sobre «Login».

Lo primero es crear un div con el contenido. Tendremos un link con «Login» y una flechita hacia abajo. Al pulsar sobre login se abrirá el div loginpanel mostrando los campos para el usuario y contraseña, además del botón de Entrar. El HTML es el siguiente:

[sourcecode language=html]


Login


[/sourcecode]

Para poder utilizar jQuery importamos la librería javascript desde googleapis.

[sourcecode language=html]

Login desplegable jQuery

[/sourcecode]

Por último tenemos el código que controlará cuándo se abre la capa del login, se cambia la flecha y/o se cierra la capa al volver a pulsar sobre el login.

[sourcecode language=html]

[/sourcecode]

Cuando se pulsa sobre el div con id «showlogin», se muestra la capa de login cuyo identificador es «loginpanel» con un efecto deslizante (slide). Si la capa ya estuviera abierta, haría lo contrario (se cerraría), por eso se utiliza toggle.
Además, como bonus, se cambia la flecha para indicar que se puede desplegar o plegar el login.

Os podéis descargar el contenido del menú desplegable y utilizarlo donde queráis. Se han añadido unos estilos css para que sea un poco más amigable.

Creación de validadores con anotaciones

Este va a ser un ejemplo rápido sobre cómo crear validaciones con anotaciones a medida del estilo:

@NotEmpty
private String name;

No pretende ser una explicación rigurosa de todas las opciones (para eso existen unos manuales y unas referencias técnicas fabulosas.

Usamos la validación de beans Bean Validation JSR 303, en su implementación de Hibernate (Hibernate validator 4.1.0.Final)

Si, por ejemplo, al dar de alta un usuario, queremos comprobar que el usuario es único, y no queremos meternos en engorrosas comprobaciones e if’s anidados para ver si un usuario está o no dado de alta, podemos querer crear la anotación siguiente dentro del bean que nos interese:

@UniqueUser
private String username;

Y si no pasa la validación, podremos dar un error de validación sin necesidad de ensuciar el código.

Para ello primero se crea la anotación propiamente dicha, por ejemplo «UniqueUser.java».

@Target({ FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueUserConstraintValidator.class)
@Documented
public @interface UniqueUser {
	String message() default "{user.exists}";
	Class<?>[] groups() default {};
	Class<? extends Payload>[] payload() default {};
}

Lo interesante de aquí es:

  • El nombre que sigue a @interface UniqueUser, que será como llamaremos a la anotación, es decir, utilizaremos @UniqueUser cuando queramos usarla.
  • La línea @Target({ FIELD, ANNOTATION_TYPE }) dice que se podrán anotar campos, pero por ejemplo no métodos (que sería tan sencillo como añadir METHOD)
  • @Retention(RUNTIME) indica que la anotación se aplicará en tiempo de ejecución por reflection. Se escapa de este mini-manual explicarlo en profundidad.
  • @Constraint(validatedBy = UniqueUserConstraintValidator.class) nos indica que la anotación se validará con la clase UniqueUserConstraintValidator, que veremos a continuación.
  • El message es el texto del error. Puede estar internacionalizado en messages_i18n.properties, donde i18n es el locale pertinente.
  • Groups y payload se dejan como arrays vacíos.

La clase UniqueUserConstraintValidator tiene que implementar un ConstraintValidator, y quedaría de la siguiente manera:

public class UniqueUserConstraintValidator implements ConstraintValidator<UniqueUser, String> {

	@Inject
	private UserService userService;

	public void initialize(UniqueUser constraintAnnotation) {
		// No hacemos nada
	}

	public boolean isValid(String username,	ConstraintValidatorContext constraintContext) {

		if (userService.existsUserByUsername(username)) {
			return false;
		} else {
			return true;
		}
	}
}

Como puede verse, hemos inyectado (gracias a Spring) el servicio de usuarios que será el que compruebe si ya existe ese nombre de usuario en el sistema. En el método isValid es donde se valida realmente si el campo username cumple o no la validación, devolviendo true si pasa la validación y false en caso contrario.

Y de esta manera ya tendremos nuestra brand-new anotación @UniqueUser lista para comprobar si el usuario es único.

Tasks anotadas. Rápidas y fáciles con Spring 3.1

Hola a todos. Aquí va un artículo píldora para aquellos que deseen crear tareas lanzadas en background (e.g. recalcular índices, borrar datos temporales, etcétera) usando anotaciones con Spring 3.1. Y para ello nada mejor que un ejemplo. Se presupone que el lector sabe configurar un proyecto con Spring 3.1.

Supongamos que queremos una tarea que imprima en los logs de nuestra aplicación «qué día más bonito hace hoy!» porque nos encontramos tremendamente felices y queremos alegrarle el día al administrador de sistemas. De hecho, queremos alegrárselo tanto que se lo queremos imprimir cada medio segundo (seguro que el encanta tener 120 líneas/minuto para revisar en el log). Para ello, crearemos una clase como la siguiente:

[sourcecode language=java]
@Component
public class MakeMyDayTask {
private static final Logger LOGGER = Logger.getLogger(MakeMyDayTask.class.getName());

@Scheduled(fixedDelay = 500)
public void run() {
// Nivel severe porque así seguro que se ven
LOGGER.severe("qué día más bonito hace hoy!");
}
}
[/sourcecode]

Y nada más. Así de fácil. Bueno, en realidad hay un detalle más, pero es tan tonto que casi no merece la pena indicarlo. Salvo para el que escribe, que nunca fue capaz de saber por qué las tareas no se lanzaban hasta que después de mucho tiempo descubrió que es necesario especificar que las anotaciones de las tareas necesitan ser escaneadas (pensaba que de eso se encargaba automágicamente el elemento «component-scan» de la configuración xml, pero evidentemente no). En fin, para que funcionen las anotaciones de las tareas en background es necesario que el fichero xml encargado de montar el contexto (aunque sólo sea para decir «oye, usa anotaciones») contenga el elemento «annotation-driven» de las tasks. A continuación se muestra un ejemplo del xml correspondiente a la configuración de un servlet de un proyecto que usa Spring MVC:

[sourcecode language=xml]
<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"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">

<context:component-scan base-package="paquetería" />

<!– GRACIAS A ESTO BUSCA ANOTACIONES EN LAS TAREAS –>
<task:annotation-driven />

<mvc:annotation-driven />

<mvc:view-controller path="/" view-name="index"/>

<mvc:resources mapping="/resources/**" location="/resources/" />

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:/i18n/messages" />
<property name="cacheSeconds" value="0" />
</bean>

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

</beans>
[/sourcecode]

Con ese elemento en la configuración y las tareas bajo la paquetería a escanear, las anotaciones funcionarán como la seda. Hay que destacar que a las anotaciones se les pueden inyectar otros objetos existentes en el contexto (con @Autowired o con @Inject, según el gusto).

Termino enlazando con la referencia a spring relativa a las tareas, donde se puede ver por ejemplo cómo configurar la tarea con sintaxis cron o cómo hacer uso de la anotación @Async. Un saludo a todos y que paséis un feliz día.