これは、Springの新しい(3.0以降の)便利な@DateTimeFormat
アノテーションで注釈された単純な値Beanです(これは、3.0より前のカスタムPropertyEditor
sの必要性を置き換えます 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から来たHttpServletRequest
は StrutsRequestWrapper
にラップされ、これにより、このようなEL式が実際にOGNL値スタックに問い合わせできるようになりました。だから私は春がコンバーターの実行を許可するためにこれに似たものを提供するのだろうか?
[〜#〜]編集[〜#〜]
また、Springのeval
タグを使用すると、@DateTimeFormat
アノテーションで定義されたパターンに従って日付が表示されることにも気づきました。
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<spring:eval expression="widget.created"/>
興味深いことに、カスタムPropertyEditor
を使用して日付をフォーマットする場合、このタグはそのPropertyEditor
のgetAsText
メソッドを呼び出さないため、デフォルトでDateFormat.SHORT
として ドキュメントで説明 。いずれにしても、タグを使用せずに日付のフォーマットを実現する方法があるかどうかを知りたいのですが、標準のJSP ELを使用するだけです。
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()}
このタグを使用して、お金、データ、時間など、さまざまな形式の書式を提供できます。
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
エドゥアルドの正確な答えは次のとおりです。
<%@ taglib prefix="fmt" uri="http://Java.Sun.com/jsp/jstl/fmt" %>
<fmt:formatDate pattern="MM/dd/yyyy" value="${widget.created}" />
また、タグを介してフォーマットを行わないことも好みます。私はこれがあなたが探している解決策ではないかもしれないことを理解し、春の注釈を介してこれを行う方法を探しています。それにもかかわらず、過去に私は次の回避策を使用しました:
次の署名で新しいゲッターを作成します。
public String getCreatedDateDisplay
(必要に応じて、ゲッターの名前を変更できます。)
ゲッター内で、SimpleDateFormatなどのフォーマッターを使用して、必要に応じてcreated
日付属性をフォーマットします。
次に、JSPから以下を呼び出すことができます
${widget.createDateDisplay}