Spring WebSocket中如何正确将DTO的ObjectId字段映射为String类型
Spring WebSocket 中 ObjectId 序列化为十六进制字符串配置方案
Spring WebSocket 默认使用 Jackson 做 JSON 序列化,ObjectId 被输出为包含时间戳、机器标识等属性的结构化对象,是因为默认序列化器未直接调用toString()方法输出单值,以下是两种可直接使用的实现方式:
- 全局配置:一次配置后所有ObjectId字段自动按字符串格式序列化/反序列化,适合项目中大量使用ObjectId的场景
- 单字段注解配置:仅对指定字段生效,适合只有少量字段需要转换的场景
全局配置实现步骤
1. 编写自定义序列化与反序列化器
序列化器负责将ObjectId转为十六进制字符串输出:
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 ObjectIdJsonSerializer extends JsonSerializer<ObjectId> { @Override public void serialize(ObjectId objectId, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeString(objectId.toHexString()); } }
反序列化器负责接收前端传入的十六进制字符串,转回ObjectId类型:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import org.bson.types.ObjectId; import java.io.IOException; public class ObjectIdJsonDeserializer extends JsonDeserializer<ObjectId> { @Override public ObjectId deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { return new ObjectId(jsonParser.getText()); } }
这里用
toHexString()和直接调用toString()效果一致,都是输出标准的24位ObjectId十六进制字符串。
2. 注册到WebSocket消息转换器
注意Spring WebSocket不会复用Spring MVC的Jackson配置,需要单独给WebSocket的消息转换器注册自定义模块:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import org.bson.types.ObjectId; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.converter.MappingJackson2MessageConverter; import org.springframework.messaging.converter.MessageConverter; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; import java.util.List; @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public boolean configureMessageConverters(List<MessageConverter> messageConverters) { MappingJackson2MessageConverter jacksonConverter = new MappingJackson2MessageConverter(); ObjectMapper objectMapper = jacksonConverter.getObjectMapper(); SimpleModule objectIdModule = new SimpleModule(); objectIdModule.addSerializer(ObjectId.class, new ObjectIdJsonSerializer()); objectIdModule.addDeserializer(ObjectId.class, new ObjectIdJsonDeserializer()); objectMapper.registerModule(objectIdModule); messageConverters.add(jacksonConverter); // 返回false表示不加载默认消息转换器,避免默认的ObjectId序列化逻辑覆盖自定义配置 return false; } }
单字段注解实现
如果不需要全局生效,直接在DTO对应字段上加Jackson注解指定序列化器即可,不需要改全局配置:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import lombok.AllArgsConstructor; import lombok.Data; import org.bson.types.ObjectId; @AllArgsConstructor @Data public class MessageDto { @JsonSerialize(using = ToStringSerializer.class) @JsonDeserialize(using = ObjectIdJsonDeserializer.class) private ObjectId messageId; @JsonSerialize(using = ToStringSerializer.class) @JsonDeserialize(using = ObjectIdJsonDeserializer.class) private ObjectId chatId; }
注意:@JsonSerialize(using = ToStringSerializer.class)仅解决返回时的序列化问题,如果需要接收前端传入的ObjectId字符串参数,必须补充@JsonDeserialize注解指定反序列化器,否则会报类型不匹配错误。
验证结果
配置完成后,接口返回的JSON结构会符合预期:
{ "messageId": "62790c02513ad11442eec6d7", "chatId": "6279125f7b23af2d7c9a1b32" }
不会再出现嵌套的timestamp、counter、machineIdentifier等属性结构。
内容的提问来源于stack exchange,提问作者Maksym Gaiduchek
相关产品推荐
相关产品推荐

