我还不知道如何在JSP中显示java.time.LocalDate
值。
在我的JSP中,我有这样的:
<fmt:formatDate value="${std.datum}" type="date" pattern="dd.MM.yyyy" var="stdDatum" />
std.datum
的类型是java.time.LocalDate
javax.el.el异常:
无法转换类型类的2015-02-14java.time.LocalDate到类java.util.Date
我想是转换吗?
那么,是否可以使用<fmr:formatDate>
操作格式化LocalDate类的实例?
我想是转换吗?
是的,这是一个与转换相关的异常。
解决方案
您可以首先使用JSTL的"I18n功能格式化标记库"中的<fmt:parseDate>
操作进行转换,然后用<fmt:formatDate>
动作执行格式化。
这里有一个例子:
<fmt:parseDate value="${std.datum}" type="date" pattern="yyyy-MM-dd" var="parsedDate" />
<fmt:formatDate value="${parsedDate}" type="date" pattern="dd.MM.yyyy" var="stdDatum" />
该解决方案也在"JavaServer页面"中介绍™标准标签库(JSTL)"规范1.2版(见第109页)。
这是一个老问题,但我发现在这种情况下最好做一个自定义tld:没有任何到String的双重转换。
创建自己的tld文件,然后覆盖FormatDate类。最后,声明您自己的自定义前缀,并使用custom:formatDate而不是fmt:formatDate。
这是一个简化版
JSP中的用法:
<%@ taglib uri="/WEB-INF/custom" prefix="custom" %>
...
<custom:formatDate value="${std.datum}" pattern="dd/MM/yyyy" />
WEB-INF/custom.tld文件
<?xml version="1.0" encoding="UTF-8"?>
<tag ib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd">
<tag>
<description>
FormatDate with java8 type
</description>
<name>formatDate</name>
<tag-class>com.custom.tag.FormatDateTag</tag-class>
<body-content>empty</body-content>
<attribute>
<description>
Date and/or time to be formatted.
</description>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>
Custom formatting style for dates and times.
</description>
<name>pattern</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
然后java类标记文件
public class FormatDateTag extends TagSupport {
protected Temporal value;
protected String pattern;
private String var;
private int scope;
public FormatDateTag()
{
super ();
init ();
}
private void init()
{
this.pattern = this.var = null;
this.value = null;
this.scope = PageContext.PAGE_SCOPE;
}
public void setVar(final String var)
{
this.var = var;
}
public void setScope(final String scope)
{
this.scope = Util.getScope (scope);
}
public void setValue(final Temporal value)
{
this.value = value;
}
public void setPattern(final String pattern)
{
this.pattern = pattern;
}
@Override
public int doEndTag() throws JspException
{
String formatted = null;
if (this.value == null)
{
if (this.var != null)
{
this.pageContext.removeAttribute (this.var, this.scope);
}
return EVAL_PAGE;
}
// Create formatter
if (this.pattern != null)
{
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern (this.pattern);
formatted = formatter.format (this.value);
}
else
{
// no formatting locale available, use Date.toString()
formatted = this.value.toString ();
}
if (this.var != null)
{
this.pageContext.setAttribute (this.var, formatted, this.scope);
}
else
{
try
{
this.pageContext.getOut ().print (formatted);
}
catch (final IOException ioe)
{
throw new JspTagException (ioe.toString (), ioe);
}
}
return EVAL_PAGE;
}
@Override
public void release()
{
init ();
}
}
我想避免更改<fmt:formatDate/>在使用的地方,所以我代替创建了以下两个类:
首先,一个转换器来转换(一些)java.time类。它检查java.util.Date是否是目标类型,如果不是,则不执行任何操作。它支持源时间为java.util.Date(包括java.sql.Timestamp和java.sql.Date)、LocalDate、LocalDateTime、ZonedDateTime、Instant或Long(时间单位为毫秒)。
package com.example.elresolvers;
import javax.el.ELContext;
import javax.el.TypeConverter;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
@SuppressWarnings("UseOfObsoleteDateTimeApi")
public class DateFromJavaTimeResolver extends TypeConverter {
@Override
public Object convertToType(ELContext context, Object obj, Class<?> type) {
Date date = null;
if (Date.class.isAssignableFrom(type)) {
if (obj instanceof Date) {
date = (Date) obj;
} else {
ZonedDateTime zdt = null;
if (obj instanceof LocalDate) {
zdt = ((LocalDate) obj).atStartOfDay(ZoneId.systemDefault());
} else if (obj instanceof LocalDateTime) {
zdt = ((LocalDateTime) obj).atZone(ZoneId.systemDefault());
} else if (obj instanceof ZonedDateTime) {
zdt = (ZonedDateTime) obj;
} else if (obj instanceof Instant) {
date = Date.from((Instant) obj);
} else if (obj instanceof Long) {
date = new Date((Long) obj);
}
if (zdt != null) {
date = Date.from(zdt.toInstant());
}
}
context.setPropertyResolved(date != null);
}
return date;
}
}
接下来,一个ServletContextListener类来注册转换器,以便与JSP:一起使用
package com.example.web;
import com.example.elresolvers.DateFromJavaTimeResolver;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspFactory;
public class JspElResolverInitListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
JspApplicationContext context = JspFactory.getDefaultFactory().getJspApplicationContext(servletContext);
context.addELResolver(new DateFromJavaTimeResolver());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
最后,web.xml中的一个条目(如果您没有使用注释或其他方式):
<listener>
<listener-class>com.example.web.JspElResolverInitListener</listener-class>
</listener>
Java:
public class DateTimeUtil {
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd.MM.yyyy");
public static String toString(LocalDateTime ldt) {
return ldt.format(DATE_FORMATTER);
}
JSP:
<%@ page import="ru.javaops.topjava.util.DateTimeUtil" %>
...
<%=DateTimeUtil.toString(std.getDatum())%>