分布式时间问题集合
分布式时间问题集合
一、
@SpringBootApplication public class SwappingApplication { public static void main(String[] args) { SpringApplication.run(SwappingApplication.class, args); } @PostConstruct void started() { TimeZone.setDefault(TimeZone.getTimeZone("GMT+8")); } }
这段代码是一个基于 Spring Boot 框架的应用程序入口类。让我来解释一下:
@SpringBootApplication
:这是一个注解,标记了该类是一个 Spring Boot 应用程序的入口类。它将自动进行一些配置,包括自动扫描和加载其他组件、配置以及设置默认属性。public static void main(String[] args)
:这是一个 Java 程序的入口方法。在该方法中,通过调用SpringApplication.run()
来启动 Spring Boot 应用程序。SwappingApplication.class
是应用程序的主类,args
是传递给应用程序的命令行参数。@PostConstruct
:这是一个注解,表示带有该注解的方法会在应用程序启动时执行。在这个例子中,started()
方法用于设置默认的时区为 GMT+8。TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"))
:这是java.util.TimeZone
类的方法调用,用于设置默认时区为 GMT+8。在应用程序启动时,started()
方法会被调用,从而设置默认的时区。总之,上述代码创建了一个 Spring Boot 应用程序入口类,并在应用程序启动时将默认时区设置为 GMT+8。通过
main()
方法启动应用程序后,Spring Boot 将根据配置和自动扫描加载其他组件,并开始运行应用程序。
二、
生成自定义token方法:public String generateCustomJwtToken() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Date now = new Date();
Date expiryDate = new Date(now.getTime() + jwtExpiration * 1000L);
SecretKey secretKey = Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8));
Map<String, Object> permissions = Maps.newHashMap();
Map<String, Object> user = Maps.newHashMap();
permissions.put("permissions", authentication.getCredentials());
user.put("user", authentication.getPrincipal());
return "Bearer " + Jwts.builder()
.addClaims(permissions)
.addClaims(user)
.setSubject(authentication.getName())
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(secretKey)
.compact();
},报错:Unable to serialize claims object to json: Unable to serialize object: Java 8 date/time typejava.time.LocalDateTime
not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: io.jsonwebtoken.impl.DefaultClaims["user"]->com.xirui.qrcode.modules.web.domain.User["create_date"])
错误信息表明你正在尝试将一个
java.time.LocalDateTime
对象序列化为 JSON,但 Jackson(用于处理 JSON 的库)默认不支持java.time.LocalDateTime
。解决方法是添加jackson-datatype-jsr310
模块,它为 Java 8 的日期/时间类型提供了支持。如果你的项目是 Maven 项目,你可以在
pom.xml
文件中添加以下依赖:<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.12.5</version> <!-- 请使用最新版本 --> </dependency>
如果你的项目是 Gradle 项目,你可以在
build.gradle
文件中添加以下依赖:implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.5' // 请使用最新版本
然后,你需要在你的配置中注册这个模块。如果你使用的是 Spring Boot,它会自动为你注册这个模块。如果不是,你需要手动注册,如下所示:
ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule());
这样,你就应该可以正常序列化
java.time.LocalDateTime
对象了。
根据上述回答,ObjectMapper mapper = new ObjectMapper();mapper.registerModule(new JavaTimeModule());手动注册写在哪儿?
在你的应用程序中,你需要创建一个配置类(通常在 Spring Boot 中,我们把它放在
@Configuration
注解的类中),然后在这个类中创建一个ObjectMapper
的 Bean,并注册JavaTimeModule
模块。以下是一个例子:@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule()); return mapper; } }
这个
objectMapper()
方法会创建一个ObjectMapper
的 Bean,并注册JavaTimeModule
模块。然后,Spring 会自动将这个ObjectMapper
Bean 注入到需要它的地方。然而,如果你的项目是一个 Spring Boot 项目,那么你通常不需要手动创建这个 Bean。Spring Boot 会自动配置一个
ObjectMapper
Bean,并自动注册JavaTimeModule
模块,只要你在项目的类路径中包含了jackson-datatype-jsr310
依赖。如果你已经添加了
jackson-datatype-jsr310
依赖,但仍然遇到序列化java.time.LocalDateTime
的问题,那么可能是其他地方的配置覆盖了 Spring Boot 的自动配置。在这种情况下,你可以尝试手动创建ObjectMapper
Bean,并注册JavaTimeModule
模块,如上述代码所示。
根据上述回答报错:Unable to serialize claims object to json: Unable to serialize object: Java 8 date/time type
java.time.LocalDateTime
not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: io.jsonwebtoken.impl.DefaultClaims["user"]->com.xirui.qrcode.modules.web.domain.User["create_date"])你的错误提示表明,你正在尝试将一个
java.time.LocalDateTime
类型的对象序列化为 JSON,但是 Jackson 库默认并不支持java.time.LocalDateTime
类型。要解决这个问题,你需要添加jackson-datatype-jsr310
这个模块,它支持 Java 8 的日期/时间类型。如果你的项目是一个 Maven 项目,你可以在你的
pom.xml
文件中添加以下依赖:<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency>
如果你的项目是一个 Gradle 项目,你可以在你的
build.gradle
文件中添加以下依赖:implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
一旦你添加了这个依赖,Spring Boot 会自动配置 Jackson 来支持
java.time.LocalDateTime
。如果你的项目不是 Spring Boot 项目,你可能需要手动配置 Jackson,方法如下:ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule()); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
上述代码首先创建了一个
ObjectMapper
对象,然后注册了JavaTimeModule
,最后禁用了将日期作为时间戳写入的特性,这样日期就会被格式化为 ISO 格式的字符串,而不是时间戳。然后,你需要确保你的应用程序在序列化和反序列化 JSON 时都使用了这个配置过的
ObjectMapper
对象。如果你使用的是 Spring MVC,你可以通过配置一个MappingJackson2HttpMessageConverter
Bean 来实现这一点。
根据上述回答报错:java.lang.IllegalArgumentException: Unable to serialize claims object to json: Unable to serialize object: Java 8 date/time type
java.time.LocalDateTime
not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: io.jsonwebtoken.impl.DefaultClaims["user"]->com.xirui.qrcode.modules.web.domain.User["create_date"])你正在遇到的问题是由于在尝试将包含
java.time.LocalDateTime
类型的对象序列化为JSON时,Jackson库默认不支持此类型。尽管你已经添加了jackson-datatype-jsr310
依赖,但问题仍然存在,这可能是因为你在创建JWT时,JJWT库使用的是其内部的JSON处理机制,而不是Spring Boot自动配置的Jackson库。解决此问题的一种方法是尽量避免在JWT的claims中直接添加包含
java.time.LocalDateTime
类型的对象。你可以在添加到JWT之前,将这些对象转换为String或者Timestamp。例如,如果你的User对象中有一个java.time.LocalDateTime
类型的create_date
字段,你可以在添加User到JWT之前,先将create_date
转换为String:User user = (User) authentication.getPrincipal(); user.setCreateDate(user.getCreateDate().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
然后再添加到JWT:
user.put("user", user);
这样,JWT中的用户信息就不再包含
java.time.LocalDateTime
类型,就不会出现序列化问题了。另一种可能的解决方案是自定义JJWT的JSON处理机制,使其使用Jackson库,并配置
JavaTimeModule
。但这可能需要更复杂的代码,且可能需要修改JJWT库的源代码。
标题:分布式时间问题集合
作者:amethystfob
地址:https://newmoon.top/articles/2023/11/28/1701163165320.html
欢迎各路大侠指点留痕: