如何从响应体获取ObjectId的字符串形式用于接口请求传参
问题原因
你当前接口返回的id被序列化为带timestamp、date字段的嵌套对象,是因为Jackson默认序列化org.bson.types.ObjectId类型时会展开其所有内部属性,没有使用MongoDB标准的24位十六进制字符串表示,这也是你无法直接将id作为普通请求参数传递的核心原因。
推荐方案:统一配置ObjectId的序列化/反序列化规则
一劳永逸的解决方式是让Jackson自动完成ObjectId和字符串的双向转换,配置后接口返回的id会直接是纯字符串格式,接收请求参数时也能自动把传入的id字符串转为ObjectId类型,不需要手动处理。
全局配置(适用于所有用到ObjectId的场景)
在项目中添加Jackson配置类即可:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import org.bson.types.ObjectId; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.IOException; @Configuration public class MongoJacksonConfig { @Bean public Jackson2ObjectMapperBuilderCustomizer objectIdCustomizer() { return builder -> { // 序列化时把ObjectId转为字符串 builder.serializerByType(ObjectId.class, ToStringSerializer.instance); // 反序列化时把字符串转为ObjectId builder.deserializerByType(ObjectId.class, new JsonDeserializer<ObjectId>() { @Override public ObjectId deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String idStr = p.getValueAsString(); if (idStr == null || idStr.isBlank()) return null; return new ObjectId(idStr); } }); }; } }
配置完成后,Student接口的返回结构会变成标准格式:
{ "id": "62c3b734a1b2c3d4e5f6a7b8", "firstName": "Test", "secondName": "Test" }
前端拿到这个id字符串后,可以直接拼接到请求参数中,格式为/getStudentById?id=62c3b734a1b2c3d4e5f6a7b8。
单字段配置(仅作用于Student实体的id字段)
如果不想做全局配置,也可以直接在实体类的id字段上加注解单独指定序列化规则:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.databind.ser.std.ToStringSerializer import org.bson.types.ObjectId import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.mapping.Document @Document() data class Student( @Id @JsonSerialize(using = ToStringSerializer::class) @JsonDeserialize(using = ObjectIdDeserializer::class) // 引用上述自定义反序列化器即可 val id: ObjectId?, val firstName: String, val secondName: String )
按id查询的接口实现
配置完转换规则后,控制器可以直接接收ObjectId类型的参数,Spring会自动完成类型转换:
import org.bson.types.ObjectId import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @RestController class StudentController(private val studentRepository: StudentRepository) { @GetMapping("/getStudentById") fun getStudentById(@RequestParam id: ObjectId): Student { return studentRepository.findById(id) .orElseThrow { IllegalArgumentException("对应ID的学生不存在") } } }
如果不想配置全局反序列化规则,也可以直接接收字符串类型的id,手动校验格式后转换为ObjectId:
@GetMapping("/getStudentById") fun getStudentById(@RequestParam id: String): Student { if (!ObjectId.isValid(id)) { throw IllegalArgumentException("传入的ID格式不符合MongoDB ObjectId规范") } return studentRepository.findById(ObjectId(id)) .orElseThrow { IllegalArgumentException("对应ID的学生不存在") } }
不推荐的临时兼容方式
如果你暂时不调整序列化配置,要传递嵌套结构的id需要先把整个id的JSON对象做URL编码后作为参数值传递,后端还需要自定义参数解析器把传入的JSON结构解析为ObjectId,实现和维护成本极高,没有实际使用价值。
内容的提问来源于stack exchange,提问作者Laughing_Man
相关产品推荐
相关产品推荐

