chore: initialize qiming workspace repository

This commit is contained in:
Codex
2026-05-29 14:22:48 +08:00
commit bfd67a0f2c
10750 changed files with 1885711 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>app-platform-log</artifactId>
<groupId>com.xspaceagi</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>app-platform-log-spec</artifactId>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<dependencies>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>system-sdk</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,43 @@
package com.xspaceagi.log.spec;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
/**
* 自定义 LocalDateTime 的序列化器,按照UTC时间格式输出
*/
public class CustomLocalDateTimeSerializer extends StdSerializer<LocalDateTime> {
private static final String UTC_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
private static final ZoneId BEIJING_ZONE_ID = ZoneId.of("Asia/Shanghai");
private static final ZoneId UTC_ZONE_ID = ZoneId.of("UTC");
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(UTC_DATE_TIME_PATTERN);
public CustomLocalDateTimeSerializer() {
super(LocalDateTime.class);
}
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
if (value != null) {
// LocalDateTime 是东八区的本地时间,将其转换为 UTC 时间
ZonedDateTime beijingDateTime = value.atZone(BEIJING_ZONE_ID);
ZonedDateTime utcDateTime = beijingDateTime.withZoneSameInstant(UTC_ZONE_ID);
// 使用指定的格式输出 UTC 时间
gen.writeString(utcDateTime.format(formatter));
} else {
gen.writeNull();
}
}
}

View File

@@ -0,0 +1,100 @@
package com.xspaceagi.log.spec;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
/**
* 反序列化 {@link LocalDateTime}:支持 UTC/带 Z 的字符串、ISO 日期时间、仅日期 {@code yyyy-MM-dd}、以及 Unix 时间戳。
*/
@Slf4j
public class FlexibleDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
private static final DateTimeFormatter FORMATTER_WITH_NANOS =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'").withZone(ZoneId.of("UTC"));
private static final DateTimeFormatter FORMATTER_WITH_MILLIS =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZone(ZoneId.of("UTC"));
private static final DateTimeFormatter FORMATTER_WITHOUT_FRACTION =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'").withZone(ZoneId.of("UTC"));
private static final DateTimeFormatter SPACE_SEPARATED =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ROOT);
private static final ZoneId BEIJING_ZONE = ZoneId.of("Asia/Shanghai");
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonToken token = p.currentToken();
if (token == JsonToken.VALUE_NULL) {
return null;
}
if (token == JsonToken.VALUE_NUMBER_INT || token == JsonToken.VALUE_NUMBER_FLOAT) {
return fromEpoch(p.getLongValue());
}
if (token == JsonToken.VALUE_STRING) {
String dateString = p.getText().trim();
if (StringUtils.isBlank(dateString)) {
return null;
}
return parseString(dateString, p);
}
throw new JsonParseException(p, "无法解析 LocalDateTime需要字符串或数字实际为 " + token);
}
private static LocalDateTime fromEpoch(long raw) {
Instant instant = raw > 10_000_000_000L ? Instant.ofEpochMilli(raw) : Instant.ofEpochSecond(raw);
return LocalDateTime.ofInstant(instant, BEIJING_ZONE);
}
private LocalDateTime parseString(String dateString, JsonParser p) throws IOException {
try {
if (dateString.matches(".*\\.\\d{6}Z$")) {
Instant instant = Instant.from(FORMATTER_WITH_NANOS.parse(dateString));
return LocalDateTime.ofInstant(instant, BEIJING_ZONE);
}
if (dateString.matches(".*\\.\\d{3}Z$")) {
Instant instant = Instant.from(FORMATTER_WITH_MILLIS.parse(dateString));
return LocalDateTime.ofInstant(instant, BEIJING_ZONE);
}
if (dateString.endsWith("Z") && dateString.contains("T")) {
Instant instant = Instant.from(FORMATTER_WITHOUT_FRACTION.parse(dateString));
return LocalDateTime.ofInstant(instant, BEIJING_ZONE);
}
} catch (DateTimeParseException ignored) {
// 走下方通用解析
}
try {
return LocalDateTime.ofInstant(OffsetDateTime.parse(dateString).toInstant(), BEIJING_ZONE);
} catch (DateTimeParseException ignored) {
}
try {
return LocalDateTime.parse(dateString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
} catch (DateTimeParseException ignored) {
}
try {
return LocalDateTime.parse(dateString, SPACE_SEPARATED);
} catch (DateTimeParseException ignored) {
}
try {
// 纯日期 yyyy-MM-dd → 当天 00:00:00东八区墙钟
return LocalDate.parse(dateString, DateTimeFormatter.ISO_LOCAL_DATE).atStartOfDay(BEIJING_ZONE).toLocalDateTime();
} catch (DateTimeParseException ignored) {
}
log.error("无法解析日期时间: {}", dateString);
throw new JsonParseException(p, "无法解析日期时间: " + dateString);
}
}