这里是一个简单的值bean,用Spring的新版本(3.0版本)方便@DateTimeFormat
注释注释(据我所知,它取代了自定义PropertyEditor
的3.0之前的需求根据{{3}}):
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 EL以相同的LocalDate
格式在JSP视图中显示创建的MM/dd/yyyy
属性(假设我的spring控制器添加了一个widget属性)到模型):
${widget.created}
不幸的是,这只会显示toString
的默认LocalDate
格式(格式为yyyy-MM-dd
)。我知道如果我使用spring的表单标签,日期会根据需要显示:
<form:form commandName="widget">
Widget created: <form:input path="created"/>
</form:form>
但我想在不使用spring form标签的情况下显示格式化的日期字符串。甚至是JSTL的fmt:formatDate
标签。
来自Struts2,HttpServletRequest
被包装在一个this SO question中,它启用了这样的EL表达式来实际查询OGNL值堆栈。所以我想知道spring是否提供类似的东西以允许转换器执行?
修改
我也意识到,当使用spring eval
标记时,日期将根据@DateTimeFormat
注释中定义的模式显示:
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<spring:eval expression="widget.created"/>
有趣的是,当使用自定义PropertyEditor
格式化日期时,此标记不会调用PropertyEditor
的{{1}}方法,因此默认为{{1} } StrutsRequestWrapper
。无论如何,我仍然想知道是否有办法实现日期格式化而不必使用标记 - 仅使用标准JSP EL。
答案 0 :(得分:8)
您可以使用该标记为您提供这些格式,例如金钱,数据,时间等等。
您可以在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
答案 1 :(得分:4)
准确地说Eduardo回答:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<fmt:formatDate pattern="MM/dd/yyyy" value="${widget.created}" />
答案 2 :(得分:2)
JSP和JSF在我们的发展重点方面都不具备强大的地位。
但是从引用的JIRA门票中获取灵感,我创建了一个自定义ELResolver,如果已解析的值为java.time.LocalDate
或java.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;
}
}
在web.xml中注册ELResolver
:
<listener>
<listener-class>com.company.el.DateTimeFormatAwareElResolver</listener-class>
</listener>
现在当我的jsp中有${widget.created}
时,显示的值将根据@DateTimeFormat
注释进行格式化!
此外,如果jsp需要LocalDate
或LocalDateTime
对象(而不仅仅是格式化的String表示),您仍然可以使用直接方法调用来访问对象本身,如:{{1 }}
答案 3 :(得分:1)
我也不想通过标签进行任何格式化。我意识到这可能不是您正在寻找的解决方案,并且正在寻找通过spring注释实现此目的的方法。然而,在过去,我使用了以下工作:
使用以下签名创建一个新的getter:
public String getCreatedDateDisplay
(如果您愿意,可以更改吸气剂的名称。)
在getter中,使用SimpleDateFormat等格式化程序根据需要格式化created
日期属性。
然后您可以从JSP中调用以下内容
${widget.createDateDisplay}