Spring Web MVC 项目中的自定义 StringDeserializer

问题描述 投票:0回答:1

我正在开发一个 Spring MVC 项目,我需要全局覆盖 Jackson 提供的默认

StringDeserializer
来清理传入的 JSON 字符串。我的目标是将这种清理应用于 DTO 中的所有
String
字段,而无需单独注释每个字段(要覆盖超过 200 个 DTO)。

我创建了一个自定义 StringDeserializer 并将其添加到 Spring 配置中,但从未被调用。

自定义解串器:

import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;

public class SanitizeDeserializer extends StringDeserializer {

  @Override
  public String deserialize(
      final JsonParser aParser,
      final DeserializationContext aContext) throws IOException {
    // this code is never executed
    return Jsoup.clean(super.deserialize(aParser, aContext), Safelist.none());
  }    
}

注册反序列化器的 Spring 配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;

@Configuration
public class SanitizeConfiguration {
    
  @Bean
  public Module addSanitizeStringDeserializer() {
    // this code is well executed when running the app
    final SimpleModule module = new SimpleModule();
    module.addDeserializer(String.class, new SanitizeDeserializer());
    return module;
  }
}

REST 控制器示例:

 @PutMapping("/document/{id}")
    public ResponseEntity<String> save(@RequestBody DocumentDTO document) {
        return ResponseEntity.ok(document.getId());
    }

@Getters
@Setters
public class DocumentDTO {
  // I want these String fields to be sanitize before the setter is called when deserializing the JSON
  private String id;
  private String title;
  private String content;
}

我在 deserialize 方法中放置了一个断点,但它从未被调用,它在 Jackson StringDeserializer 方法中中断。

我做错了什么,还是我缺少配置?

或者在已经定义的类型上自定义序列化器可能不可行?

编辑1:

我尝试配置

MessageConverters
,但它覆盖了默认配置 (
WebMvcConfigurationSupport.addDefaultHttpMessageConverters
),虽然所有字符串字段都由自定义反序列化器很好地反序列化,但 XML 内容转换无法像以前一样工作。

  @Override
  public void configureMessageConverters(
      final List<HttpMessageConverter<?>> aConverters) {
    final Jackson2ObjectMapperBuilder iBuilder = new Jackson2ObjectMapperBuilder().deserializerByType(String.class,
        new SanitizeDeserializer());
    aConverters.add(new MappingJackson2HttpMessageConverter(iBuilder.build()));
    // if i remove the following line, the XML response are not handle (500 error)
    // but with this line, XML reponse are XML escaped and become invalid
    aConverters.add(new MappingJackson2XmlHttpMessageConverter(new Jackson2ObjectMapperBuilder().xml().build()));
  }

然后我尝试了评论中的建议,添加一个

Jackson2ObjectMapperBuilder
Bean,但仍然没有使用:

  @Bean
  public Jackson2ObjectMapperBuilder configureJackson2ObjectMapperBuilder() {
    final Jackson2ObjectMapperBuilder iBuilder = new Jackson2ObjectMapperBuilder();
    final SimpleModule iSanitizeModule = new SimpleModule("sanitize-module");
    iSanitizeModule.addDeserializer(String.class, new SanitizeDeserializer());
    iBuilder.modules(iSanitizeModule);
    return iBuilder;
  }

  @Bean
  public MappingJackson2HttpMessageConverter configureMappingJackson2HttpMessageConverter() {
    final MappingJackson2HttpMessageConverter iConverter = new MappingJackson2HttpMessageConverter();
    iConverter.setObjectMapper(configureJackson2ObjectMapperBuilder().build());
    return iConverter;
  }
java spring spring-mvc jackson-databind
1个回答
0
投票

这是可行的解决方案,保留默认的 Spring

MessageConverters
,并在 Jackson JSON 转换器中添加自定义的反序列化器。

自定义代码

Deserializer

public class SanitizeDeserializer extends StringDeserializer {

  @Override
  public String deserialize(
      final JsonParser aParser,
      final DeserializationContext aContext) throws IOException {
    return Jsoup.clean(super.deserialize(aParser, aContext), Safelist.none());
  }    
}

然后,在扩展

@EnableWebMvc
WebMvcConfigurer
类中,重写
extendMessageConverters
以将默认的 Jackson JSON MessageConverter 替换为您的自定义消息转换器:

@Override
public void extendMessageConverters(
    final List<HttpMessageConverter<?>> aConverters) {
  aConverters.removeIf(MappingJackson2HttpMessageConverter.class::isInstance);
  final Jackson2ObjectMapperBuilder iBuilder = new Jackson2ObjectMapperBuilder().deserializerByType(String.class,
      new SanitizeDeserializer());
  aConverters.add(new MappingJackson2HttpMessageConverter(iBuilder.build()));
}
© www.soinside.com 2019 - 2024. All rights reserved.