在使用MongoDB时,如果使用了ObjectId作为主键策略,那么在数据传输时会涉及到一个问题,就是序列化,默认情况下会返回时间戳,非常不利于展示和传递,展示如下:
{
"id":{
"timestamp":1688365000,
"date":"2023-07-03T06:16:40.000+00:00"
},
...
}
MongoDB主键,由时间戳(四个字节)、机器ID(三个字节)、进程ID(两个字节)、计数器(三个字节)四部分构成
64a267c8
73dbd0
58f5
dd2c87
MongoDB中创建文档时可以指定文档主键,默认不指定时会生成一个名为_id(ObjectId:默认主键生成策略,是 MongoDB 提供的默认生成方式,使用 12 字节的 BSON 类型存储主键,包含了时间戳、机器标识、进程标识和随机数)的字段作为主键,也可以使用注解@Id指定主键,可以作用于字符串、数字、对象等,除了使用@Id指定主键还可以自定义主键,例如自增序列等,但是建议使用默认生成策略。
序列化解决方案
自定义序列化策略,将ObjectId转换为String,ObjectIdSerializer.java
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.bson.types.ObjectId;
import java.io.IOException;
public class ObjectIdSerializer extends JsonSerializer<ObjectId> {
@Override
public void serialize(ObjectId objectId, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(objectId.toHexString());
}
}
反序列化解决方案
自定义反序列化策略,将String转换为ObjectId,ObjectIdDeserializer.java,需要注意,对长度有限制,必须时标准长度。
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import org.bson.types.ObjectId;
import java.io.IOException;
import java.util.regex.Pattern;
public class ObjectIdDeserializer extends JsonDeserializer<ObjectId> {
private static final Pattern HEX_PATTERN = Pattern.compile("^[0-9a-fA-F]{24}$");
@Override
public ObjectId deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
String hexString = jsonParser.readValueAs(String.class);
if (!HEX_PATTERN.matcher(hexString).matches()) {
throw new JsonMappingException("Invalid ObjectId: " + hexString);
}
return new ObjectId(hexString);
}
}
使用
@Document(collection = "Books")
@Data
public class Book {
@JsonSerialize(using = ObjectIdSerializer.class)
@JsonDeserialize(using = ObjectIdDeserializer.class)
@Id
private ObjectId id;
}
结果
{
"id":"64a267c873dbd058f5dd2c87",
...
}
总结
以上就是使用ObjectId作为主键时序列化解决方案,如果有更好的解决方案欢迎探讨。