variable test else java spring jsp spring-mvc el

java - test - c out variable



Spring MVC: cómo mostrar valores de fecha formateados en JSP EL (4)

Me sentí decepcionado por saber que los desarrolladores de Spring han decidido no integrar Unified EL (el lenguaje de expresión usado en JSP 2.1+) con Spring EL declarando:

Ni JSP ni JSF tienen una posición sólida en términos de nuestro enfoque de desarrollo.

Pero inspirándome en el ticket de JIRA citado, creé un ELResolver personalizado que, si el valor resuelto es un java.time.LocalDate o java.time.LocalDateTime , intentará extraer el valor del patrón @DateTimeFormat para formatear la String devuelta valor.

Aquí está ELResolver (junto con el ServletContextListener usado para arrancarlo):

public class DateTimeFormatAwareElResolver extends ELResolver implements ServletContextListener { private final ThreadLocal<Boolean> isGetValueInProgress = new ThreadLocal<>(); @Override public void contextInitialized(ServletContextEvent event) { JspFactory.getDefaultFactory().getJspApplicationContext(event.getServletContext()).addELResolver(this); } @Override public void contextDestroyed(ServletContextEvent sce) {} @Override public Object getValue(ELContext context, Object base, Object property) { try { if (Boolean.TRUE.equals(isGetValueInProgress.get())) { return null; } isGetValueInProgress.set(Boolean.TRUE); Object value = context.getELResolver().getValue(context, base, property); if (value != null && isFormattableDate(value)) { String pattern = getDateTimeFormatPatternOrNull(base, property.toString()); if (pattern != null) { return format(value, DateTimeFormatter.ofPattern(pattern)); } } return value; } finally { isGetValueInProgress.remove(); } } private boolean isFormattableDate(Object value) { return value instanceof LocalDate || value instanceof LocalDateTime; } private String format(Object localDateOrLocalDateTime, DateTimeFormatter formatter) { if (localDateOrLocalDateTime instanceof LocalDate) { return ((LocalDate)localDateOrLocalDateTime).format(formatter); } return ((LocalDateTime)localDateOrLocalDateTime).format(formatter); } private String getDateTimeFormatPatternOrNull(Object base, String property) { DateTimeFormat dateTimeFormat = getDateTimeFormatAnnotation(base, property); if (dateTimeFormat != null) { return dateTimeFormat.pattern(); } return null; } private DateTimeFormat getDateTimeFormatAnnotation(Object base, String property) { DateTimeFormat dtf = getDateTimeFormatFieldAnnotation(base, property); return dtf != null ? dtf : getDateTimeFormatMethodAnnotation(base, property); } private DateTimeFormat getDateTimeFormatFieldAnnotation(Object base, String property) { try { if (base != null && property != null) { Field field = base.getClass().getDeclaredField(property); return field.getAnnotation(DateTimeFormat.class); } } catch (NoSuchFieldException | SecurityException ignore) { } return null; } private DateTimeFormat getDateTimeFormatMethodAnnotation(Object base, String property) { try { if (base != null && property != null) { Method method = base.getClass().getMethod("get" + StringUtils.capitalize(property)); return method.getAnnotation(DateTimeFormat.class); } } catch (NoSuchMethodException ignore) { } return null; } @Override public Class<?> getType(ELContext context, Object base, Object property) { return null; } @Override public void setValue(ELContext context, Object base, Object property, Object value) { } @Override public boolean isReadOnly(ELContext context, Object base, Object property) { return true; } @Override public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) { return null; } @Override public Class<?> getCommonPropertyType(ELContext context, Object base) { return null; } }

Registre ELResolver en web.xml:

<listener> <listener-class>com.company.el.DateTimeFormatAwareElResolver</listener-class> </listener>

¡Y ahora, cuando tenga ${widget.created} en mi jsp, el valor mostrado se formateará de acuerdo con la anotación @DateTimeFormat !

Además, si jsp (y no solo la representación de cadena formateada) necesita el objeto LocalDate o LocalDateTime , aún puede acceder al objeto utilizando la invocación directa del método como: ${widget.getCreated()}

Aquí hay un bean de valor simple anotado con la nueva anotación @DateTimeFormat Spring (a partir de 3.0) (que, según tengo entendido, reemplaza la necesidad pre-3.0 de PropertyEditor s personalizado según esta pregunta SO ):

import java.time.LocalDate; import org.springframework.format.annotation.DateTimeFormat; public class Widget { private String name; @DateTimeFormat(pattern = "MM/dd/yyyy") private LocalDate created; // getters/setters excluded }

Al vincular los valores de un envío de formulario a este widget, el formato de fecha funciona perfectamente. Es decir, solo las cadenas de fecha en el formato MM/dd/yyyy se convertirán satisfactoriamente en objetos LocalDate reales. Genial, estamos a mitad de camino.

Sin embargo, también me gustaría poder mostrar la propiedad LocalDate creada en una vista JSP en el mismo formato MM/dd/yyyy utilizando JSP EL así (asumiendo que mi controlador Spring incorporó un atributo de widget al modelo):

${widget.created}

Desafortunadamente, esto solo mostrará el formato de LocalDate predeterminado de LocalDate (en formato yyyy-MM-dd ). Entiendo que si uso las etiquetas de formulario de Spring, la fecha se muestra como se desea:

<form:form commandName="widget"> Widget created: <form:input path="created"/> </form:form>

Pero me gustaría simplemente mostrar la cadena de fecha formateada sin usar las etiquetas de formulario de primavera. O incluso la etiqueta fmt:formatDate JSTL.

Proveniente de Struts2, el HttpServletRequest se envolvió en un StrutsRequestWrapper que permitía que las expresiones EL de este tipo interrogaran la pila de valores OGNL. ¿Entonces me pregunto si el resorte proporciona algo similar a esto para permitir que los convertidores ejecuten?

EDITAR

También me doy cuenta de que al usar la etiqueta eval de spring, la fecha se mostrará de acuerdo con el patrón definido en la anotación @DateTimeFormat :

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <spring:eval expression="widget.created"/>

Curiosamente, cuando se utiliza un PropertyEditor personalizado para formatear la fecha, esta etiqueta NO invoca el método getAsText y, por lo tanto, el valor predeterminado es DateFormat.SHORT como se describe en los documentos . En cualquier caso, todavía me gustaría saber si hay una manera de lograr el formato de fecha sin tener que usar una etiqueta, solo usando el estándar JSP EL.


Para precisar la respuesta de Eduardo:

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <fmt:formatDate pattern="MM/dd/yyyy" value="${widget.created}" />


Puede usar la etiqueta para proporcionarle este tipo de formateo, como dinero, datos, tiempo y muchos otros.

Puede agregar en su JSP la referencia: <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

Y use el formato como: <fmt:formatDate pattern="yyyy-MM-dd" value="${now}" />

Sigue a continuación una referencia:

http://www.tutorialspoint.com/jsp/jstl_format_formatdate_tag.htm


También prefiero no hacer ningún formato a través de etiquetas. Me doy cuenta de que esta puede no ser la solución que está buscando y está buscando una manera de hacerlo a través de las anotaciones de primavera. Sin embargo, en el pasado he usado el siguiente trabajo alrededor:

Crea un nuevo getter con la siguiente firma:

public String getCreatedDateDisplay

(Puedes modificar el nombre del captador si lo prefieres).

Dentro del captador, formatee el atributo de fecha created como se desee utilizando un formateador como SimpleDateFormat.

Entonces puedes llamar al siguiente desde tu JSP.

${widget.createDateDisplay}