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

布莱斯·朗卡斯(Brice Roncace)

这是一个简单的value bean,它带有Spring的新的(从3.0版本开始)便捷@DateTimeFormat注释(据我所知PropertyEditor,它按照此SO问题取代了3.0之前的custom需求):

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 ELLocalDate以相同的MM/dd/yyyy格式在JSP视图中显示创建的属性,如下所示(假设我的spring控制器向模型添加了小部件属性):

${widget.created}

不幸的是,这只会显示默认toString格式LocalDateyyyy-MM-dd格式)。我了解,如果我使用spring的form标签,则日期将根据需要显示:

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

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

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

编辑

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

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

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

布莱斯·朗卡斯(Brice Roncace)

我感到沮丧的是,Spring开发人员决定不将Unified EL(JSP 2.1+中使用的表达语言)与Spring EL集成在一起,说明:

在我们的开发重点方面,JSP和JSF都没有优势。

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

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

ELResolver在web.xml中注册

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

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

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在 JSP 页面中打印 Spring MVC 模型值

来自分类Dev

如何在jsp中调用Spring MVC控制器

来自分类Dev

如何在Spring MVC中禁用对JSP URL的处理?

来自分类Dev

如何在Spring MVC中禁用对JSP URL的处理?

来自分类Dev

如何在Spring MVC JSP中动态分配值给禁用属性

来自分类Dev

Spring MVC:如何在处理程序方法中获取jsp文件的名称

来自分类Dev

如何在spring mvc的点击事件中将jsp页面注入到div中

来自分类Dev

如何使用Spring Data Elasticsearch正确格式化日期

来自分类Dev

Spring MVC-如何在jsp页面上显示CSV文件中的每一行数据?

来自分类Dev

如何重新格式化显示的日期?

来自分类Dev

如何在Spring中将map(master)值设置为bean?如何在jsp中显示?

来自分类Dev

如何在spring-mvc中为同一jsp页面在同一Controller上创建两个动作

来自分类Dev

如何在JSP中显示Spring Webflow的“ flowScope”的内容?

来自分类Dev

如何使用Spring MVC在JSP上显示图像

来自分类Dev

如何在 Spring MVC 的 EL 中显示现有和新创建的值?

来自分类Dev

如何通过Spring MVC在JSP中包含js和CSS

来自分类Dev

如何使用JavaScript在Spring MVC中获得对JSP的Unicode响应

来自分类Dev

在Spring MVC项目的“ jsp”中如何使用“ css”?

来自分类Dev

如何在 CanvasJS 图表中显示格式化的日期时间?

来自分类Dev

如何在Spring MVC中链接页面

来自分类Dev

如何在Spring MVC中链接页面

来自分类Dev

如何在Spring MVC中实现模型?

来自分类Dev

如何在Spring MVC中检测错误

来自分类Dev

如何在Spring MVC中利用url?

来自分类Dev

如何在spring mvc中输出json

来自分类Dev

如何在 spring mvc 中配置 JPA?

来自分类Dev

如何在Hibernate,Spring,JSP中从db中获取多行?

来自分类Dev

如何在Spring Boot中启用JSP页面?

来自分类Dev

如何将DatePicker中的日期值存储到格式化的String值中?

Related 相关文章

  1. 1

    如何在 JSP 页面中打印 Spring MVC 模型值

  2. 2

    如何在jsp中调用Spring MVC控制器

  3. 3

    如何在Spring MVC中禁用对JSP URL的处理?

  4. 4

    如何在Spring MVC中禁用对JSP URL的处理?

  5. 5

    如何在Spring MVC JSP中动态分配值给禁用属性

  6. 6

    Spring MVC:如何在处理程序方法中获取jsp文件的名称

  7. 7

    如何在spring mvc的点击事件中将jsp页面注入到div中

  8. 8

    如何使用Spring Data Elasticsearch正确格式化日期

  9. 9

    Spring MVC-如何在jsp页面上显示CSV文件中的每一行数据?

  10. 10

    如何重新格式化显示的日期?

  11. 11

    如何在Spring中将map(master)值设置为bean?如何在jsp中显示?

  12. 12

    如何在spring-mvc中为同一jsp页面在同一Controller上创建两个动作

  13. 13

    如何在JSP中显示Spring Webflow的“ flowScope”的内容?

  14. 14

    如何使用Spring MVC在JSP上显示图像

  15. 15

    如何在 Spring MVC 的 EL 中显示现有和新创建的值?

  16. 16

    如何通过Spring MVC在JSP中包含js和CSS

  17. 17

    如何使用JavaScript在Spring MVC中获得对JSP的Unicode响应

  18. 18

    在Spring MVC项目的“ jsp”中如何使用“ css”?

  19. 19

    如何在 CanvasJS 图表中显示格式化的日期时间?

  20. 20

    如何在Spring MVC中链接页面

  21. 21

    如何在Spring MVC中链接页面

  22. 22

    如何在Spring MVC中实现模型?

  23. 23

    如何在Spring MVC中检测错误

  24. 24

    如何在Spring MVC中利用url?

  25. 25

    如何在spring mvc中输出json

  26. 26

    如何在 spring mvc 中配置 JPA?

  27. 27

    如何在Hibernate,Spring,JSP中从db中获取多行?

  28. 28

    如何在Spring Boot中启用JSP页面?

  29. 29

    如何将DatePicker中的日期值存储到格式化的String值中?

热门标签

归档