java8新增的语法糖除了lamda,stream,还引入了新的日期时间类,支持国际化
引入的类简单分类如下
====
时间日期类
LocalDateTime 不可变的类,该类代表不带时区的日期、时间,如:2019-02-24T10:20:09
LocalDate 不可变的类,该类代表不带时区的日期,如:2019-02-24
LocalTime 不可变的类,该类代表不带时区的时间,如:10:20:09
====
年月日
Year:该类仅代表年,如:2019
YearMonth:该类仅代表年月 如:2019-02
MonthDay:该类仅代表月日,如:09-20
Month:该类是一个枚举类,定义了一月到十二月的枚举值
DayOfWeek:该类是一个枚举类,定义了周日到周六的枚举值
====
时区
ZonedDateTime:该类代表一个时区化的日期、时间 如:2022-01-09T19:50:54.751+08:00[Asia/Shanghai]
ZonedId:该类代表一个时区 Asia/Shanghai
Instant:不可变的类,代表时间戳,精确到纳秒 2022-01-09T11:52:37.879Z
====
时间段
Period:一段日期
Duration:一段时间
====
日期格式化
DateTimeFormatter:可以格式化日期时间,线程安全
一、旧的日期时间类存在的问题
旧类存在的问题如下
1.SimpleDateFormat 线程安全问题
2.时间加减繁琐
3.时间比较相等时繁琐
4.时区支持 Date不支持时区,引入了Calendar和TimeZone类后才支持
5.国际化问题,需要在DateFormat.getDateTimeInstance 指定Locale参数
二、与Joda-Time思想借鉴
Joda-Time常用的类如下
- Instant - 不可变的类,用来表示时间轴上一个瞬时的点(时间戳)
- DateTime - 不可变的类,用来替换JDK的Calendar类
- LocalDate - 不可变的类,表示一个本地的日期,而不包含时间部分(没有时区信息)
- LocalTime - 不可变的类,表示一个本地的时间,而不包含日期部分(没有时区信息)
- LocalDateTime - 不可变的类,表示一个本地的日期-时间(没有时区信息)
java8相当于去掉了DateTime这个不可变类,使用ZonedDateTime进行替代,增加了一些时区处理类
三、与传统的日期时间类互转问题
1.Date转LocalDateTime
//Date转LocalDateTime 方式一
//示例 Sun Jan 09 16:49:04 CST 2022 --> 2022-01-09T16:49:04.264
public LocalDateTime date2LocalDateTime(Date date) {
//方式一
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
return localDateTime;
}
//Date转LocalDateTime 方式二
//示例 Sun Jan 09 16:49:04 CST 2022 --> 2022-01-09T16:49:04.264
public LocalDateTime date2LocalDateTime2(Date date) {
//方式二 直接使用LocalDateTime.ofInstant
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
return localDateTime;
}
2.LocalDateTime转Date
//LocalDateTime转Date
//示例 2022-01-09T16:53:08.717 -->Sun Jan 09 16:53:08 CST 2022
public Date localDateTime2Date(LocalDateTime localDateTime) {
Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
return date;
}
同类方法LocalDate转Date
Date date = Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
3.Calendar转LocalDateTime
//Calendar转LocalDateTime
//示例 Sun Jan 09 16:49:04 CST 2022 --> 2022-01-09T16:49:04.264
public LocalDateTime calendar2LocalDateTime(Calendar calendar) {
//方式一
LocalDateTime localDateTime = calendar.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
//方式二
LocalDateTime localDateTime2 = LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());
return localDateTime;
}
4.LocalDateTime转Calendar
//LocalDateTime转Calendar
public Calendar localDateTime2Calendar(LocalDateTime localDateTime) {
Calendar localDateTimeCalendar = GregorianCalendar.from(ZonedDateTime.of(localDateTime, ZoneId.systemDefault()));
return localDateTimeCalendar;
}
四、常用方法
1.当前时间和毫秒时间戳
//当前时间LocalDateTime
//示例 2022-01-09T17:26:43.537
public LocalDateTime currentLocalDateTime(){
LocalDateTime now = LocalDateTime.now();
return now;
}
//当前时间时间戳 毫秒
//示例 1641720403538
public Long currentMillisecondTimestamp() {
//获取毫秒数
Long milliSecond = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
return milliSecond;
}
2.年月日时分秒获取
LocalDateTime localDateTime = LocalDateTime.now();
localDateTime.getYear(); //2022
localDateTime.getMonth(); //JANUARY
localDateTime.getDayOfMonth();//9
localDateTime.getHour(); //17
localDateTime.getMinute(); //32
localDateTime.getSecond(); //25
3.时间加减
LocalDateTime localDateTime1 = localDateTime.plusYears(1).plusMonths(1).plusDays(1).plusHours(1).plusMinutes(1).plusSeconds(1);
注意调用plusXXX不会改变原来的localDateTime值,需要用变量接受加完后的值,plus负值相当于减法
4.时间比较
localDateTime.isBefore(localDateTime1);
localDateTime.isEqual(localDateTime1);
localDateTime.isAfter(localDateTime1);
返回的是 boolean 类型 跟旧时间类相比,对于等于的判断不用写getTime再比较了
5.初始化指定日期时间
LocalDateTime of = LocalDateTime.of(2022, 1, 8, 8, 01, 46);
//结果 2022-01-08T08:01:46
使用LocalDateTime.of方法直接初始化
6.格式化日期
LocalDateTime转字符串
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String strDate = dateTimeFormatter.format(LocalDateTime.now());
System.out.println(strDate);
//2022-01-09 17:54:25
先定义DateTimeFormatter,然后调用format方法
字符串转LocalDateTime
DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String strDate2 = "2022-01-09 06:54:25";
LocalDateTime time1 = LocalDateTime.parse(strDate2, dateTimeFormatter1);
System.out.print(time1);
//2022-01-09T06:54:25
先定义DateTimeFormatter,然后调用parse方法
7.计算时间差
Duration.between方法,结果为后一个减去前一个,返回结果可以转秒数,分钟数
//localDateTime = 2022-01-09T18:13:02.750 localDateTime1=2022-03-08T08:01:46
Duration duration = Duration.between(localDateTime, localDateTime1);
System.out.println(duration); //PT1381H48M43.25S
System.out.println(duration.toDays()); //转天数 57
System.out.println(duration.toHours()); //转小时 1381
System.out.println(duration.toMinutes()); //转分钟数 82908
System.out.println(duration.getSeconds()); //转秒数 4974523
System.out.println(duration.toMillis()); //转毫秒数 4974523250
System.out.println(duration.toNanos()); //转纳秒数 4974523250000000
Period.between方法与Duration.between方法类似,只不过参数类型为LocalDate,返回值对应方法不一样,返回只是对应年月日相减,去除的是对应年月日的值
LocalDate start = LocalDate.of(2021,3,25);
LocalDate end = LocalDate.of(2022,5,29);
Period period = Period.between(start, end);
System.out.println(period); //P1Y2M4D
System.out.println(period.getYears()); //1
System.out.println(period.getMonths()); //2
System.out.println(period.getDays()); //4
注意Period的方法取的是对应位置相减的值,而Duration的方法取的是纳秒值换算后的值
ChronoUnit.YEARS.between方法,返回与Duration.between类似
LocalDateTime startDate = LocalDateTime.of(2020, 2, 20, 8, 1, 46);
LocalDateTime endDate = LocalDateTime.of(2021, 1, 15, 8, 1, 46);
long years = ChronoUnit.YEARS.between(startDate, endDate); //0
long months = ChronoUnit.MONTHS.between(startDate, endDate); //10
long weeks = ChronoUnit.WEEKS.between(startDate, endDate); //47
long days = ChronoUnit.DAYS.between(startDate, endDate); //330
long hours = ChronoUnit.HOURS.between(startDate, endDate); //7920
long minutes = ChronoUnit.MINUTES.between(startDate, endDate); //475200
long seconds = ChronoUnit.SECONDS.between(startDate, endDate); //28512000
long milis = ChronoUnit.MILLIS.between(startDate, endDate); //28512000000
long nano = ChronoUnit.NANOS.between(startDate, endDate); //28512000000000000
ChronoUnit.YEARS.between也可用于LocalDate,但是ChronoUnit.HOURS.between不能用于LocalDate会报UnsupportedTemporalTypeException异常,网上也有个Instant不能用于ChronoUnit.YEARS的讨论,猜想应该是时区的问题,假设一个时间北京时间2000年2月29日8点东八区,此时对应美国中部时间 2000年2月28日18点(西四区),用LocalDateTime的plusYears加一年,一个实际上加365天,另一个加了366天。所以放到未确定时区的Instant(默认UTC+0),无法分辨应该是加365天还是366天
LocalDateTime的plusYears验证代码如下
//东八区2000-02-29 08:00:00 = 西四区 2000-02-28 18:00:00
LocalDateTime startDate = LocalDateTime.of(2000, 2, 29, 8, 0, 0);
LocalDateTime localDateTime1 = startDate.plusYears(1);
LocalDateTime localDateTime2 = startDate.plusDays(365);
System.out.println(localDateTime1); //2001-02-28T08:00
System.out.println(localDateTime2); //2001-02-28T08:00
LocalDateTime startDate2 = LocalDateTime.of(2000, 2, 28, 18, 0, 0);
LocalDateTime localDateTime21 = startDate2.plusYears(1);
LocalDateTime localDateTime22 = startDate2.plusDays(366);
System.out.println(localDateTime21); //2001-02-28T18:00
System.out.println(localDateTime22); //2001-02-28T18:00
五、json格式转换问题
在java里常用的json工具类有下面四个
jackson
fastjson
gson
json-lib(net.sf.json)
安卓里有个常用的org.json这里不介绍。
从序列化和反序列化调用的结果来看,fastjson最省事,其次是jackson。
1.json序列化及问题解决
下面用这四个工具类测试对时间类的转换结果
先用maven导入
<!--fastjson包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>
<!--Jackson包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<!--gson包-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<!--json-lib包-->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
定义实体
package com.vvvtimes.vo;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class DateVo implements Serializable {
private LocalDateTime localDateTime;
private LocalDate localDate;
private LocalTime localTime;
public LocalDateTime getLocalDateTime() {
return localDateTime;
}
public void setLocalDateTime(LocalDateTime localDateTime) {
this.localDateTime = localDateTime;
}
public LocalDate getLocalDate() {
return localDate;
}
public void setLocalDate(LocalDate localDate) {
this.localDate = localDate;
}
public LocalTime getLocalTime() {
return localTime;
}
public void setLocalTime(LocalTime localTime) {
this.localTime = localTime;
}
}
使用四个json工具类转换测试
DateVo dateVo = new DateVo();
dateVo.setLocalDateTime(LocalDateTime.now());
dateVo.setLocalDate(LocalDate.now());
dateVo.setLocalTime(LocalTime.now());
System.out.println(dateVo.getLocalDateTime());
//2022-01-15T22:19:37.752
System.out.println(dateVo.getLocalDate());
//2022-01-15
System.out.println(dateVo.getLocalTime());
//22:19:37.752
//jackson将对象转字符串
//1.创建objectmappter对象
ObjectMapper mapper=new ObjectMapper();
//2.调用mapper的writeValueAsString()方法把一个对象或集合转为json字符串
String jsonStr=mapper.writeValueAsString(dateVo);
System.out.println(jsonStr);
//结果
//{"localDateTime":{"dayOfMonth":15,"dayOfWeek":"SATURDAY","dayOfYear":15,"hour":22,"minute":10,"month":"JANUARY","monthValue":1,"nano":80000000,"second":48,"year":2022,"chronology":{"id":"ISO","calendarType":"iso8601"}},"localDate":{"year":2022,"month":"JANUARY","dayOfMonth":15,"dayOfWeek":"SATURDAY","dayOfYear":15,"monthValue":1,"chronology":{"id":"ISO","calendarType":"iso8601"},"era":"CE","leapYear":false},"localTime":{"hour":22,"minute":10,"second":48,"nano":81000000}}
//fastjson将对象转字符串
String str = JSON.toJSONString(dateVo);
System.out.println(str);
//结果
//{"localDate":"2022-01-15","localDateTime":"2022-01-15T22:13:18.689","localTime":"22:13:18.689"}
//gson将对象转字符串
Gson gson = new Gson();
String gsonStr = gson.toJson(dateVo);
System.out.println(str);
//结果
//{"localDate":"2022-01-15","localDateTime":"2022-01-15T22:14:54.209","localTime":"22:14:54.210"}
//json-lib将对象转字符串
JSONObject obj = JSONObject.fromObject(dateVo);
System.out.println(obj.toString());
//结果
//{"localDate":{"chronology":{"calendarType":"iso8601","id":"ISO"},"dayOfMonth":15,"dayOfWeek":"SATURDAY","dayOfYear":15,"era":"CE","leapYear":false,"month":"JANUARY","monthValue":1,"year":2022},"localDateTime":{"dayOfMonth":15,"dayOfWeek":"SATURDAY","dayOfYear":15,"hour":22,"minute":17,"month":"JANUARY","monthValue":1,"nano":952000000,"second":27,"year":2022},"localTime":{"hour":22,"minute":17,"nano":952000000,"second":27}}
可以看到jackson和json-lib转换的记过出乎我们的意料,并非正常的toString结果。
(1)解决序列化报错问题
对于jackson需要增加导入jackson-datatype-jsr310,mapper注册com.fasterxml.jackson.datatype.jsr310.JavaTimeModule并禁用Date转时间戳的序列化特性
maven导入代码
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.9.10</version>
</dependency>
jackson完整代码
//jackson将对象转字符串
//1.创建objectmappter对象
ObjectMapper mapper=new ObjectMapper();
//处理java8时间类型新增代码
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
//2.调用mapper的writeValueAsString()方法把一个对象或集合转为json字符串
String jsonStr=mapper.writeValueAsString(dateVo);
System.out.println(jsonStr);
//结果
//{"localDateTime":"2022-01-15T22:51:52.616","localDate":"2022-01-15","localTime":"22:51:52.616"}
json-lib解决方案
写三个JsonValueProcessor的实现类,调用前注册进去就OK
LocalDateJsonValueProcessor
package com.vvvtimes.util.jsonlib;
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
//序列化 实体类LocalDate --> JSONObject
public class LocalDateJsonValueProcessor implements JsonValueProcessor {
public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
private DateTimeFormatter formatter;
/**
* 构造方法.
*
* @param datePattern 日期格式
*/
public LocalDateJsonValueProcessor(String datePattern) {
try {
formatter = DateTimeFormatter.ofPattern(datePattern);
} catch (Exception ex) {
formatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN);
}
}
@Override
public Object processArrayValue(Object value, JsonConfig jsonConfig) {
return process(value);
}
@Override
public Object processObjectValue(String key, Object value,
JsonConfig jsonConfig) {
return process(value);
}
private Object process(Object value) {
return formatter.format((LocalDate) value);
}
}
LocalDateTimeJsonValueProcessor
package com.vvvtimes.util.jsonlib;
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
//序列化 实体类LocalDateTime --> JSONObject
public class LocalDateTimeJsonValueProcessor implements JsonValueProcessor {
public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS";
private DateTimeFormatter formatter;
/**
* 构造方法.
*
* @param datePattern 日期格式
*/
public LocalDateTimeJsonValueProcessor(String datePattern) {
try {
formatter = DateTimeFormatter.ofPattern(datePattern);
} catch (Exception ex) {
formatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN);
}
}
@Override
public Object processArrayValue(Object value, JsonConfig jsonConfig) {
return process(value);
}
@Override
public Object processObjectValue(String key, Object value,
JsonConfig jsonConfig) {
return process(value);
}
private Object process(Object value) {
return formatter.format((LocalDateTime) value);
}
}
LocalTimeJsonValueProcessor
package com.vvvtimes.util.jsonlib;
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
//序列化 实体类LocalTime --> JSONObject
public class LocalTimeJsonValueProcessor implements JsonValueProcessor {
public static final String DEFAULT_DATE_PATTERN = "HH:mm:ss.SSS";
private DateTimeFormatter formatter;
/**
* 构造方法.
*
* @param datePattern 日期格式
*/
public LocalTimeJsonValueProcessor(String datePattern) {
try {
formatter = DateTimeFormatter.ofPattern(datePattern);
} catch (Exception ex) {
formatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN);
}
}
@Override
public Object processArrayValue(Object value, JsonConfig jsonConfig) {
return process(value);
}
@Override
public Object processObjectValue(String key, Object value,
JsonConfig jsonConfig) {
return process(value);
}
private Object process(Object value) {
return formatter.format((LocalTime) value);
}
}
调用结果成功
DateVo dateVo = new DateVo();
dateVo.setLocalDateTime(LocalDateTime.now());
dateVo.setLocalDate(LocalDate.now());
dateVo.setLocalTime(LocalTime.now());
//json-lib将对象转字符串
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.registerJsonValueProcessor(LocalDate.class, new LocalDateJsonValueProcessor(
LocalDateJsonValueProcessor.DEFAULT_DATE_PATTERN));
jsonConfig.registerJsonValueProcessor(LocalDateTime.class, new LocalDateTimeJsonValueProcessor(
LocalDateTimeJsonValueProcessor.DEFAULT_DATE_PATTERN));
jsonConfig.registerJsonValueProcessor(LocalTime.class, new LocalTimeJsonValueProcessor(
LocalTimeJsonValueProcessor.DEFAULT_DATE_PATTERN));
JSONObject obj = JSONObject.fromObject(dateVo, jsonConfig);
System.out.println(obj.toString());
//结果{"localDate":"2022-01-16","localDateTime":"2022-01-16T17:37:01.563","localTime":"17:37:01.563"}
2.json反序列化及问题解决
再看看反序列化的效果
为了方便打印实体,使用lombook的@Data注解改写实体toString方法
lombook的maven引入
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
DateVo类,使用@Date注解,去掉原有的getter setter方法
package com.vvvtimes.vo;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
@Data
public class DateVo implements Serializable {
private LocalDateTime localDateTime;
private LocalDate localDate;
private LocalTime localTime;
}
反序列化代码
String dateVoStr = "{\"localDate\":\"2022-01-15\",\"localDateTime\":\"2022-01-15T22:51:52.616\",\"localTime\":\"22:51:52.616\"}";
//jackson将字符串转对象
ObjectMapper mapper = new ObjectMapper();
//处理java8时间类型新增代码
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
DateVo dateVo1 = mapper.readValue(dateVoStr, DateVo.class);
System.out.println(dateVo1);
//结果
//DateVo(localDateTime=2022-01-15T22:51:52.616, localDate=2022-01-15, localTime=22:51:52.616)
//fastjson将字符串转对象
DateVo dateVo2 = JSON.parseObject(dateVoStr, DateVo.class);
System.out.println(dateVo2);
//结果
//DateVo(localDateTime=2022-01-15T22:51:52.616, localDate=2022-01-15, localTime=22:51:52.616)
//gson将字符串转对象
DateVo dateVo3 = new Gson().fromJson(dateVoStr, DateVo.class);
System.out.println(dateVo3);
//结果报错
//Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 15 path $.localDate
//json-lib将字符串转对象
JSONObject jsonObject = JSONObject.fromObject(dateVoStr);
DateVo dateVo4 = (DateVo) JSONObject.toBean(jsonObject, DateVo.class);
//结果报错
//一月 16, 2022 2:26:42 下午 net.sf.json.JSONObject morphPropertyValue
//警告: Can't transform property 'localDate' from java.lang.String into java.time.LocalDate. Will register a default Morpher
//Exception in thread "main" net.sf.json.JSONException: Error while setting property=localDate type class java.lang.String
可以看到,除了fastjson,其他的使用普通的反序列化都会报错,这里jackson没报错是因为序列化的时候引入jsr310的JavaTimeModule。
(1)解决反序列化报错问题
jackson报错处理
跟json序列化一样。引入jsr310,不赘述
gson报错处理
需要重写com.google.gson.JsonDeserializer<T>的反序列化方法deserialize,实现如下(这里顺带实现了com.google.gson.JsonSerializer<T>的序列化方法serialize)
LocalDate反序列化实现LocalDateDeserializer.java
package com.vvvtimes.util;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocalDateDeserializer implements JsonDeserializer<LocalDate> {
@Override
public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return LocalDate.parse(json.getAsString(),
DateTimeFormatter.ofPattern("yyyy-MM-dd").withLocale(Locale.CHINESE));
}
}
LocalDate序列化实现LocalDateSerializer.java
package com.vvvtimes.util;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class LocalDateSerializer implements JsonSerializer<LocalDate> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public JsonElement serialize(LocalDate localDate, Type srcType, JsonSerializationContext context) {
return new JsonPrimitive(formatter.format(localDate));
}
}
LocalDateTime反序列化实现
package com.vvvtimes.util;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocalDateTimeDeserializer implements JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return LocalDateTime.parse(json.getAsString(),
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").withLocale(Locale.CHINESE));
}
}
LocalDateTime序列化实现
package com.vvvtimes.util;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LocalDateTimeSerializer implements JsonSerializer<LocalDateTime> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
@Override
public JsonElement serialize(LocalDateTime localDateTime, Type srcType, JsonSerializationContext context) {
return new JsonPrimitive(formatter.format(localDateTime));
}
}
LocalTime反序列化实现
package com.vvvtimes.util;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocalTimeDeserializer implements JsonDeserializer<LocalTime> {
@Override
public LocalTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return LocalTime.parse(json.getAsString(),
DateTimeFormatter.ofPattern("HH:mm:ss.SSS").withLocale(Locale.CHINESE));
}
}
LocalTime序列化实现
package com.vvvtimes.util;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class LocalTimeSerializer implements JsonSerializer<LocalTime> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");
@Override
public JsonElement serialize(LocalTime localTime, Type srcType, JsonSerializationContext context) {
return new JsonPrimitive(formatter.format(localTime));
}
}
gson中需要注册这些实现在调用反序列化方法
//gson将字符串转对象
GsonBuilder gsonBuilder = new GsonBuilder();
//注册刚序列化实现
gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateSerializer());
gsonBuilder.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer());
gsonBuilder.registerTypeAdapter(LocalTime.class, new LocalTimeSerializer());
//注册反序列化实现
gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateDeserializer());
gsonBuilder.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeDeserializer());
gsonBuilder.registerTypeAdapter(LocalTime.class, new LocalTimeDeserializer());
Gson gson = gsonBuilder.setPrettyPrinting().create();
DateVo dateVo3 = gson.fromJson(dateVoStr, DateVo.class);
System.out.println(dateVo3);
//结果正常
//DateVo(localDateTime=2022-01-15T22:51:52.616, localDate=2022-01-15, localTime=22:51:52.616)
json-lib报错处理
反序列的实现并没有序列的实现简单,不像序列化那样实现方法就行。在尝试重写Morpher类并调用JSONUtils.getMorpherRegistry().registerMorpher()后,PropertySetStrategy的setProperty方法还需要处理。暂时不弄了。
六、数据库类型适配问题
mybatis使用报错
对于mybatis3.4以下,需要引入jsr310依赖,高版本(3.4.5以上)不需要
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
<version>1.0.1</version>
</dependency>
mybatis-config.xml 需要添加配置
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.InstantTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.LocalDateTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.LocalDateTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.LocalTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.OffsetDateTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.OffsetTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.ZonedDateTimeTypeHandler" />
</typeHandlers>
、