12

My Domain 对象有几个 Joda-TimeDateTime字段。当我使用 SimpleJdbcTemplate 读取数据库值时:

患者患者 = jdbc.queryForObject(sql, new BeanPropertyRowMapper(Patient.class), patientId);

它只是失败了,令人惊讶的是,没有记录任何错误。我想这是因为timestamp解析到DateTime不与 Jdbc 一起使用。

如果可以继承和覆盖BeanPropertyRowMapper并指示将所有java.sql.Timestamp和转换java.sql.DateDateTime,那就太好了,并且可以节省很多额外的代码。

有什么建议吗?

4

3 回答 3

22

正确的做法是继承BeanPropertyRowMapper、覆盖initBeanWrapper(BeanWrapper)和注册自定义属性编辑器:

public class JodaDateTimeEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(final String text) throws IllegalArgumentException {
        setValue(new DateTime(text)); // date time in ISO8601 format
                                      // (yyyy-MM-ddTHH:mm:ss.SSSZZ)
    }
    @Override
    public void setValue(final Object value) {
        super.setValue(value == null || value instanceof DateTime ? value
                                        : new DateTime(value));
    }
    @Override
    public DateTime getValue() {
        return (DateTime) super.getValue();
    }
    @Override
    public String getAsText() {
        return getValue().toString(); // date time in ISO8601 format
                                      // (yyyy-MM-ddTHH:mm:ss.SSSZZ)
    }
}
public class JodaTimeSavvyBeanPropertyRowMapper<T>
                  extends BeanPropertyRowMapper<T> {
    @Override
    protected void initBeanWrapper(BeanWrapper bw) {
        bw.registerCustomEditor(DateTime.class, new JodaDateTimeEditor());
    }
}
于 2011-10-12T14:59:18.827 回答
2

查看BeanPropertyRowMapper实现,它设置字段的方式是:

Object value = getColumnValue( rs, index, pd );

if (logger.isDebugEnabled() && rowNumber == 0) {
    logger.debug("Mapping column '" + column + "' to property '" +
    pd.getName() + "' of type " + pd.getPropertyType());
}
try {
    bw.setPropertyValue(pd.getName(), value);
}

其中getColumnValue(rs, index, pd);委托给JdbcUtils.getResultSetValue

in 中的那个pd字段getColumnValue是实际的“ p roperty d escriptor”,它在 ( pd.getPropertyType()) 中JdbcUtils用作要映射到的字段类型。

如果您查看方法的JdbcUtils代码getResultSetValue,您会发现它只是从一个if语句到另一个语句,以匹配pd.getPropertyType()所有标准类型。当它找不到时,由于DateTime不是“标准”类型,它依赖于rs.getObject()

} else {
// Some unknown type desired -> rely on getObject.

然后,如果此对象是 SQL Date ,则它将其转换为 a Timestamp,并返回设置为DateTime您的域 => 失败的字段。

因此,似乎没有直接的方法将Date/TimestampDateTime转换器注入到BeanPropertyRowMapper. 因此,实现您自己的 RowMapper 会更简洁(并且性能更高)。

如果您想在控制台中查看映射错误,请将您的日志记录级别设置org.springframework.jdbc为“调试”或更好的“跟踪”以查看究竟发生了什么。

您可以尝试的一件事,我没有测试过,是扩展 aBeanPropertyRowMapper并覆盖DateTime类型 in 的属性:

/**
 * Initialize the given BeanWrapper to be used for row mapping.
 * To be called for each row.
 * <p>The default implementation is empty. Can be overridden in subclasses.
 * @param bw the BeanWrapper to initialize
 */
 protected void initBeanWrapper(BeanWrapper bw) {}
于 2011-10-12T02:43:49.553 回答
1

@Sean Patrick Floyd 的答案是完美的,直到您没有很多自定义类型。

这是一个基于使用扩展的通用的、可配置的:

public class CustomFieldTypeSupportBeanPropertyRowMapper<T> extends BeanPropertyRowMapper<T> {
  private Map<Class<?>, Handler> customTypeMappers = new HashMap<Class<?>, Handler>();

  public CustomFieldTypeSupportBeanPropertyRowMapper() {
    super();
  }

  public CustomFieldTypeSupportBeanPropertyRowMapper(Class<T> mappedClass, boolean checkFullyPopulated) {
    super(mappedClass, checkFullyPopulated);
  }

  public CustomFieldTypeSupportBeanPropertyRowMapper(Class<T> mappedClass) {
    super(mappedClass);
  }

  public CustomFieldTypeSupportBeanPropertyRowMapper(Class<T> mappedClass, Map<Class<?>, Handler> customTypeMappers) {
    super(mappedClass);
    this.customTypeMappers = customTypeMappers;
  }

  @Override
  protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException {
    final Class<?> current = pd.getPropertyType();
    if (customTypeMappers.containsKey(current)) {
      return customTypeMappers.get(current).f(rs, index, pd);
    }
    return super.getColumnValue(rs, index, pd);
  }

  public void addTypeHandler(Class<?> class1, Handler handler2) {
    customTypeMappers.put(class1, handler2);
  }

  public static interface Handler {
    public Object f(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException;
  }
}
于 2014-07-23T13:19:36.840 回答