Mybatis生成的映射实体类对应的日期类型是Date类型,我们应该改成LocatDateTime等Java8新出的安全日期类型,但是这样实体类在mybatis执行映射解析上跟数据库的类型是匹配不上的,会报类型格式不匹配等问题。
解决方法:统计设置日期类型转换,执行查询获取的日期需要映射为LocatDateTime类型,执行新增更新等操作时将LocatDateTime日期对象转成与数据库相匹配的类型。代码如下:
import com.common.constant.DateConstant;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.springframework.stereotype.Component;
import java.sql.*;
import java.time.LocalDateTime;
import java.time.ZoneId;
/**
* Description:Mybatis支持LocalDateTime格式化
* @version 1.0.0
* @date 2021/10/8
*/
@Component
//定义转换器支持的JAVA类型
@MappedTypes(LocalDateTime.class)
//定义转换器支持的数据库类型
@MappedJdbcTypes(value = JdbcType.TIMESTAMP, includeNullJdbcType = true)
public class CustomLocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, LocalDateTime parameter, JdbcType jdbcType)
throws SQLException {
if (parameter != null) {
// ps.setString(i, DateConstant.FORMAT_YYYY_MM_DD_HH_MM_SS.format(parameter));
// 不用解析为字符串,不然与数据库TIMESTAMP类型不匹配
// setDate(),sql.Date只能精确到年月日,采用Timestamp时间戳方式
ps.setTimestamp(i, Timestamp.valueOf(parameter));
}
}
@Override
public LocalDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {
String target = rs.getString(columnName);
if (StringUtils.isBlank(target)) {
return null;
}
// 日期值后面多了.0,去掉
target = target.substring(0, target.length() - 2);
return LocalDateTime.parse(target, DateConstant.FORMAT_YYYY_MM_DD_HH_MM_SS);
}
@Override
public LocalDateTime getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String target = rs.getString(columnIndex);
if (StringUtils.isBlank(target)) {
return null;
}
// 日期值后面多了.0,去掉
target = target.substring(0, target.length() - 2);
return LocalDateTime.parse(target, DateConstant.FORMAT_YYYY_MM_DD_HH_MM_SS);
}
@Override
public LocalDateTime getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String target = cs.getString(columnIndex);
if (StringUtils.isBlank(target)) {
return null;
}
// 日期值后面多了.0,去掉
target = target.substring(0, target.length() - 2);
return LocalDateTime.parse(target, DateConstant.FORMAT_YYYY_MM_DD_HH_MM_SS);
}
}
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.mapper.autoconfigure.ConfigurationCustomizer;
/**
* Description:Mybatis配置
* @version 1.0.0
* @date 2021/10/8
*/
@Configuration
public class MybatisConfigurationCustomizer implements ConfigurationCustomizer {
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
typeHandlerRegistry.register(CustomLocalDateTimeTypeHandler.class);
}
}
import java.time.format.DateTimeFormatter;
/**
* Description:日期常量
* @version 1.0.0
* @date 2021/10/8
*/
public interface DateConstant {
/**
* Java8日期格式
*/
DateTimeFormatter FORMAT_YYYY_MM_DD = DateTimeFormatter.ofPattern(YYYY_MM_DD);
DateTimeFormatter FORMAT_YYYY_MM_DD_HH_MM_SS = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS);
}
这样与数据库映射实体类的日期属性改为LocatDateTime类型时,也可以正常执行Mybatis操作,代码实现主要也是监听TIMESTAMP类型的sql字段进行解析转化,如果是获取则转化为LocatDateTime日期类,如果是更新则解析成java.sql包下可与数据库类型匹配的时间戳类型。
另外,如下是统一按日期格式json序列化LocatDateTime日期类型的代码:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.common.constant.DateConstant;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* Description:统一json日期格式配置
* @version 1.0.0
* @date 2021/10/8
*/
@Configuration
public class ObjectMapperConfiguration {
private static ObjectMapper MAPPER;
public static ObjectMapper getMapper() {
if (MAPPER != null) {
return MAPPER;
}
return new ObjectMapper();
}
@Bean
@Primary
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
MAPPER = builder.createXmlMapper(false).build();
return MAPPER;
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer enumCustomizer() {
return builder -> builder
.deserializerByType(LocalDateTime.class,
new LocalDateTimeDeserializer(DateConstant.FORMAT_YYYY_MM_DD_HH_MM_SS))
.deserializerByType(LocalDate.class,
new LocalDateDeserializer(DateConstant.FORMAT_YYYY_MM_DD_HH_MM_SS))
.serializerByType(LocalDateTime.class,
new LocalDateTimeSerializer(DateConstant.FORMAT_YYYY_MM_DD_HH_MM_SS))
.serializerByType(LocalDate.class, new LocalDateSerializer(DateConstant.FORMAT_YYYY_MM_DD_HH_MM_SS))
;
}
}