【问题标题】:How to filter attributes from JSON response in spring?如何在春季从 JSON 响应中过滤属性?
【发布时间】:2017-10-17 08:44:48
【问题描述】:

我有一个像下面这样的控制器,

@RequestMapping(value = "rest/v1/tester")
public class TestController {

    @RequestMapping(value = "/search", method = RequestMethod.GET)
    public ResponseEntity<SampleResults> search(@ModelAttribute("criteria")SampleCriteria criteria) throws Exception {
            SampleResults sampleResults = sampleService.search(criteria);
            return new ResponseEntity<>(sampleResults, OK);
    }

}

我有另一个这样的控制器,

@RequestMapping(value = "rest/v1/second")
public class SecondTestController {

@RequestMapping(value = "/search", method = RequestMethod.GET)
    public ResponseEntity<SampleResults> search(@ModelAttribute("criteria")SampleCriteria criteria) throws Exception {
            SampleResults sampleResults = secondsampleService.search(criteria);
            return new ResponseEntity<>(sampleResults, OK);
    }

}

我的结果结构如下:

public class SampleResults extends Results<SearchSummary, Sample> {
}

这从结果类扩展:

public class Results<SUMMARY,RESULTS> {
    private SUMMARY summary;
    private List<RESULTS> results;

    /*Constructors, getters and setters*/
}

现在我要设置到结果字段中的模型是,

@JsonDeserialize(as = SampleImpl.class)
public interface Sample {

    Long getId();
    void setId(Long id);

    String getName();
    void setName(String name);

    int getAge();
    void setAge(int age);

}

public class SampleImpl implements Sample {

    private Long id;
    private String name;
    private int age;

    /* Getters and Setters */

}

现在对于上面提到的 TestController,我想显示 json 响应中的所有字段,而在 SecondTestController 中,我想屏蔽(不显示)json 响应中的年龄属性。我怎样才能在春天实现这一目标。非常感谢任何帮助!

【问题讨论】:

标签: json spring-mvc spring-boot jackson


【解决方案1】:

公共类 BeanFilterCustom {

public Object filterBean(Object object,String someBeanFilter)  {

    SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept("","");
    FilterProvider filters = new SimpleFilterProvider()
            .addFilter(someBeanFilter, filter);
    MappingJacksonValue mapping = new MappingJacksonValue(object);
    mapping.setFilters(filters);
    return mapping.getValue();
}

}

【讨论】:

  • Object 是任意 DTO 而 someBeanFilter 是 bean 属性
【解决方案2】:

我认为最简单的方法是使用 Jackson @JsonFilter 如果你想要动态的话。

例如,这里可能是 Spring Boot 的一个例子:

您的文件:

@JsonFilter("myFilter")
class Document {
   private field1;
   private field2;
}

修改你默认配置的 HttpMessageConverter :

@Configuration
class WebMvcConfiguration extends WebMvcConfigurationSupport {
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        for(HttpMessageConverter<?> converter: converters) {
            if(converter instanceof MappingJackson2HttpMessageConverter) {
                ObjectMapper mapper = ((MappingJackson2HttpMessageConverter)converter).getObjectMapper();
                mapper.setFilterProvider(new SimpleFilterProvider().addFilter("myFilter", SimpleBeanPropertyFilter.serializeAll()));
            }
        }
    }
}

默认情况下,此过滤器将全部序列化。这一步是强制性的,如果你不指定它,当你的控制器尝试生成对象响应时,你会遇到一个他不知道myFilter的异常。

然后,在您的控制器中,这是您序列化所有字段的常规端点(使用先前声明的过滤器):

@RequestMapping(value = "path/document", method = RequestMethod.GET)
public Document getDocumentWithAllFields() {
   return new Document("val1","val2");
} 
//result : {"field1":"val1","field2":"val2"}

现在,端点具有相同的对象,只有一些字段被序列化:

@RequestMapping(value = "path/document", method = RequestMethod.GET)
public MappingJacksonValue getDocumentWithSomeFields(@RequestParam String[] fields) {
    MappingJacksonValue wrapper = new MappingJacksonValue(new Document("val1","val2"));
    FilterProvider filterProvider = new SimpleFilterProvider().addFilter("myFilter", 
         SimpleBeanPropertyFilter.filterOutAllExcept(fields)); 
    wrapper.setFilters(filterProvider);
    return wrapper;
} 
//result : {"field1":"val1"} (with 'fields' being a coma separated list, containing here just "field1"

【讨论】:

【解决方案3】:

使用必填字段覆盖模态类中的 toString 方法,并在第二个控制器方法中将其显式转换为 json。

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
//get yourObject

ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(yourObject);

【讨论】:

    【解决方案4】:

    你考虑过@JsonView吗?

    它是supported by Spring MVC,允许您根据序列化的上下文过滤字段。

    首先定义你的观点:

    public class View {     
    
        interface SampleView { }  
        interface SampleViewWithAge extends SampleView { }   
    }
    

    然后使用所需的视图注释您的字段:

    public class SampleImpl implements Sample { 
    
        @JsonView(View.SampleView.class)
        private Long id; 
    
        @JsonView(View.SampleView.class)
        private String name; 
    
        @JsonView(View.SampleViewWithAge.class)
        private int age;
    
        // Getters and setters
     }
    

    最后注释您的处理程序以在序列化响应时使用视图:

    @JsonView(View.SampleView.class) 
    @RequestMapping(value = "/search", method = RequestMethod.GET)  
    public ResponseEntity<SampleResults> search() {
        ... 
    }
    
    @JsonView(View.SampleViewWithAge.class)
    @RequestMapping(value = "/search", method = RequestMethod.GET)  
    public ResponseEntity<SampleResults> searchWithAge() {
        ... 
    }
    

    【讨论】:

    • 我尝试了这种方法,但我不断收到异常说明:“message”:“500:异常:”,“logger_name”:“com.cdk.dmg.services.sample.exceptions.APIExceptionHandler” ,"thread_name":"http-nio-8080-exec-1","level":"ERROR","stack_trace":"org.springframework.http.converter.HttpMessageNotWritableException: 无法写入内容: 无法解析 PropertyFilter id 'DynamicFieldFilter';未配置 FilterProvider;嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException:无法解析 ID 为“DynamicFieldFilter”的 PropertyFilter;
    猜你喜欢
    • 2017-06-19
    • 1970-01-01
    • 1970-01-01
    • 2014-07-13
    • 2015-08-31
    • 2010-11-20
    • 2019-10-21
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多