fzy-blog

SpringCloudFeignJackson自定义配置

2019-05-24

Spring Cloud Feign 默认支持 Spring MVC 的注解 使用相同的 HttpMessageConverters 类转换

官方文档说明:

Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web.

但是我们一般在返回给前端 JSON 格式的时候 都会把相应的 NULL 值转为相应的””,这使得 Spring Cloud Feign 也使用相同的 Jackson 配置,例如我们项目的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Bean
public ObjectMapper jacksonObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
// objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
@Override
public void serialize(Object value, JsonGenerator jg, SerializerProvider sp)
throws IOException, JsonProcessingException {
jg.writeString("");
sp.getDefaultNullKeySerializer();
}
});
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
return objectMapper;
}

出现的问题:
在服务通过 Feign 进行请求的时候,传 NULL 值引用类型值时,会出现类型转换异常,由于 HttpMessageConverters 直接把 NULL 转为了””。

解决思路:
自定义配置 Spring Cloud Feign Encoder 与 Decoder

官方文档说明:

Spring Cloud Netflix provides the following beans by default for feign (BeanType beanName: ClassName):
Decoder feignDecoder: ResponseEntityDecoder (which wraps a SpringDecoder)
Encoder feignEncoder: SpringEncoder
Logger feignLogger: Slf4jLogger
Contract feignContract: SpringMvcContract
Feign.Builder feignBuilder: HystrixFeign.Builder
Client feignClient: if Ribbon is enabled it is a LoadBalancerFeignClient, otherwise the default feign client is used.

解决方法:
统一配置 Feign 的 Encoder 和 Decoder 的 Jackson 转换方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import feign.codec.Decoder;
import feign.codec.Encoder;
@Configuration
public class CustomFeignConfig {
@Bean
public Decoder feignDecoder() {
HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
}
@Bean
public Encoder feignEncoder(){
HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
return new SpringEncoder(objectFactory);
}

public ObjectMapper customObjectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
//Customize as much as you want
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
return objectMapper;
}
}

如果配置 DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT 不起作用可以试试这种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public ObjectMapper customObjectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
//Customize as much as you want
objectMapper.registerModule(new StringSanitizerModule());
return objectMapper;
}

public class StringSanitizerModule extends SimpleModule {
public StringSanitizerModule() {
addDeserializer(String.class, new StdScalarDeserializer<String>(String.class) {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
return StringUtils.trimToNull(jsonParser.getValueAsString());
}
});
}
}
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章