OpenFeign 使用FastJson解析返回数据

在微服务项目中,一个服务需要调用另一个服务来获取相关数据,feign组件能够很方便进行调用,添加相关依赖和注解,就能快速进行使用。

在实际应用中,调用完之后需要解析返回的数据,这时候就有一个问题, 如果是多层封装的数据

,如何进行获取?第一时间想到的是直接强转,这样做如果只是简单的返回对象是没有问题的,但需要的数据是对象中集合,而直接强转获取到的集合并不能直接进行操作,这时候就不得不换一种方式。可以把feign调用想象成http调用,而http返回的数据格式是json,那么能不能用json去解析feign返回数据?如果可以就能直接使用FastJson转换成我们需要的集合再进行操作,然鹅使用FastJson解析过程中出现了问题,debug发现返回的数据根本就不是json数据,FastJson直接抛出解析异常,问题在哪就解决问题,返回的数据不是json,那么就让它返回json数据不就能继续往下操作吗?那么如何让feign返回我们需要的json数据呢!!!

查阅相关资料发现(找度娘),因为Feign并不共用Spring MVC的消息转换器链,默认使用的是Jackson Json解析库。只要我们把服务端和客户端都替换成FastJson,理论上就能够返回json数据。

所以来进行配置吧

服务端配置,也就是提供服务的一方

@Configuration
public class FastJsonConverterConfig extends WebMvcConfigurationSupport {

    /**
     * 使用fastjson代替jackson
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //先把JackSon的消息转换器删除.
        //(1)源码分析可知,返回json的过程为:
        //  Controller调用结束后返回一个数据对象,for循环遍历conventers,找到支持application/json的HttpMessageConverter,然后将返回的数据序列化成json。
        //  具体参考org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor的writeWithMessageConverters方法
        //(2)由于是list结构,我们添加的fastjson在最后。因此必须要将jackson的转换器删除,不然会先匹配上jackson,导致没使用fastjson
        for (int i = converters.size() - 1; i >= 0; i--) {
            if (converters.get(i) instanceof MappingJackson2HttpMessageConverter) {
                converters.remove(i);
            }
        }

        //自定义fastjson配置
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(
                // 是否输出值为null的字段,默认为false,我们将它打开
                SerializerFeature.WriteMapNullValue,
                // 将Collection类型字段的字段空值输出为[]
                SerializerFeature.WriteNullListAsEmpty,
                // 将字符串类型字段的空值输出为空字符串
                SerializerFeature.WriteNullStringAsEmpty,
                // 将数值类型字段的空值输出为0
                SerializerFeature.WriteNullNumberAsZero,
                SerializerFeature.WriteDateUseDateFormat,
                // 禁用循环引用
                SerializerFeature.DisableCircularReferenceDetect
        );

        // 添加支持的MediaTypes;不添加时默认为*/*,也就是默认支持全部
        // 但是MappingJackson2HttpMessageConverter里面支持的MediaTypes为application/json
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON);
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);

        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        fastJsonHttpMessageConverter.setFastJsonConfig(config);
        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
        converters.add(fastJsonHttpMessageConverter);
        //支持XML格式的请求
        converters.add(new StringHttpMessageConverter());
    }

    /**
     * 发现如果继承了WebMvcConfigurationSupport,则在yml中配置的相关内容会失效。 需要重新指定静态资源
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations(
                "classpath:/static/");
        registry.addResourceHandler("swagger-ui.html").addResourceLocations(
                "classpath:/META-INF/resources/");
        registry.addResourceHandler("doc.html").addResourceLocations(
                "classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations(
                "classpath:/META-INF/resources/webjars/");
        super.addResourceHandlers(registry);
    }

}

客户端配置,也就是调用的一方

@Configuration
public class FeignSimpleEncoderConfig {
    @Bean
    Logger.Level feignLoggerLevel() {
        //这里记录所有,根据实际情况选择合适的日志level
        return Logger.Level.FULL;
    }

    @Bean
    public Encoder feignEncoder() {
        return new SpringEncoder(feignHttpMessageConverter());
    }

    @Bean
    public Decoder feignDecoder() {
        return new SpringDecoder(feignHttpMessageConverter());
    }

    /**
     * 设置解码器为fastjson
     *
     * @return
     */
    private ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
        final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(this.getFastJsonConverter());
        return () -> httpMessageConverters;
    }

    private FastJsonHttpMessageConverter getFastJsonConverter() {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();

        List<MediaType> supportedMediaTypes = new ArrayList<>();
        MediaType mediaTypeJson = MediaType.valueOf(MediaType.APPLICATION_JSON_UTF8_VALUE);
        supportedMediaTypes.add(mediaTypeJson);
        converter.setSupportedMediaTypes(supportedMediaTypes);
        FastJsonConfig config = new FastJsonConfig();
        config.getSerializeConfig().put(JSON.class, new SwaggerJsonSerializer());
        config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
        converter.setFastJsonConfig(config);

        return converter;
    }
}

feign调用类指定配置

//远程调用
@FeignClient(value = "nakadai",fallback = NakadaiClientImpl.class,configuration = FeignSimpleEncoderConfig.class)
@Component
@Headers("Accept: application/json")
public interface NakadaiClient {

    /**
     * 查询数据
     */
    @Headers({"Content-Type: application/json","Accept: application/json"})
    @GetMapping(value = "/nakadai/nakadai/order/getCustomerOrder",consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    R getCustomerOrder(@RequestParam("id") Integer id);

}

再重新启动,debug可以发现返回的数据符合json格式,接下来就可以对json数据进行操作了

例:

R result= nakadaiClient.getCustomerOrder(id);
Object orderList = customerOrder.get("orderList");
String jsonString = JSON.toJSONString(orderList);
List<Order> orders = JSON.parseArray(jsonString, Order.class);

这样转换虽然较为麻烦,但操作集合时就没有直接强转所导致的问题

在实际运用中,又发现了一个问题,在服务端配置完之后,发现返回格式全都乱码了,导致无法正确获取接口返回数据,然鹅将这个配置类删除,feign返回数据还是json格式,这说明服务端并不需要去进行配置,配置反而会有问题,发现乱码之后直接将配置类删除即可

猜你喜欢

转载自blog.csdn.net/m0_46803792/article/details/119147166