【问题标题】:Jackson LocalDate: one day off during serializationJackson LocalDate:序列化期间休息一天
【发布时间】:2019-05-11 22:37:18
【问题描述】:

当 Jackson 尝试从我的课程中序列化 LocalDate 列但数据库完全正常时,我遇到了问题,每次 JSON 从数据库中显示一天。

当数据库按预期显示时:

2018-10-01

调用 Spring REST 入口点的 JSON 输出:

{ "ticketStart": "2018-09-30" }

这表明一天已经过去了。数据库表不存储时间,只存储预期的日期,时区是完全可以丢弃的,因为我的项目是供内部使用的。我尝试用谷歌搜索我的具体问题,发现唯一的问题是 thisthis,但没有一个能解决我的问题。

有一种方法可以强制从我的数据库中按原样序列化日期(又名:禁用转换)。

实体代码:

@Entity
@Table(name="tickets")
public class Ticket
{
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Getter
  @Setter
  private long TicketId;

  @Column(unique=true)
  @Getter
  @Setter
  private LocalDate TicketStart;

  @Column(unique=true)
  @Getter
  @Setter
  private LocalDate TicketEnd;

  //.... some fields omitted
}

由于门票实体由 CRON 脚本自动生成或在日期范围内指定,其中门票具有每周的星期一和星期日:

public Ticket GenerateEmptyTicket(LocalDate begin, LocalDate end)
{
    Ticket newTicket = new Ticket();

    newTicket.setTicketStart(begin);
    newTicket.setTicketEnd(end);
    newTicket.setYear(begin.getYear());
    newTicket.setMonth(begin.getMonth());
    newTicket.setLastMod(new Date());

    boolean isLocked = false;
    LocalDate date = LocalDate.now();
    if(date.isAfter(end)) isLocked = true;

    newTicket.setLocked(isLocked);

    //@TODO: Set a default responsible in the configuration.
    SystemUser rootUser = usersRepo.findByUsername("root").get();
    newTicket.setResponsable(rootUser);

    return newTicket;
}

public void GenerateTicketsBetweenTwoDates(LocalDate begin, LocalDate end)
{        
    List<LocalDate> weekDates = new ArrayList<>();

    if(begin.getDayOfWeek() != DayOfWeek.MONDAY)
        while(begin.getDayOfWeek()  != DayOfWeek.MONDAY)
            begin = begin.minusDays(1);


    LocalDate tmp = begin;
    while(tmp.isBefore(end)){
        weekDates.add(tmp);
        tmp = tmp.plusWeeks(1);
    }

    if(end.getDayOfWeek() == DayOfWeek.MONDAY)
        weekDates.add(end);


    LocalDate current = LocalDate.now();
    List<Ticket> ticketsToSave = new ArrayList<>();

    for(LocalDate dat : weekDates)
    {
        logger.info("BEGIN DATE:" + dat.toString());
        LocalDate __end = dat.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

        if(current.isAfter(__end)) logger.info("LOCKED: YES");

        ticketsToSave.add(GenerateEmptyTicket(dat, __end));
    }

    ticketsRepo.saveAll(ticketsToSave);
}    

数据库和 Jackson 序列化没有显示任何错误,只是序列化产生了不希望的“休息日”结果。

注意:数据库 JDBC 连接 (MySQL) 从 application.properties spring.datasource.url 指定 useJDBCCompliantTimezoneShift=false&amp;useLegacyDatetimeCode=false&amp;serverTimezone=UTC

【问题讨论】:

  • 请附上您使用的代码。您是否已经使用调试器来确定是在从数据库中读取日期时引入错误,还是在将日期序列化为 JSON 时引入错误?
  • @Joni 数据库中没有引入错误,正如我之前提到的,从 Java 添加到数据库的日期显示了预期的值,但是一旦从 JSON 结果显示显示一次隐式转换我做了一个 GET 调用,Spring 没有在日志/调试输出中显示任何内容。
  • 如果在反序列化之前调试对象会得到什么?
  • 多么有趣的事情,我只是这样做并用 Java 从数据库中检索对象,它显示了休息日的副作用转换
  • 您能否在您的 LodalDate 字段之上添加:@JsonDeserialize(using = LocalDateDeserializer.class) @JsonSerialize(using = LocalDateSerializer.class) 并重试是否可行!

标签: java spring date spring-boot jackson


【解决方案1】:

时区问题

一样多 事实证明,Spring 从数据库中检索日期,我猜它使用java.util.Date(它考虑系统的时区)首先解析它,然后将其转换为java.time.LocalDate,使用TimeZone.setDefault(TimeZone.getTimeZone("UTC")); 完全解决问题,像这样使用它:

@SpringBootApplication
public class MyTicketApplication {

    public static void main(String[] args) {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        SpringApplication.run(MyTicketApplication.class, args);
    }
}

【讨论】:

  • 我在 entityManagerFactory() bean 中添加了该行,其中定义了其他持久性设置,它解决了我在应用程序范围内的问题。 // 数据库日期的时区 TimeZone.setDefault(TimeZone.getTimeZone("America/Denver"));这与数据库 URL 的定义方式相匹配:jdbc:mysql://localhost:3306/db?useSSL=false&serverTimezone=America/Denver
猜你喜欢
  • 2018-09-29
  • 2017-10-24
  • 2020-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多