MVC de printemps: comment afficher les valeurs de date formatées dans JSP EL
voici un haricot de valeur simple annoté avec la nouvelle (à partir de 3.0) convenance de Spring @DateTimeFormat
annotation (qui, comme je comprends remplace le pré-3.0 besoin de custom PropertyEditor
s selonce DONC, la question):
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
}
quand on bide les valeurs d'une soumission de formulaire à ce widget, le format de date fonctionne parfaitement. C'est, uniquement date de chaînes dans le MM/dd/yyyy
le format convertira avec succès enLocalDate
objets. Super, nous sommes à mi-chemin y.
cependant, je voudrais aussi pouvoir afficher le LocalDate
propriété dans une vue JSP dans le même MM/dd/yyyy
format utilisant JSP EL comme so (en supposant que mon contrôleur de printemps a ajouté un attribut widget au model):
${widget.created}
malheureusement, cela n'affichera que la valeur par défaut toString
format de LocalDate
yyyy-MM-dd
format). Je comprends que si j'utilise du printemps balises de formulaire la date s'affiche comme vous le souhaitez:
<form:form commandName="widget">
Widget created: <form:input path="created"/>
</form:form>
Mais j'aimerais il suffit d'afficher la chaîne de date formatée sans utiliser les étiquettes de forme de ressort. Ou même JSTL!--13--> balise.
venant de Struts2, le HttpServletRequest
était enveloppé dans un StrutsRequestWrapper
qui permettait à des expressions EL comme celle-ci d'interroger la pile de valeurs D'OGNL. Donc je me demande si spring fournit quelque chose de similaire à ceci pour permettre aux convertisseurs d'exécuter?
EDIT
je me rends compte aussi que lors de l'utilisation du ressort eval
balise la date s'affichera selon le motif défini dans le @DateTimeFormat
note:
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<spring:eval expression="widget.created"/>
fait intéressant, lorsque l'on utilise une coutume PropertyEditor
pour formater la date, cette balise n'invoque pas que PropertyEditor
getAsText
et donc par défaut à la méthode DateFormat.SHORT
décrit dans les docs. Quoi qu'il en soit, j'aimerais savoir s'il y a un moyen d'obtenir le formatage de la date sans avoir à utiliser une étiquette--en utilisant seulement le JSPEL standard.
4 réponses
vous pouvez utiliser l'étiquette pour vous fournir ce genre de formatage, tels que l'argent, les données, le temps, et beaucoup d'autres.
vous pouvez ajouter sur vous JSP la référence:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
et utiliser le formatage comme suit::
<fmt:formatDate pattern="yyyy-MM-dd" value="${now}" />
voici une référence:
http://www.tutorialspoint.com/jsp/jstl_format_formatdate_tag.htm
pour préciser la réponse D'Eduardo:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<fmt:formatDate pattern="MM/dd/yyyy" value="${widget.created}" />
j'ai été découragés d'apprendre que les développeurs spring ont décidé de ne pas intégrer El unifié (le langage d'expression utilisé dans JSP 2.1+) avec El Spring en déclarant:
ni JSP ni JSF n'ont une position forte en termes de développement.
mais en m'inspirant du billet JIRA Cité, j'ai créé une coutume ELResolver qui, si la valeur résolue est un java.time.LocalDate
ou java.time.LocalDateTime
, va tenter pour tirer le @DateTimeFormat
valeur de motif afin de formater leString
valeur.
Voici le ELResolver
(avec ServletContextListener
utilisé pour l'amorçage):
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;
}
}
Enregistrer le ELResolver
dans le web.xml:
<listener>
<listener-class>com.company.el.DateTimeFormatAwareElResolver</listener-class>
</listener>
Et maintenant, quand j'ai ${widget.created}
dans mon jsp, la valeur affichée sera formatée selon le @DateTimeFormat
annotation!
en outre, si le LocalDate
ou LocalDateTime
l'objet est nécessaire au jsp (et pas seulement le formaté) String representation), vous pouvez toujours accéder à l'objet lui-même en utilisant la méthode directe invocation comme: ${widget.getCreated()}
je préfère aussi ne pas faire de formatage via des tags. Je me rends compte que ce n'est peut-être pas la solution que vous recherchez et que vous cherchez un moyen de le faire via des annotations de printemps. Néanmoins, Dans le passé, j'ai utilisé le contourner suivante:
Créer un nouveau getter avec la signature suivante:
public String getCreatedDateDisplay
(vous pouvez modifier le nom du getter si vous préférez.)
dans le getter, formater le created
attribut date tel que désiré en utilisant un formatteur tel que SimpleDateFormat.
alors vous pouvez appeler ce qui suit à partir de votre JSP
${widget.createDateDisplay}