Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 710|回复: 0

spring cloud feign 上传文件报not a type supported by this encoder解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-6-3 01:35:42 | 显示全部楼层 |阅读模式

    上传文件调用外部服务报错: not a type supported by this encoder

    查看SpringFormEncoder类的源码:

     1 public class SpringFormEncoder extends FormEncoder
     2 {
     3  
     4     public SpringFormEncoder()
     5     {
     6         this(((Encoder) (new feign.codec.Encoder.Default())));
     7     }
     8  
     9     public SpringFormEncoder(Encoder delegate)
    10     {
    11         super(delegate);//调用父类的构造方法
    12         MultipartFormContentProcessor processor = (MultipartFormContentProcessor)getContentProcessor(ContentType.MULTIPART);
    13         processor.addWriter(new SpringSingleMultipartFileWriter());
    14         processor.addWriter(new SpringManyMultipartFilesWriter());
    15     }
    16  
    17     public void encode(Object object, Type bodyType, RequestTemplate template)
    18         throws EncodeException
    19     {
    20         if(!bodyType.equals(org/springframework/web/multipart/MultipartFile))
    21         {
    22             super.encode(object, bodyType, template);//调用FormEncoder对应方法
    23             return;
    24         } else
    25         {
    26             MultipartFile file = (MultipartFile)object;
    27             java.util.Map data = Collections.singletonMap(file.getName(), object);
    28             super.encode(data, MAP_STRING_WILDCARD, template);
    29             return;
    30         }
    31     }
    32 }

     

    可以发现SpringFormEncoder的encode方法当传送的对象不是MultipartFile的时候,就会调用super.encode, 也就是FormEncoder的encode方法。

    FormEncoder类的部分源码:

     1 public FormEncoder()
     2     {
     3         this(((Encoder) (new feign.codec.Encoder.Default())));
     4     }
     5  
     6     public FormEncoder(Encoder delegate)
     7     {
     8         _flddelegate = delegate;
     9         List list = Arrays.asList(new ContentProcessor[] {
    10             new MultipartFormContentProcessor(delegate), new UrlencodedFormContentProcessor()
    11         });
    12         processors = new HashMap(list.size(), 1.0F);
    13         ContentProcessor processor;
    14         for(Iterator iterator = list.iterator(); iterator.hasNext(); processors.put(processor.getSupportedContentType(), processor))
    15             processor = (ContentProcessor)iterator.next();
    16  
    17     }
    18  
    19     public void encode(Object object, Type bodyType, RequestTemplate template)
    20         throws EncodeException
    21     {
    22         String contentTypeValue = getContentTypeValue(template.headers());//这里会去到@PostMapping中consumes的值,所以参数需要传对象时指定一下consumes
    23         ContentType contentType = ContentType.of(contentTypeValue);//为啥指定consumes,是因为不指定就是application/x-www-form-urlencoded,而且processors中也包含,为啥包含见FormEncoder的构造函数
    24         if(!MAP_STRING_WILDCARD.equals(bodyType) || !processors.containsKey(contentType))
    25         {
    26             _flddelegate.encode(object, bodyType, template);//_flddelegate是啥呢,是SpringFormEncoder传递过来,也就是new Encoder.Default()
    27             return;
    28         }
    29         Charset charset = getCharset(contentTypeValue);
    30         Map data = (Map)object;
    31         try
    32         {
    33             ((ContentProcessor)processors.get(contentType)).process(template, charset, data);
    34         }
    35         catch(Exception ex)
    36         {
    37             throw new EncodeException(ex.getMessage());
    38         }
    39     }

    FormEncoderr的encode方法当传送的对象是json格式的字符串的时候,就会调用 _flddelegate.encode,即Encoder.Default的encode方法,而这个Encoder.Default的encode方法判断传送的类型不是String或者byte[],就会抛异常

     1 public interface Encoder
     2 {
     3     public static class Default
     4         implements Encoder
     5     {
     6  
     7         public void encode(Object object, Type bodyType, RequestTemplate template)
     8         {
     9             if(bodyType == java/lang/String)
    10                 template.body(object.toString());
    11             else
    12             if(bodyType == [B)
    13                 template.body((byte[])(byte[])object, null);
    14             else
    15             if(object != null)//当我们用对象传递参数的时候,会走这里
    16                 throw new EncodeException(String.format("%s is not a type supported by this encoder.", new Object[] {
    17                     object.getClass()
    18                 }));
    19         }
    20  
    21         public Default()
    22         {
    23         }
    24     }
    25  
    26  
    27     public abstract void encode(Object obj, Type type, RequestTemplate requesttemplate)
    28         throws EncodeException;
    29  
    30     public static final Type MAP_STRING_WILDCARD = Util.MAP_STRING_WILDCARD;
    31  
    32 }

     

    解决方案一:继续使用前面提到的方案,如果引用该配置类的FeignClient中,没有使用实体类作为参数的接口,则去掉配置类上的注解@Configuration就可以了,去掉注解@Configuration之后,该配置就只对通过configuration属性引用该配置的FeignClient起作用(或者将该文件上传接口单独放到一个FeignClient中,去掉配置类上的注解@Configuration)。

    方案一只支持文件上传,如果引用该配置的FeignClient中有使用实体类作为参数接收的接口,则调用该接口时会抛异常。

    解决方案二:继续使用前面提到的方案,将配置文件修改为如下:

     1 @Configuration
     2 class MultipartSupportConfig {
     3     @Autowired
     4     private ObjectFactory<HttpMessageConverters> messageConverters;
     5         
     6     @Bean
     7     public Encoder feignFormEncoder() {
     8         return new SpringFormEncoder(new SpringEncoder(messageConverters));
     9     }
    10  }

    方案二既支持文件上传也支持实体类作为参数接收。

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-2 15:53 , Processed in 0.062626 second(s), 27 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表