Java Spring MVC:如何在 JSP EL 中显示格式化的日期值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27516576/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 04:29:43  来源:igfitidea点击:

Spring MVC: how to display formatted date values in JSP EL

javaspringjspspring-mvcel

提问by Brice Roncace

Here's a simple value bean annotated with Spring's new (as of 3.0) convenience @DateTimeFormatannotation (which as I understand replaces the pre-3.0 need for custom PropertyEditors as per this SO question):

这是一个简单的值 bean,它用 Spring 的新(从 3.0 起)便利 @DateTimeFormat注释进行了注释(据我所知,它取代了 3.0 之前的对 custom PropertyEditors 的需求,根据这个 SO 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
}

When biding the values from a form submission to this widget, the date format works flawlessly. That is, only date strings in the MM/dd/yyyyformat will convert successfully to actual LocalDateobjects. Great, we're halfway there.

将表单提交中的值投标到此小部件时,日期格式完美无缺。也就是说,只有MM/dd/yyyy格式中的日期字符串才能成功转换为实际LocalDate对象。太好了,我们已经成功了一半。

However, I would also like to be able to also display the created LocalDateproperty in a JSP view in the same MM/dd/yyyyformat using JSP EL like so (assuming my spring controller added a widget attribute to the model):

但是,我还希望能够像这样使用 JSP ELLocalDate以相同MM/dd/yyyy格式在 JSP 视图中显示创建的属性(假设我的 spring 控制器向模型添加了一个小部件属性):

${widget.created}

Unfortunately, this will only display the default toStringformat of LocalDate(in yyyy-MM-ddformat). I understand that if I use spring's form tags the date displays as desired:

不幸的是,这只会显示(in format)的默认toString格式。我知道如果我使用 spring 的表单标签,日期会根据需要显示:LocalDateyyyy-MM-dd

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

But I'd like to simply display the formatted date string without using the spring form tags. Or even JSTL's fmt:formatDatetag.

但我想简单地显示格式化的日期字符串而不使用 spring 表单标签。甚至 JSTL 的fmt:formatDate标签。

Coming from Struts2, the HttpServletRequestwas wrapped in a StrutsRequestWrapperwhich enabled EL expressions like this to actually interrogate the OGNL value stack. So I'm wondering if spring provide something similar to this for allowing converters to execute?

来自 Struts2,HttpServletRequest被包裹在 a 中StrutsRequestWrapper,这使得像这样的 EL 表达式能够实际询问 OGNL 值堆栈。所以我想知道 spring 是否提供类似的东西来允许转换器执行?

EDIT

编辑

I also realize that when using spring's evaltag the date will display according the pattern defined in the @DateTimeFormatannotation:

我也意识到当使用 spring 的eval标签时,日期将根据@DateTimeFormat注释中定义的模式显示:

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

Interestingly, when using a custom PropertyEditorto format the date, this tag does NOT invoke that PropertyEditor's getAsTextmethod and therefore defaults to the DateFormat.SHORTas described in the docs. In any event, I'd still like to know if there is a way to achieve the date formatting without having to use a tag--only using standard JSP EL.

有趣的是,使用自定义当PropertyEditor格式化日期,该标签不会调用该PropertyEditorgetAsText方法,因此默认为DateFormat.SHORT在该文档中描述。无论如何,我仍然想知道是否有一种方法可以在无需使用标记的情况下实现日期格式——仅使用标准 JSP EL。

采纳答案by Brice Roncace

I was dispirited to learn that spring developers have decided not to integrate Unified EL (the expression language used in JSP 2.1+) with Spring ELstating:

得知Spring 开发人员决定不将 Unified EL(JSP 2.1+ 中使用的表达式语言)与 Spring EL 集成时,我感到沮丧:

neither JSP nor JSF have a strong position in terms of our development focus anymore.

JSP 和 JSF 都不再是我们的开发重点。

But taking inspiration from the JIRA ticket cited, I created a custom ELResolverwhich, if the resolved value is a java.time.LocalDateor java.time.LocalDateTime, will attempt to pull the @DateTimeFormatpattern value in order to format the returned Stringvalue.

但是从引用的 JIRA 票证中获得灵感,我创建了一个自定义ELResolver,如果解析的值是 ajava.time.LocalDatejava.time.LocalDateTime,它将尝试提取@DateTimeFormat模式值以格式化返回String值。

Here's the ELResolver(along with the ServletContextListenerused to bootstrap it):

这是ELResolver(以及ServletContextListener用于引导它的):

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

Register the ELResolverin web.xml:

ELResolver在 web.xml 中注册:

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

And now when I have ${widget.created}in my jsp, the value displayed will be formatted according to the @DateTimeFormatannotation!

现在当我${widget.created}在我的 jsp 中时,显示的值将根据@DateTimeFormat注释进行格式化!

Additionally, if the LocalDateor LocalDateTimeobject is needed by the jsp (and not just the formatted String representation), you can still access the object itself using direct method invocation like: ${widget.getCreated()}

此外,如果jsp 需要LocalDateorLocalDateTime对象(而不仅仅是格式化的字符串表示),您仍然可以使用直接方法调用访问对象本身,例如:${widget.getCreated()}

回答by appleHyman42

I also prefer to not do any formatting via tags. I realise this may not be the solution you are looking for and are looking for a way to do this via spring annotations. Nevertheless, In the past I've used the following work around:

我也更喜欢不通过标签进行任何格式化。我意识到这可能不是您正在寻找的解决方案,并且正在寻找一种通过 spring 注释来做到这一点的方法。尽管如此,过去我使用了以下解决方法:

Create a new getter with the following signature:

使用以下签名创建一个新的 getter:

public String getCreatedDateDisplay

(You can alter the name of the getter if you prefer.)

(如果您愿意,可以更改 getter 的名称。)

Within the getter, format the createddate attribute as desired using a formatter such as SimpleDateFormat.

在 getter 中,created使用 SimpleDateFormat 等格式化程序根据需要格式化日期属性。

Then you can call the following from your JSP

然后你可以从你的 JSP 中调用以下内容

${widget.createDateDisplay}

回答by Eduardo Mioto

You may use the tag to provide you these kind of formattings, such as money, data, time, and many others.

您可以使用标签为您提供这些类型的格式,例如金钱、数据、时间等等。

You may add on you JSP the reference: <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

您可以在 JSP 中添加参考: <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

And use the formatting as: <fmt:formatDate pattern="yyyy-MM-dd" value="${now}" />

并使用格式为: <fmt:formatDate pattern="yyyy-MM-dd" value="${now}" />

Follows below a reference:

下面是一个参考:

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

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

回答by Remy Mellet

To precise Eduardo answer:

准确的爱德华多回答:

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

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