web-dev-qa-db-ja.com

Spring MVC:JSP ELでフォーマットされた日付値を表示する方法

これは、Springの新しい(3.0以降の)便利な@DateTimeFormatアノテーションで注釈された単純な値Beanです(これは、3.0より前のカスタムPropertyEditorsの必要性を置き換えます this 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
}

このウィジェットへのフォーム送信から値を入札する場合、日付形式は問題なく機能します。つまり、MM/dd/yyyy形式の日付文字列のみが実際のLocalDateオブジェクトに正常に変換されます。いいですね、途中です。

ただし、JSPビューで作成されたLocalDateプロパティも同じMM/dd/yyyy形式でJSP ELを使用して表示できるようにしたいと思います(Springコントローラーがウィジェット属性をモデル):

${widget.created}

残念ながら、これはtoStringのデフォルトのLocalDate形式(yyyy-MM-dd形式)のみを表示します。春のフォームタグを使用すると、日付が希望どおりに表示されることを理解しています。

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

しかし、スプリングフォームタグを使用せずに、フォーマットされた日付文字列を単純に表示したいと思います。またはJSTLのfmt:formatDateタグです。

Struts2から来たHttpServletRequestStrutsRequestWrapper にラップされ、これにより、このようなEL式が実際にOGNL値スタックに問い合わせできるようになりました。だから私は春がコンバーターの実行を許可するためにこれに似たものを提供するのだろうか?

[〜#〜]編集[〜#〜]

また、Springのevalタグを使用すると、@DateTimeFormatアノテーションで定義されたパターンに従って日付が表示されることにも気づきました。

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

興味深いことに、カスタムPropertyEditorを使用して日付をフォーマットする場合、このタグはそのPropertyEditorgetAsTextメソッドを呼び出さないため、デフォルトでDateFormat.SHORTとして ドキュメントで説明 。いずれにしても、タグを使用せずに日付のフォーマットを実現する方法があるかどうかを知りたいのですが、標準のJSP ELを使用するだけです。

18
Brice Roncace

Spring開発者は、Unified EL(JSP 2.1+で使用されている式言語)をSpring ELと統合しないことを決定しました を次のように学んだ。

jSPもJSFも、私たちの開発フォーカスの観点からはもはや強い立場にありません。

しかし、引用されたJIRAチケットからインスピレーションを得て、カスタムの ELResolver を作成しました。これは、解決された値がJava.time.LocalDateまたはJava.time.LocalDateTimeの場合、@DateTimeFormatパターン値をプルして、返されたString value。

ここにELResolverがあります(これに使用されるServletContextListenerとともにbootstrap it):

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

ELResolverをweb.xmlに登録します。

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

そして、jspに${widget.created}があると、表示される値は@DateTimeFormatアノテーションに従ってフォーマットされます。

さらに、LocalDateまたはLocalDateTimeオブジェクトがjspで必要な場合(フォーマットされた文字列表現だけでなく)、次のような直接メソッド呼び出しを使用してオブジェクト自体にアクセスできます。${widget.getCreated()}

3
Brice Roncace

このタグを使用して、お金、データ、時間など、さまざまな形式の書式を提供できます。

JSPに参照を追加できます:<%@ taglib prefix="fmt" uri="http://Java.Sun.com/jsp/jstl/fmt" %>

そして、フォーマットを次のように使用します:<fmt:formatDate pattern="yyyy-MM-dd" value="${now}" />

参照の下に続きます:

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

8
Eduardo Mioto

エドゥアルドの正確な答えは次のとおりです。

<%@ taglib prefix="fmt" uri="http://Java.Sun.com/jsp/jstl/fmt" %>

<fmt:formatDate pattern="MM/dd/yyyy" value="${widget.created}" />
4
Remy Mellet

また、タグを介してフォーマットを行わないことも好みます。私はこれがあなたが探している解決策ではないかもしれないことを理解し、春の注釈を介してこれを行う方法を探しています。それにもかかわらず、過去に私は次の回避策を使用しました:

次の署名で新しいゲッターを作成します。

public String getCreatedDateDisplay

(必要に応じて、ゲッターの名前を変更できます。)

ゲッター内で、SimpleDateFormatなどのフォーマッターを使用して、必要に応じてcreated日付属性をフォーマットします。

次に、JSPから以下を呼び出すことができます

${widget.createDateDisplay}
2
applejack42