这是一个简单的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
格式LocalDate
(yyyy-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
格式化日期,该标签不会调用该PropertyEditor
的getAsText
方法,因此默认为DateFormat.SHORT
如在该文档中描述。无论如何,我仍然想知道是否有一种无需使用标签即可实现日期格式的方法-仅使用标准的JSP EL。
我感到沮丧的是,Spring开发人员决定不将Unified EL(JSP 2.1+中使用的表达语言)与Spring EL集成在一起,说明:
在我们的开发重点方面,JSP和JSF都没有优势。
但是从引用的JIRA票证中获得启发后,我创建了一个自定义的ELResolver,如果解析的值为ajava.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;
}
}
ELResolver
在web.xml中注册:
<listener>
<listener-class>com.company.el.DateTimeFormatAwareElResolver</listener-class>
</listener>
现在,当我${widget.created}
在jsp中使用该命令时,显示的值将根据@DateTimeFormat
注释进行格式化!
另外,如果jsp需要LocalDate
orLocalDateTime
对象(而不仅仅是格式化的String表示形式),您仍然可以使用直接方法调用来访问对象本身,例如:${widget.getCreated()}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句