我是靠谱客的博主 潇洒小懒虫,这篇文章主要介绍Java for Web学习笔记(一二五)映射(1):再谈converter,现在分享给大家,希望可以做个参考。

我们在《Java for Web学习笔记(一零八):再谈Entity映射(1)数据转换》中已经给出了通过转换器将数据库列的信息和指定类属性进行转换的例子。

原生JDBC的时间日期转换

JDBC的版本

我们原来使用的mysql-connector-java-5.1.x支持多个JDBC的版本,我们可以通过下面的原生jdbc代码来检查当前使用的版本:

复制代码
1
2
3
4
5
6
7
8
try(Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost/test?user=test&password=123456");){ DatabaseMetaData meta = connection.getMetaData(); log.info("Dirver version is {}",meta.getDriverVersion()); log.info("JDBC version {}.{}", meta.getJDBCMajorVersion(),meta.getJDBCMinorVersion()); }

在我的开发环境中显示如下:

复制代码
1
2
20180601 11:28:15.781 [localhost-startStop-1] [INFO ] TestService:41 init() - Dirver version is mysql-connector-java-5.1.46 ( Revision: 9cc87a48e75c2d2e87c1a293b2862ce651cb256e ) 20180601 11:28:15.781 [localhost-startStop-1] [INFO ] TestService:42 init() - JDBC version 4.0

其实在spring framework启动过程中也有相关的显示:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
20180228 09:16:39.460 [localhost-startStop-1] [DEBUG] (Hibernate) JdbcEnvironmentInitiator: Database -> name : MySQL version : 5.7.21-0ubuntu0.16.04.1 major : 5 minor : 7 20180228 09:16:39.460 [localhost-startStop-1] [DEBUG] (Hibernate) JdbcEnvironmentInitiator: Driver -> name : MySQL Connector Java version : mysql-connector-java-5.1.44 ( Revision: b3cda4f864902ffdde495b9df93937c3e20009be ) major : 5 minor : 1 20180228 09:16:39.460 [localhost-startStop-1] [DEBUG] (Hibernate) JdbcEnvironmentInitiator: JDBC version : 4.0 20180228 09:16:39.495 [localhost-startStop-1] [INFO ] (Hibernate) Dialect: HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect

要确保开发环境中使用JDBC 4.2,可以使用mysql-connector-java-8.0.11.jar。

SQL中datetime的转换

datetime在原生jdbc的api中可以转换为java.sql.timestamp,java.sql.date和java.sql.time。其中java.sql.timestamp可以很方便转换为java 8的Instant和LocalDateTime。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// -------------- Read --------------- //datetime在原生jdbc的api中可以转换为java.sql.timestamp,java.sql.date和java.sql.time。 java.sql.Date date = resultSet.getDate(1); java.sql.Time time = resultSet.getTime(1); java.sql.Timestamp timestamp = resultSet.getTimestamp(1); //java.sql.timestamp可以很方便转换为java 8的Instant和LocalDateTime LocalDateTime localDateTime = timestamp.toLocalDateTime(); Instant instant = timestamp.toInstant(); // 也可以通过getObject的方式直接转为java 8的LocalDateTime, LocalDate和LocalTime,但在我们的 // 测试中不能转成Instant, OffsetDateTime, ZonedDateTime,无论是JDBC4.0还是4.2,都不行。 // JDBC 4.2的API是提供了Instant, OffsetDateTime, ZonedDateTime,但具体的实现还在 // mysql-connector-java, 而mysql-connector-java上不支持。估计和Mysql里面的datetime和 // timestamp不带timezone信息有关。 LocalDateTime localDateTime = resultSet.getObject(1, LocalDateTime.class); LocalDate localDate = resultSet.getObject(1, LocalDate.class); LocalTime localTime = resultSet.getObject(1, LocalTime.class); // -------------- Write --------------- // LocalDateTime可以通过SetObject()直接设置,但Instant,OffsetDateTime,ZonedDateTime不行, // 会抛出异常。同样JDBC 4.2的api是提供了相关接口,但是mysql-connector-java上不支持。 statement.setObject(1, LocalDateTime.now(),JDBCType.TIMESTAMP); statement.setObject(1, LocalDateTime.now());

Attribute Converter

要进行转换,还是需要使用转换器。下面以数据库的timestamp(或者datetime),在JPA中对应java.sql.timestamp和Instant之间的转换为例子。

创建转换器

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//【1】进行Converter的标记,并实现AttributeConverter接口 @Converter public class InstantConverter implements AttributeConverter<Instant, Timestamp>{ //【2】实现AttributeConverter,进行类型转换。这里需要提醒的是,一定要记得处理null。 @Override public Timestamp convertToDatabaseColumn(Instant instant) { return instant == null ? null:new Timestamp(instant.toEpochMilli()); } @Override public Instant convertToEntityAttribute(Timestamp dbData) { return dbData == null ? null:Instant.ofEpochMilli(dbData.getTime()); } }

转换器需要在entity的扫描范围内

我们在root上下文的entityManagerFactory()中,确保在扫描范围内

复制代码
1
2
3
4
5
6
7
8
9
10
@Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(){ ... ... LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); // 例子中entity放在cn.wei.flowingflying.chapter24.entities内,转换器放在 // cn.wei.flowingflying.chapter24.converters包内 factory.setPackagesToScan("cn.wei.flowingflying.chapter24.entities", "cn.wei.flowingflying.chapter24.converters"); ... ... }

在entity上加载转换器

方式1:在属性上加载

复制代码
1
2
3
4
5
6
@Entity public class MyEntity{ @Convert(converter = InstantConverter.class) private Instant dateCreated; ..... }

方式2:在方法上加载

复制代码
1
2
3
4
5
6
@Entity public class MyEntity{ @Convert(converter = InstantConverter.class) private Instant dateCreated; ..... }

方式3:在类上加载

复制代码
1
2
3
4
5
@Convert(attributeName = "dateCreated", converter = InstantConverter.class) @Entity public class MyEntity{ private Instant dateCreated; }
复制代码
1
2
3
4
5
6
7
8
@Converts({ @Convert(attributeName = "dateCreated", converter = InstantConverter.class), @Convert(attributeName = "dateModified", converter = InstantConverter.class) }) @Entity public class MyEntity{ private Instant dateCreated; }

相关链接:我的Professional Java for Web Applications相关文章

最后

以上就是潇洒小懒虫最近收集整理的关于Java for Web学习笔记(一二五)映射(1):再谈converter的全部内容,更多相关Java内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部