Spring MappingJackson2JsonView 视图的怪异问题

时间比较匆忙,可能记录有些乱。

先说明一下问题:我用Spring MVC 4.0+ 编写restful框架, 因为看到了提供有MappingJackson2JsonView类,就没有通过自己转换json, 返回字符串。

但是遇到一个灵异的问题:如果利用javaBean类接收参数,在返回值中,会自动把javaBean的键值对以json格式返回,效果等同于对javaBean参数使用了标签@ModelAttribute


MappingJackson2JsonView-0

会返回

MappingJackson2JsonView-1

使用 View 是因为以后有需要的话,可能会重写一个JsonView。

翻了一天的源码,看到了如下几个部分(以图片中的代码举例):

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest)

初始container的model里有2个对象,但并没有返回的data Map, 而是一个user和一个BindingResult,user是入参,BindingResult用于validation绑定页面元素。


org.springframework.web.servlet.DispatcherServlet#processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception)

方法中通过

org.springframework.web.servlet.view.AbstractView#createMergedOutputModel(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)

方法将data Map参数放入model,由ModelAndView对象持有。

然后MappingJackson2JsonView#filterModel 方法会过滤掉BindingResult 以及 指定的filter规则类

protected Object filterModel(Map<String, Object> model) {
    Map<String, Object> result = new HashMap<String, Object>(model.size());
    Set<String> modelKeys = (!CollectionUtils.isEmpty(this.modelKeys) ? this.modelKeys : model.keySet());
    for (Map.Entry<String, Object> entry : model.entrySet()) {
        if (!(entry.getValue() instanceof BindingResult) && modelKeys.contains(entry.getKey()) &&
                !entry.getKey().equals(JsonView.class.getName()) &&
                !entry.getKey().equals(FilterProvider.class.getName())) {
            result.put(entry.getKey(), entry.getValue());
        }
    }
    return (this.extractValueFromSingleKeyModel && result.size() == 1 ? result.values().iterator().next() : result);
}

modelKeys 可以通过 MappingJackson2JsonView#setModelKeys方法指定,所以如果希望只返回data Map 需要指定

    MappingJackson2JsonView model = new MappingJackson2JsonView();
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("data", object);
    model.setModelKeys(params.keySet());
    

这种设计默认全部返回,通过Set数组参数 指定需要返回的json对象。如果全部展平为一级的map,是不是就可以不经过转换,而通过此参数指定给客户端返回的参数?

BindingResult 是将校验结果返回给页面展现,包括元素和错误message等信息。restful不需要此信息,所以系统自动忽略。

但是可以通过此规则进行入参校验