spring boot jsonダイナミックフィルタ属性カスタムタグ完璧解決互換元@ResonseBody@Jsoning IgnoreProperties@Json View


spring boot jsonプロパティ動的フィルタリング完全対応原生@ResonseBody@Jsoning IgnoreProperties@Json View
まず環境はspring boot 2.1 xバージョンです.他のバージョンは同じです.肝心な点はどこですか?主にcomp.fasterxml.jackson.databind.ObjectMapperという種類はスプリングフレームの中では単独ですので、動的フィルタリングの時にコピーしたいですが、springのプロセスと構造を壊さないようにしてください.第一歩はまずController定義の注釈を切り取ります.このクラスはspringにスキャンされたら実行できます.
@ControllerAdvice
public class JFilterResponseBodyAdvice extends AbstractMappingJacksonResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class extends HttpMessageConverter>> converterType) {
        return super.supports(returnType, converterType) && ( returnType.hasMethodAnnotation(JFilters.class) || returnType.hasMethodAnnotation(JFilter.class) );
    }


    protected MappingJacksonValue getOrCreateContainer(Object body) {
        return (body instanceof MappingJacksonValue ? (MappingJacksonValue) body : new JFilterValue(body));
    }

    @Override
    protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType,
                                           MethodParameter returnType, ServerHttpRequest request,
                                           ServerHttpResponse response) {

        if (returnType.hasMethodAnnotation(JFilters.class)) {
            ((JFilterValue) bodyContainer).setJfilters(returnType.getMethodAnnotation(JFilters.class).value());
        } else if (returnType.hasMethodAnnotation(JFilter.class)) {
            ((JFilterValue) bodyContainer).setJfilters(
                    new JFilter[]{returnType.getMethodAnnotation(JFilter.class)}
            );
        }

    }

}
第二のステップは、受け取ったフィルタ情報をMappingJackson Value bodyContinerに保存します.spring jaskysonではMappingJackson Valueを通じて情報を伝達しますので、私達は彼に私達が必要とする属性を追加します.
public class JFilterValue extends MappingJacksonValue {

    private JFilter[] jfilters = null;

    /**
     * Create a new instance wrapping the given POJO to be serialized.
     *
     * @param value the Object to be serialized
     */
    public JFilterValue(Object value) {
        super(value);
    }

    public JFilter[] getJfilters() {
        return jfilters;
    }

    public void setJfilters(JFilter[] jfilters) {
        this.jfilters = jfilters;
    }
}

JFilterResponseBodyAdviceのロジックを解析するのは簡単ですが、カスタムタグがあればJFilterValueを使います.なければ元のMappingJackson Valueを使います.JFilter[]jfiltersは私達が記憶しているフィルタ情報です.後のコードで呼び出します.
第三ステップも重要なステップです.jaskysonの出力前にObject Mapperをコピーして、他の関連コードを実行します.
public class JFilterHttpMessageConverter extends MappingJackson2HttpMessageConverter {

    public PrettyPrinter mSsePrettyPrinter;

    public JFilterHttpMessageConverter() {
        super();
    }

    public JFilterHttpMessageConverter(ObjectMapper objectMapper) {
        super(objectMapper);
        DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
        prettyPrinter.indentObjectsWith(new DefaultIndenter("  ", "
data:")); this.mSsePrettyPrinter = prettyPrinter; } @Override protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { // , if (object instanceof JFilterValue) { // objectMapper ObjectMapper objectMapper = this.objectMapper.copy(); BeanJFilter.setJFilter((JFilterValue) object, objectMapper); // MediaType contentType = outputMessage.getHeaders().getContentType(); JsonEncoding encoding = getJsonEncoding(contentType); JsonGenerator generator = objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding); try { writePrefix(generator, object); Object value = object; Class> serializationView = null; FilterProvider filters = null; JavaType javaType = null; if (object instanceof MappingJacksonValue) { MappingJacksonValue container = (MappingJacksonValue) object; value = container.getValue(); serializationView = container.getSerializationView(); filters = container.getFilters(); } if (type != null && TypeUtils.isAssignable(type, value.getClass())) { javaType = getJavaType(type, null); } ObjectWriter objectWriter = (serializationView != null ? objectMapper.writerWithView(serializationView) : objectMapper.writer()); if (filters != null) { objectWriter = objectWriter.with(filters); } if (javaType != null && javaType.isContainerType()) { objectWriter = objectWriter.forType(javaType); } SerializationConfig config = objectWriter.getConfig(); if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) && config.isEnabled(SerializationFeature.INDENT_OUTPUT)) { objectWriter = objectWriter.with(this.mSsePrettyPrinter); } objectWriter.writeValue(generator, value); writeSuffix(generator, object); generator.flush(); } catch (InvalidDefinitionException ex) { throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex); } catch (JsonProcessingException ex) { throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex); } } else { // super.writeInternal(object, type, outputMessage); } } }
以上のコードは比較的に多くて、実はこんなに多くを管理しなくてもいいです.Abstract Jackson 2 HttpMessage ConverterのwriteInternal方法を直接コピーして、まずカスタムのJFilterValueを判断しました.そして、Object Mapperをコピーして、Object Mapper=this.object Mapper.com py();すべての引用したobject Mapperを、あなたのCOPYのobject Mapperに変えます.この方法を変えるだけでいいです.
第四のステップはフィルタを使って、json属性をフィルタリングします.ここではフィールドを取り除くだけです.
@com.fasterxml.jackson.annotation.JsonFilter("BeanJFilter")
public class BeanJFilter extends SimpleBeanPropertyFilter implements Serializable {
    public Map> includesClazz ;
    public BeanJFilter() {
        this.includesClazz = new HashMap<>();
    }
    public BeanJFilter addFilter(Class clazz, String propertyArray) {
        includesClazz.put(clazz, new HashSet<>(Arrays.asList(propertyArray.split(","))));
        return this;
    }
    protected boolean include(BeanPropertyWriter writer) {
        if( includesClazz.containsKey(writer.getMember().getDeclaringClass()) ){
            return !this.includesClazz.get(writer.getMember().getDeclaringClass()).contains(writer.getName());
        }
        return true;
    }
    protected boolean include(PropertyWriter writer) {
        if( includesClazz.containsKey(writer.getMember().getDeclaringClass()) ){
            return !this.includesClazz.get(writer.getMember().getDeclaringClass()).contains(writer.getName());
        }
        return true;
    }
    public static void setJFilter(JFilterValue jFilterValue, ObjectMapper objectMapper ){
        JFilter[] jFilter = jFilterValue.getJfilters();
        if (jFilter.length > 0) {
            BeanJFilter beanJFilter = new BeanJFilter();
            for (int i = 0; i < jFilter.length; i++) {
                beanJFilter.addFilter(jFilter[i].clazz(), jFilter[i].property());
                objectMapper.addMixIn(jFilter[i].clazz(), BeanJFilter.class);
            }
            objectMapper.setFilterProvider(new SimpleFilterProvider().addFilter("BeanJFilter", beanJFilter));
        }
    }
}
JFilterHttpMessage Coverterのコードセグメントの中でBenJFilter.set JFilter(JFilterValue)OB ject、oject Mapper)フィルタルールを入れることです.
JFilterHttp Message Coverterはspringbootでbeanを定義する必要があります.
    @Order(0)
    @Bean
    public JFilterHttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
        JFilterHttpMessageConverter messageConverter = new JFilterHttpMessageConverter(objectMapper);
        return messageConverter;
    }
これで終わりです.本人のテストはもう完璧にスプリングフレームに融合できます.