Spring Cloud中FeignClient实现文件上传功能

 更新时间:2019年04月26日 09:24:18   作者:ytzzh0726  
这篇文章主要为大家详细介绍了Spring Cloud中FeignClient实现文件上传功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

项目概况:Spring Cloud搭的微服务,使用了eureka,FeignClient,现在遇到FeignClient调用接口时不支持上传文件,

百度到两种方案,一种是使用feign-form和feign-form-spring库来做,源码地址

具体的使用方法是加入maven依赖

<dependency>
 <groupId>io.github.openfeign.form</groupId>
 <artifactId>feign-form-spring</artifactId>
 <version>3.2.2</version>
 </dependency>
 <dependency>
 <groupId>io.github.openfeign.form</groupId>
 <artifactId>feign-form</artifactId>
 <version>3.2.2</version>
</dependency>

注入SpringFormEncoder类

@Bean
 @Primary
 @Scope("prototype")
 public Encoder multipartFormEncoder() {
 return new SpringFormEncoder();
 }

FeignClient接口里方法参数是文件类型的要用@RequestPart注解,且要设置ContentType为multipart/form-data

@ResponseBody
@RequestMapping(value = "/ctstestcase/updateTestCase", method = {RequestMethod.POST}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
 Map<String, Object> updateTestCase(@RequestParam("testcaseId") String testcaseId,
 @RequestParam("name") String name, @RequestParam("assignId") String assignId,
 @RequestParam("areaId") String areaId, @RequestParam("state") Integer state,
 @RequestParam("iterationId") String iterationId,@RequestParam("priority") Integer priority,
 @RequestParam("moduleId") String moduleId, @RequestParam("executionType") Integer executionType,
 @RequestParam("summary") String summary, @RequestParam("tcsteps") String tcsteps,
 @RequestParam("relations") String relations,@RequestParam("attachments") String attachments,
 @RequestPart("files") MultipartFile[] files);

但遇到一个问题,就是不支持文件数组类型,我看了源码,发现源码里底层是有对MultipartFile[]类型的支持的,源码中有个类叫SpringManyMultipartFilesWriter,是专门针对文件数组类型进行操作的,但是配置到项目里的SpringFormEncoder类里却没有对文件数组类型的判断,以致不能支持文件数组的上传.。

SpringManyMultipartFilesWriter源码:

@FieldDefaults(level = PRIVATE, makeFinal = true)
public class SpringManyMultipartFilesWriter extends AbstractWriter {
 
 SpringSingleMultipartFileWriter fileWriter = new SpringSingleMultipartFileWriter();
 
 @Override
 public void write (Output output, String boundary, String key, Object value) throws Exception {
 if (value instanceof MultipartFile[]) {
 val files = (MultipartFile[]) value;
 for (val file : files) {
 fileWriter.write(output, boundary, key, file);
 }
 } else if (value instanceof Iterable) {
 val iterable = (Iterable<?>) value;
 for (val file : iterable) {
 fileWriter.write(output, boundary, key, file);
 }
 }
 }
 
 @Override
 public boolean isApplicable (Object value) {
 if (value == null) {
 return false;
 }
 if (value instanceof MultipartFile[]) {
 return true;
 }
 if (value instanceof Iterable) {
 val iterable = (Iterable<?>) value;
 val iterator = iterable.iterator();
 if (iterator.hasNext() && iterator.next() instanceof MultipartFile) {
 return true;
 }
 }
 return false;
 }

SpringFormEncoder源码:

public class SpringFormEncoder extends FormEncoder {
 
 /**
 * Constructor with the default Feign's encoder as a delegate.
 */
 public SpringFormEncoder () {
 this(new Encoder.Default());
 }
 
 /**
 * Constructor with specified delegate encoder.
 *
 * @param delegate delegate encoder, if this encoder couldn't encode object.
 */
 public SpringFormEncoder (Encoder delegate) {
 super(delegate);
 
 val processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);
 processor.addWriter(new SpringSingleMultipartFileWriter());
 processor.addWriter(new SpringManyMultipartFilesWriter());
 }
 
 @Override
 public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException {
 if (!bodyType.equals(MultipartFile.class)) {
 super.encode(object, bodyType, template);
 return;
 }
 
 val file = (MultipartFile) object;
 val data = singletonMap(file.getName(), object);
 super.encode(data, MAP_STRING_WILDCARD, template);
 }
}

从上面SpringFormEncoder的源码上可以看到SpringFormEncoder类构造时把SpringManyMultipartFilesWriter实例添加到了处理器列表里了,但是在encode方法里又只判断了MultipartFile类型,没有判断数组类型,这就比较奇怪了,底层有对数组的支持但上层却缺少了相应判断,而且在源码里的test包里也没有对文件数组类型的测试,难道只是encode方法里漏掉了?还是说那个文件数组的支持有问题?所以encode方法里才没有加入对其的判断?

于是我先试着对encode方法进行扩展加入对文件数组的判断,应该就可以支持文件数组的上传了,于是把SpringFormEncoder类源码复制出来重命名为FeignSpringFormEncoder,源码如下:

public class FeignSpringFormEncoder extends FormEncoder {
 
 /**
 * Constructor with the default Feign's encoder as a delegate.
 */
 public FeignSpringFormEncoder() {
 this(new Encoder.Default());
 }
 
 
 /**
 * Constructor with specified delegate encoder.
 *
 * @param delegate delegate encoder, if this encoder couldn't encode object.
 */
 public FeignSpringFormEncoder(Encoder delegate) {
 super(delegate);
 
 val processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);
 processor.addWriter(new SpringSingleMultipartFileWriter());
 processor.addWriter(new SpringManyMultipartFilesWriter());
 }
 
 
 @Override
 public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
 if (bodyType.equals(MultipartFile.class)) {
 val file = (MultipartFile) object;
 val data = singletonMap(file.getName(), object);
 super.encode(data, MAP_STRING_WILDCARD, template);
 return;
 } else if (bodyType.equals(MultipartFile[].class)) {
 val file = (MultipartFile[]) object;
 if(file != null) {
 val data = singletonMap(file.length == 0 ? "" : file[0].getName(), object);
 super.encode(data, MAP_STRING_WILDCARD, template);
 return;
 }
 }
 super.encode(object, bodyType, template);
 }
}

经过测试,已经可以支持文件数组了,完美解决。

这里再顺便说一下当时还百度到另一个解决文件上传的方案,这个方案就不细说了,直接上我用到的那个开源代码的地址

这个我试过也是可以解决文件上传问题的,但问题是FeignClient不能用SpringMVC的注解,得用Feign自带的注解,也因此我才扩展了第一种方法来做的文件上传功能。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • SSM框架实现分页和搜索分页的示例代码

    SSM框架实现分页和搜索分页的示例代码

    本篇文章主要介绍了SSM框架实现分页和搜索分页的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • JetBrains IntelliJ IDEA 配置优化技巧

    JetBrains IntelliJ IDEA 配置优化技巧

    这篇文章主要介绍了JetBrains IntelliJ IDEA 配置优化技巧,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • 使Java的JButton文字隐藏功能的实现(不隐藏按钮的前提)

    使Java的JButton文字隐藏功能的实现(不隐藏按钮的前提)

    这篇文章主要介绍了使Java的JButton文字隐藏功能的实现(不隐藏按钮的前提),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Spring Event事件通知机制解读

    Spring Event事件通知机制解读

    这篇文章主要介绍了Spring Event事件通知机制解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Mybatis之#{}与${}的区别使用详解

    Mybatis之#{}与${}的区别使用详解

    这篇文章主要介绍了Mybatis之#{}与${}的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Spring  ApplicationContextAware 接口的作用及使用方式

    Spring  ApplicationContextAware 接口的作用及使用方式

    Spring提供了许多回调接口,用于Bean生命周期中执行特定的操作,通过实现ApplicationContextAware接口,Spring提供了一种便捷的方式让 Bean获取对Spring容器的引用,本文介绍ApplicationContextAware接口的作用、使用方式,以及在实际应用中的常见场景,感兴趣的朋友一起看看吧
    2024-01-01
  • tio-boot jfinal-plugins框架整合redis示例详解

    tio-boot jfinal-plugins框架整合redis示例详解

    这篇文章主要为大家介绍了tio-boot jfinal-plugins框架整合redis示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • SpringBoot面试突击之过滤器和拦截器区别详解

    SpringBoot面试突击之过滤器和拦截器区别详解

    过滤器(Filter)和拦截器(Interceptor)都是基于 AOP(Aspect Oriented Programming,面向切面编程)思想实现的,用来解决项目中某一类问题的两种“工具”,但二者有着明显的差距,接下来我们一起来看
    2022-10-10
  • 打开.properties中文显示unicode编码问题以及解决

    打开.properties中文显示unicode编码问题以及解决

    这篇文章主要介绍了打开.properties中文显示unicode编码问题以及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • springCloud集成nacos启动时报错原因排查

    springCloud集成nacos启动时报错原因排查

    这篇文章主要介绍了springCloud集成nacos启动时报错原因排查,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04

最新评论