MappingJacksonJsonView return top-level json objec

2020-02-29 02:11发布

I converted to controller to use ContentNegotiatingViewResolver instead of MessageConverters to support multiple output types. With json, I am using MappingJacksonJsonView:

<bean
    class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="order" value="1" />
    <property name="mediaTypes">
        <map>
            <entry key="html" value="text/html"/>
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
        </map>
    </property>
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
            <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
                <constructor-arg>
                    <bean class="org.springframework.oxm.xstream.XStreamMarshaller" />
                </constructor-arg>
            </bean>                         
        </list>
    </property>
    <property name="ignoreAcceptHeader" value="true" />
    <property name="defaultContentType" value="application/json" />
</bean>

With the following controller logic:

@RequestMapping(value = "/id/{id}", method = RequestMethod.GET)
public ModelAndView getById(@PathVariable (value="id") String id) {
    MyObject ret = doGetById(id);
    ModelAndView modelAndView = new ModelAndView("common/single");
    modelAndView.addObject("myObject", ret);
    return modelAndView;
}

The json return when I access /id/1234.json is something like:

{
   myObject: {
        field1:"abc",
        field2:"efg"
   }
}

Is there a way for my to set myObject as the top level node for the result so it look like this instead:

{
    field1:"abc",
    field2:"efg"
}

3条回答
再贱就再见
2楼-- · 2020-02-29 02:30

I faced same issue and following solution works for me.

<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
   <property name="prefixJson" value="true" />
</bean>
查看更多
太酷不给撩
3楼-- · 2020-02-29 02:32

What's happening is Spring MVC is taking the ModelAndView and serializing it to JSON. Since a ModelAndView just looks like a map, and in this case, you only have one entry in the map with a key name of myObject, that's what the JSON response looks at. In order to get just your object, you need to return just your object instead of a ModelAndView and let Jackson serialize your object to JSON.

Rather than returning a ModelAndView, return a MyObject and annotate the method with @ResponseBody, so your controller method becomes

@RequestMapping(value="/id/{id}", method=RequestMethod.GET, produces="application/json")
public @ResponeBody MyObject getById(@PathVariable (value="id") String id) {
    return doGetById(id);
}
查看更多
ゆ 、 Hurt°
4楼-- · 2020-02-29 02:32

You should be able to remove the outer node by using MappingJacksonJsonView.setExtractValueFromSingleKeyModel(true):

Set whether to serialize models containing a single attribute as a map or whether to extract the single value from the model and serialize it directly.

The effect of setting this flag is similar to using MappingJacksonHttpMessageConverter with an @ResponseBody request-handling method.

For example:

private final MappingJacksonJsonView view = new MappingJacksonJsonView();

public MyController() {
     view.setExtractValueFromSingleKeyModel(true);
}

@RequestMapping(value = "/id/{id}", method = RequestMethod.GET)
public ModelAndView getById(@PathVariable (value="id") String id) {
    MyObject ret = doGetById(id);
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setView(this.view);
    modelAndView.addObject("myObject", ret);
    return modelAndView;
}

This should also work if you prefer to do it via configuration:

<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
    <property name="extractValueFromSingleKeyModel" value="true" />
</bean>
查看更多
登录 后发表回答