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にスキャンされたら実行できます.
第三ステップも重要なステップです.jaskysonの出力前にObject Mapperをコピーして、他の関連コードを実行します.
第四のステップはフィルタを使って、json属性をフィルタリングします.ここではフィールドを取り除くだけです.
JFilterHttp Message Coverterはspringbootでbeanを定義する必要があります.
まず環境は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;
}
これで終わりです.本人のテストはもう完璧にスプリングフレームに融合できます.