杰克逊的@JsonView,@JsonFilter和春天

2022-09-01 10:42:48

是否可以使用 Jackson 和注释来修改 Spring MVC 控制器返回的 JSON,同时使用 和 Spring 的注释?@JsonView@JsonFilterMappingJacksonHttpMessageConverter@ResponseBody@RequestBody

public class Product
{
    private Integer id;
    private Set<ProductDescription> descriptions;
    private BigDecimal price;
    ...
}


public class ProductDescription
{
    private Integer id;
    private Language language;
    private String name;
    private String summary;
    private String lifeStory;
    ...
}

当客户端请求集合时,我想返回每个集合的最小版本,也许只是它的ID。然后,在后续调用中,客户端可以使用此 ID 请求具有所有属性的完整实例。ProductsProductDescriptionProductDescription

理想的情况是能够在Spring MVC控制器方法上指定这一点,因为调用的方法定义了客户端请求数据的上下文。


答案 1

此问题已解决!
关注

添加对杰克逊序列化视图的支持

Spring MVC现在支持Jackon的序列化视图,用于从不同的控制器方法(例如,详细页面与摘要视图)呈现同一POJO的不同子集。问题: SPR-7156

这就是SPR-7156

状态:已解决

描述

Jackson 的 JSONView 注释允许开发人员控制对方法的哪些方面进行序列化。在当前实现中,必须使用 Jackson 视图编写器,但随后内容类型不可用。如果作为 RequestBody 注释的一部分,可以指定 JSONView,那就更好了。

适用于春季版 >= 4.1

更新

点击此链接。通过示例解释@JsonView批注。


答案 2

最终,我们希望使用类似于StaxMan为JAX-RS显示的符号。不幸的是,Spring并不支持开箱即用,所以我们必须自己做。

这是我的解决方案,它不是很漂亮,但它可以完成工作。

@JsonView(ViewId.class)
@RequestMapping(value="get", method=RequestMethod.GET) // Spring controller annotation
public Pojo getPojo(@RequestValue Long id)
{
   return new Pojo(id);
}

public class JsonViewAwareJsonView extends MappingJacksonJsonView {

    private ObjectMapper objectMapper = new ObjectMapper();

    private boolean prefixJson = false;

    private JsonEncoding encoding = JsonEncoding.UTF8;

    @Override
    public void setPrefixJson(boolean prefixJson) {
        super.setPrefixJson(prefixJson);
        this.prefixJson = prefixJson;
    }

    @Override
    public void setEncoding(JsonEncoding encoding) {
        super.setEncoding(encoding);
        this.encoding = encoding;
    }


    @Override
    public void setObjectMapper(ObjectMapper objectMapper) {
        super.setObjectMapper(objectMapper);
        this.objectMapper = objectMapper;
    }


    @Override
    protected void renderMergedOutputModel(Map<String, Object> model,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        Class<?> jsonView = null;
        if(model.containsKey("json.JsonView")){
            Class<?>[] allJsonViews = (Class<?>[]) model.remove("json.JsonView");
            if(allJsonViews.length == 1)
                jsonView = allJsonViews[0];
        }


        Object value = filterModel(model);
        JsonGenerator generator =
                this.objectMapper.getJsonFactory().createJsonGenerator(response.getOutputStream(), this.encoding);
        if (this.prefixJson) {
            generator.writeRaw("{} && ");
        }
        if(jsonView != null){
            SerializationConfig config = this.objectMapper.getSerializationConfig();
            config = config.withView(jsonView);
            this.objectMapper.writeValue(generator, value, config);
        }
        else
            this.objectMapper.writeValue(generator, value);
    }
}

public class JsonViewInterceptor extends HandlerInterceptorAdapter
{

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
        Object handler, ModelAndView modelAndView) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        JsonView jsonViewAnnotation = handlerMethod.getMethodAnnotation(JsonView.class);
        if(jsonViewAnnotation != null)
            modelAndView.addObject("json.JsonView", jsonViewAnnotation.value());
    }
}

在弹簧服务中.xml

<bean name="ViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="mediaTypes">
            <map>
                <entry key="json" value="application/json" />
            </map>
        </property>
        <property name="defaultContentType" value="application/json" />
        <property name="defaultViews">
            <list>
                <bean class="com.mycompany.myproject.JsonViewAwareJsonView">
                </bean>
            </list>
        </property>
    </bean>

<mvc:interceptors>
    <bean class="com.mycompany.myproject.JsonViewInterceptor" />
</mvc:interceptors>