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

作者:ytzzh0726 时间:2023-06-23 07:57:09 

项目概况: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自带的注解,也因此我才扩展了第一种方法来做的文件上传功能。

来源:https://blog.csdn.net/ytzzh0726/article/details/79467843

标签:Spring,Cloud,文件上传
0
投稿

猜你喜欢

  • Kotlin与Java相互调用的完整实例

    2023-06-17 03:23:23
  • Flutter实现矩形取色器的封装

    2023-06-19 04:08:47
  • 详解Android Flutter中SliverAppBar的使用教程

    2023-06-23 12:11:27
  • C#串口通信模块使用方法示例

    2023-06-19 12:13:57
  • Android ListView的Item点击效果的定制

    2023-06-21 11:46:01
  • springboot大文件上传、分片上传、断点续传、秒传的实现

    2023-06-16 02:18:30
  • Spring MVC 关于controller的字符编码问题

    2023-06-17 09:52:52
  • 如何在Android中实现左右滑动的指引效果

    2023-06-23 09:08:47
  • 安卓GreenDao框架一些进阶用法整理

    2023-06-17 03:27:21
  • 详解Spring Boot Admin监控服务上下线邮件通知

    2023-06-16 21:53:31
  • 解决Android软键盘弹出覆盖h5页面输入框问题

    2023-06-19 11:33:24
  • 重温C# clr 笔记总结

    2023-06-22 02:24:30
  • Android 实现签到足迹功能

    2023-06-21 15:16:24
  • Java实战之实现一个好用的MybatisPlus代码生成器

    2023-06-18 02:16:10
  • Flutter app页面路由以及路由拦截的实现

    2023-06-23 14:21:18
  • Java ArrayList源码深入分析

    2023-06-16 16:30:26
  • flutter ExpansionTile 层级菜单的实现

    2023-06-15 16:04:01
  • springcloud feign传输List的坑及解决

    2023-06-20 18:31:57
  • C++语言实现线性表之链表实例

    2023-06-20 22:21:20
  • Flutter 使用fluro的转场动画进行页面切换

    2023-06-17 11:49:26
  • asp之家 软件编程 m.aspxhome.com