java springMapjacksonjsonView未对mongodb对象Id执行toString操作

txu3uszq  于 2023-01-22  发布在  Java
关注(0)|答案(5)|浏览(124)

我在我的SpringMVC应用程序中使用MappingJacksonJsonView从我的控制器呈现JSON。我希望来自我的对象的ObjectId呈现为. toString,但是它将ObjectId序列化为它的各个部分。它在我的Velocity/JSP页面中工作得很好:

Velocity:
    $thing.id
Produces:
    4f1d77bb3a13870ff0783c25

Json:
    <script type="text/javascript">
         $.ajax({
             type: 'GET',
             url: '/things/show/4f1d77bb3a13870ff0783c25',
             dataType: 'json',
             success : function(data) {
                alert(data);
             }
         });
    </script>
Produces:
    thing: {id:{time:1327331259000, new:false, machine:974358287, timeSecond:1327331259, inc:-260555739},…}
        id: {time:1327331259000, new:false, machine:974358287, timeSecond:1327331259, inc:-260555739}
            inc: -260555739
            machine: 974358287
            new: false
            time: 1327331259000
            timeSecond: 1327331259
        name: "Stack Overflow"

XML:
    <script type="text/javascript">
         $.ajax({
             type: 'GET',
             url: '/things/show/4f1d77bb3a13870ff0783c25',
             dataType: 'xml',
             success : function(data) {
                alert(data);
             }
         });
    </script>
Produces:
    <com.place.model.Thing>
        <id>
            <__time>1327331259</__time>
            <__machine>974358287</__machine>
            <__inc>-260555739</__inc>
            <__new>false</__new>
        </id>
        <name>Stack Overflow</name>
    </com.place.model.Thing>

有没有办法阻止MappingJacksonJsonView从ObjectId中获取那么多信息?我只需要. toString()方法,而不是所有细节。
谢谢。
添加Spring配置:

@Configuration
@EnableWebMvc
public class MyConfiguration {

    @Bean(name = "viewResolver")
    public ContentNegotiatingViewResolver viewResolver() {
        ContentNegotiatingViewResolver contentNegotiatingViewResolver = new ContentNegotiatingViewResolver();
        contentNegotiatingViewResolver.setOrder(1);
        contentNegotiatingViewResolver.setFavorPathExtension(true);
        contentNegotiatingViewResolver.setFavorParameter(true);
        contentNegotiatingViewResolver.setIgnoreAcceptHeader(false);
        Map<String, String> mediaTypes = new HashMap<String, String>();
        mediaTypes.put("json", "application/x-json");
        mediaTypes.put("json", "text/json");
        mediaTypes.put("json", "text/x-json");
        mediaTypes.put("json", "application/json");
        mediaTypes.put("xml", "text/xml");
        mediaTypes.put("xml", "application/xml");
        contentNegotiatingViewResolver.setMediaTypes(mediaTypes);
        List<View> defaultViews = new ArrayList<View>();
        defaultViews.add(xmlView());
        defaultViews.add(jsonView());
        contentNegotiatingViewResolver.setDefaultViews(defaultViews);
        return contentNegotiatingViewResolver;
    }

    @Bean(name = "xStreamMarshaller")
    public XStreamMarshaller xStreamMarshaller() {
        return new XStreamMarshaller();
    }

    @Bean(name = "xmlView")
    public MarshallingView xmlView() {
        MarshallingView marshallingView = new MarshallingView(xStreamMarshaller());
        marshallingView.setContentType("application/xml");
        return marshallingView;
    }

    @Bean(name = "jsonView")
    public MappingJacksonJsonView jsonView() {
        MappingJacksonJsonView mappingJacksonJsonView = new MappingJacksonJsonView();
        mappingJacksonJsonView.setContentType("application/json");
        return mappingJacksonJsonView;
    }
}

和我的控制器:

@Controller
@RequestMapping(value = { "/things" })
public class ThingController {

    @Autowired
    private ThingRepository thingRepository;

    @RequestMapping(value = { "/show/{thingId}" }, method = RequestMethod.GET)
    public String show(@PathVariable ObjectId thingId, Model model) {
        model.addAttribute("thing", thingRepository.findOne(thingId));
        return "things/show";
    }
}
swvgeqrz

swvgeqrz1#

默认情况下,Jackson提供接收到的对象的序列化。ObjectId返回对象,因此其属性在转换为JSON后可见。您需要指定所需的序列化类型,在本例中为字符串。用于创建ThingRepositoryThing实体类如下所示:

public class Thing {
    @Id
    @JsonSerialize(using= ToStringSerializer.class)
    ObjectId id;

    String name;
}

在此记录添加的注解**@JsonSerialize(使用= ToStringSerializer.class)**,该注解指示将ObjectID序列化为String。

wh6knrhe

wh6knrhe2#

之前的答案确实奏效了,但它很难看,而且没有经过深思熟虑--这是一个实际解决问题的明确变通方案。
真实的的问题是ObjectId反序列化为它的组成部分。MappingJacksonJsonView看到ObjectId的本质,即一个对象,并对其进行处理。JSON中看到的反序列化字段是组成ObjectId的字段。要停止此类对象的序列化/反序列化,必须配置一个扩展ObjectMapperCustomObjectMapper
下面是CustomeObjectMapper

public class CustomObjectMapper extends ObjectMapper {

    public CustomObjectMapper() {
        CustomSerializerFactory sf = new CustomSerializerFactory();
        sf.addSpecificMapping(ObjectId.class, new ObjectIdSerializer());
        this.setSerializerFactory(sf);
    }
}

以下是CustomObjectMapper使用的ObjectIdSerializer

public class ObjectIdSerializer extends SerializerBase<ObjectId> {

    protected ObjectIdSerializer(Class<ObjectId> t) {
        super(t);
    }

    public ObjectIdSerializer() {
        this(ObjectId.class);
    }

    @Override
    public void serialize(ObjectId value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        jgen.writeString(value.toString());
    }
}

下面是需要在@Configuration注解的类中更改的内容:

@Bean(name = "jsonView")
public MappingJacksonJsonView jsonView() {
    final MappingJacksonJsonView mappingJacksonJsonView = new MappingJacksonJsonView();
    mappingJacksonJsonView.setContentType("application/json");
    mappingJacksonJsonView.setObjectMapper(new CustomObjectMapper());
    return mappingJacksonJsonView;
}

你基本上是在告诉Jackson如何序列化/反序列化这个特定的对象。工作起来很有魅力。

x0fgdtte

x0fgdtte3#

如果您在Sping Boot 中使用自动配置Map器的自动连线示例,则只需添加以下定制器bean:

@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
    return builder -> builder.serializerByType(ObjectId.class, ToStringSerializer.instance);
}

相关进口:

import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.bson.types.ObjectId;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;

然后,这将反映使用自动连线Map器的任何位置,例如:

@Service
public class MyService {
    private final ObjectMapper objectMapper;
    private final MongoTemplate mongoTemplate;

    @Autowired
    public MyService(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    public String getJsonForMongoCommand(Document document) {
        return objectMapper.writeValueAsString(mongoTemplate.executeCommand(document));
    }
}

或在此特定情况下(未经测试,可能不必要):

@Bean(name = "jsonView")
public MappingJacksonJsonView jsonView(ObjectMapper objectMapper) {
    final MappingJacksonJsonView mappingJacksonJsonView = new MappingJacksonJsonView();
    mappingJacksonJsonView.setContentType("application/json");
    mappingJacksonJsonView.setObjectMapper(objectMapper);
    return mappingJacksonJsonView;
}
to94eoyn

to94eoyn4#

我不得不让getId()方法返回一个String,这是让Jackson停止序列化ObjectId的唯一方法。

public String getId() {
    if (id != null) {
        return id.toString();
    } else {
        return null;
    }
}

public void setId(ObjectId id) {
    this.id = id;
}

setId()仍然必须是ObjectId,以便Mongo(及其驱动程序)可以正确设置ID。

ndasle7k

ndasle7k5#

为了补充这些答案,如果您面临还需要序列化ObjectId数组的场景,则可以使用以下逻辑创建自定义序列化程序:

public class ObjectIdSerializer extends JsonSerializer<Object> {

    @Override
    public void serialize(final Object value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException {
        if (value instanceof Collection) {
            final Collection<String> ids = new ArrayList<>();
            for (final Object id : ((Collection<?>) value)) {
                ids.add(ObjectId.class.cast(id).toString());
            }
            jgen.writeObject(ids);
        } else {
            jgen.writeString(ObjectId.class.cast(value).toString());
        }
    }
}

相关问题