SpringCloud Feign Jackson自定义配置方式

 更新时间:2022年03月16日 16:09:48   作者:zhaoyang10  
这篇文章主要介绍了SpringCloud Feign Jackson自定义配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Feign Jackson自定义配置

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配置,例如我们项目的配置

    @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: SpringEncoderLogger feignLogger: Slf4jLoggerContract feignContract: SpringMvcContractFeign.Builder feignBuilder: HystrixFeign.BuilderClient feignClient: if Ribbon is enabled it is a LoadBalancerFeignClient, otherwise the default feign client is used.

解决方法

统一配置Feign 的Encoder和Decoder的Jackson转换方式

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 不起作用可以试试这种方式

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());
            }
        });
    }
}

Feign自定义配置应用

环境

nacos: 1.3.1

启动nacos

cd /usr/local/nacos/bin

sh startup.sh -m standalone

自定义Feign的配置

1)添加依赖

加入nacos-discovery发现服务的依赖、web、actuator用于监控检查,添加openfeign依赖才能使用Feign功能

2)修改配置文件

配置nacos注册中心地址,因为不提供服务,所以不需要再注册中心注册因此register-enabled=false

3)添加Feign支持

配置FeignConfiguration类文件

Spring Cloud Netflix默认的SpringMvcController将替换为feign.Contract.Default

用feign.Contract.Default将契约改为Feign原生的默认契约,就可以使用feign自带的注解了

4)自定义Feign接口

Feign接口文件需和启动类再同一包目录下,使用@FeignClient注解配置所需要调用服务,此处nacos-provider是需要在注册中心提供服务

因为上面配置了feign.Contract.Deafault,所以在接口中可以使用Feign原生的注解@RequestLine

添加HelloController类文件

此处使用接口MyFeignClient调用hello方法获取到nacos-provider客户端提供的服务

Feign中记录日志

1)添加配置项

在配置文件中添加记录日志的包,* 而每个FeignClient都需要单独配置,它只能响应debug级别的日志

2)设置日志等级

在FeignConfiguration类文件中配置日志等级

日志等级:

  • NONE:不记录(默认)
  • BASIC:只记录请求方法、URL、响应状态码和执行时间
  • HEADERS:记录基本信息,请求和响应标题
  • FULL: 记录请求和响应标题、正文和行数据

测试Feign自定义的配置

启动nacos-provider、feign-config客户端,进入nacos查询nacos-provider服务是否注册

进入浏览器端键入地址http://localhost:2334/hello,就能访问到nacos-provider提供的服务内容

查看日志

控制台会输出如下信息

[MyFeignClient#hello] <— HTTP/1.1 200 (405ms)
2020-08-13 16:16:23.021 DEBUG 3680 — [nio-2334-exec-1] com.kk.feign.MyFeignClient : [MyFeignClient#hello] content-length: 16
2020-08-13 16:16:23.021 DEBUG 3680 — [nio-2334-exec-1] com.kk.feign.MyFeignClient : [MyFeignClient#hello] content-type: text/plain;charset=UTF-8
2020-08-13 16:16:23.021 DEBUG 3680 — [nio-2334-exec-1] com.kk.feign.MyFeignClient : [MyFeignClient#hello] date: Thu, 13 Aug 2020 08:16:23 GMT
2020-08-13 16:16:23.021 DEBUG 3680 — [nio-2334-exec-1] com.kk.feign.MyFeignClient : [MyFeignClient#hello]
2020-08-13 16:16:23.021 DEBUG 3680 — [nio-2334-exec-1] com.kk.feign.MyFeignClient : [MyFeignClient#hello] Hello Gateway A!
2020-08-13 16:16:23.021 DEBUG 3680 — [nio-2334-exec-1] com.kk.feign.MyFeignClient : [MyFeignClient#hello] <— END HTTP (16-byte body)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 教你用Java在个人电脑上实现微信扫码支付

    教你用Java在个人电脑上实现微信扫码支付

    今天给大家带来的是Java实战的相关知识,文章围绕着Java在个人电脑上实现微信扫码支付展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • jdk15的安装与配置全过程记录

    jdk15的安装与配置全过程记录

    这篇文章主要给大家介绍了关于jdk15的安装与配置,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Jenkins自动化打包为war包

    Jenkins自动化打包为war包

    这篇文章主要介绍了Jenkins自动化打包为war包,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • java实现一次性压缩多个文件到zip中的方法示例

    java实现一次性压缩多个文件到zip中的方法示例

    这篇文章主要介绍了java实现一次性压缩多个文件到zip中的方法,涉及java针对文件批量压缩相关的文件判断、遍历、压缩等操作技巧,需要的朋友可以参考下
    2019-09-09
  • Java实现多文件上传功能

    Java实现多文件上传功能

    这篇文章主要为大家详细介绍了Java实现多文件上传功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • 详解Java线程池队列中的延迟队列DelayQueue

    详解Java线程池队列中的延迟队列DelayQueue

    这篇文章主要为大家详细介绍了Java线程池队列中的延迟队列DelayQueue的相关资料,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-12-12
  • 关于使用ContextClassLoader遇到的问题

    关于使用ContextClassLoader遇到的问题

    这篇文章主要介绍了关于使用ContextClassLoader遇到的问题,ContextClassLoader是通过Thread.currentThread().getContextClassLoader()返回该线程上下文的ClassLoader,需要的朋友可以参考下
    2023-10-10
  • SpringBoot使用Shiro实现动态加载权限详解流程

    SpringBoot使用Shiro实现动态加载权限详解流程

    本文小编将基于 SpringBoot 集成 Shiro 实现动态uri权限,由前端vue在页面配置uri,Java后端动态刷新权限,不用重启项目,以及在页面分配给用户 角色 、 按钮 、uri 权限后,后端动态分配权限,用户无需在页面重新登录才能获取最新权限,一切权限动态加载,灵活配置
    2022-07-07
  • Intellij Idea修改代码方法参数自动提示快捷键的操作

    Intellij Idea修改代码方法参数自动提示快捷键的操作

    这篇文章主要介绍了Intellij Idea修改代码方法参数自动提示快捷键的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • spring配置不扫描service层的原因解答

    spring配置不扫描service层的原因解答

    这篇文章主要介绍了spring配置不扫描service层的原因解答,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03

最新评论