2014-12-17 8 views
14

Hier ist ein einfacher Wert bean kommentierte mit Spring neuen (ab 3.0) Bequemlichkeit @DateTimeFormat Anmerkung (die wie ich sie verstehe formatiert Datumswerte angezeigt werden ersetzt die Pre-3.0 Bedarf für individuelle PropertyEditor s per this SO question):Spring MVC: Wie in JSP EL

Wenn Sie die Werte von einer Formularübergabe an dieses Widget warten, funktioniert das Datumsformat einwandfrei. Das heißt, nur Datumszeichenfolgen im Format MM/dd/yyyy werden erfolgreich in tatsächliche LocalDate Objekte konvertiert. Großartig, wir sind auf halbem Weg.

Allerdings würde ich auch in der Lage sein mag auch LocalDate Eigenschaft in einer JSP-Ansicht in das gleichen MM/dd/yyyy Format mit JSP EL wie so die erstellte anzuzeigen (meine Feder-Controller unter der Annahme, ein Widget Attribut zum Modell hinzugefügt):

Leider wird nur das Standardformat toString von LocalDate (im Format yyyy-MM-dd) angezeigt. Ich verstehe, dass, wenn ich Frühling Formular-Tags gehören Datumsanzeige nach Wunsch:

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

Aber ich mag einfach, um das formatierte Datum Zeichenfolge anzuzeigen, ohne die Federform-Tags. Oder sogar JSTL fmt:formatDate Tag.

Von Struts2 kommend wurde die HttpServletRequest in eine StrutsRequestWrapper eingebunden, die EL-Ausdrücke wie diese ermöglichte, den OGNL-Wertstack tatsächlich abzufragen. Ich frage mich also, ob die Feder etwas Ähnliches für die Ausführung von Konvertern bereitstellt?

EDIT

ich auch erkennen, dass, wenn eval Tag-Feder mit dem Datum der in der @DateTimeFormat Anmerkung definierten Muster entsprechend anzeigt:

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

Interessanterweise, wenn ein benutzerdefinierten PropertyEditor mit der zu formatieren Datum, ruft dieses Tag NICHT PropertyEditor 's getAsText Methode und daher standardmäßig DateFormat.SHORT als described in the docs. Auf jeden Fall möchte ich noch wissen, ob es eine Möglichkeit gibt, die Datumsformatierung zu erreichen, ohne ein Tag verwenden zu müssen - nur unter Verwendung von Standard-JSP-EL.

+0

betrachten Formatierung das Datums in der Steuerung vor der Übergabe an die Aussicht? – Septem

Antwort

0

Ich war mutlos zu erfahren, dass spring developers have decided not to integrate Unified EL (the expression language used in JSP 2.1+) with Spring EL besagen:

weder JSP noch JSF hat eine starke Position in Bezug auf unseren Entwicklungsschwerpunkt mehr.

Aber Inspiration aus dem JIRA-Ticket nehmen zitiert, habe ich ein benutzerdefinierte ELResolver, die, wenn der aufgelöste Wert ein java.time.LocalDate oder java.time.LocalDateTime ist, den @DateTimeFormat Musterwert, um den zurückgegebenen String Wert zu formatieren zu ziehen versucht.

Hier ist die ELResolver (zusammen mit dem ServletContextListener verwendeten Bootstrap):

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; 
     } 
    } 

die ELResolver in web.xml registrieren:

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

Und wenn ich jetzt ${widget.created} in meiner jsp haben, Der angezeigte Wert wird entsprechend der @DateTimeFormat Annotation formatiert!

Wenn zusätzlich das LocalDate oder LocalDateTime Objekt durch die jsp benötigt wird (und nicht nur die formatierte String-Darstellung), können Sie immer noch auf das Objekt zugreifen selbst direkten Methodenaufruf verwendet wie: ${widget.getCreated()}

+0

In Ihrer Lösung ist ** isGetValueInProgress ** notwendig, und wenn ja, warum? – Pawel

+0

vergiss, fand einen Kommentar in einem alten [github Repo] (https://github.com/pukkaone/webappenhance/blob/master/src/main/java/com/github/pukkaone/jsp/EscapeXmlELResolver.java), das führte Ich zu dem Zweck. '// Dieser Resolver ist in der ursprünglichen Resolver-Kette. Um // unendliche Rekursion zu verhindern, setze ein Flag, um zu verhindern, dass dieser Resolver von // die ursprüngliche Resolver-Kette erneut aufruft, wenn sie in der // Kette herumkommt – Pawel

1

Ich bevorzuge auch keine Formatierung über Tags. Ich weiß, dass dies nicht die Lösung ist, nach der Sie suchen, und suchen Sie nach einer Möglichkeit, dies über Federnotizen zu tun. Dennoch In der Vergangenheit habe ich die folgende Arbeit um verwendet:

Erstellen Sie einen neuen Getter mit der folgenden Signatur: (. Sie können den Namen des Getter ändern, wenn Sie bevorzugen)

public String getCreatedDateDisplay 

Formatieren Sie innerhalb des Getters das Datumsattribut created mit einem Formatierungsprogramm wie SimpleDateFormat.

Dann können Sie die folgenden von Ihrem JSP

${widget.createDateDisplay} 
+0

Dies ist eine gültige Alternative. Danke für die Antwort. Aber du hast Recht - ich hoffe wirklich, dass ich Spring's '@ DateTimeFormat' verwenden kann und erklärend bekomme, was ich in der Ansicht benötige, anstatt die Arbeit (unbedingt) in der Bean erledigen zu müssen. Wir befinden uns jedoch auf der gleichen Seite, da das Endergebnis von '$ {widget.createDateDisplay}' sehr schön ist (besonders, wenn es sich um das neuere 'java.time.LocalDate' handelt, das nicht so gut mit JSTLs fmt taglib abgespielt wird). –

7

rufen Sie das Tag verwenden, können Sie diese Art von Formatierungen, wie Geld, Daten, Zeit und viele andere zur Verfügung zu stellen.

Sie auf die Sie hinzufügen können JSP die Referenz: <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

Und verwenden Sie die Formatierung: <fmt:formatDate pattern="yyyy-MM-dd" value="${now}" />

Folgt unter einem Referenz:

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

+1

Die '<% @ taglib prefix =" fmt "uri =" http://java.sun.com/jsp/jstl/fmt "%>' taglib funktioniert nicht mit 'java.time.LocalDate' –

4

Um genau zu Eduardo Antwort:

+0

Wie ich bereits erwähnt habe In der Frage hoffte ich, den Wert direkt ausgeben zu können, ohne JSTLs 'fmt: formatDate'-Tag zu verwenden. (Und auf jeden Fall funktioniert dieses Tag nicht, wenn 'LocalDate'-Datumsobjekte verwendet werden.) –

+0

Warum möchten Sie die JSTL nicht verwenden? –