微服务间通过Feign传输文件,处理MultipartFile类型

在微服务间通过Feign传输文件,特别是处理MultipartFile类型时,确实需要一些特殊配置。下面是一个清晰的步骤指南,帮助你实现这一过程。

配置Feign客户端支持文件上传

默认情况下,OpenFeign不直接支持MultipartFile传输,你需要进行以下配置。

添加依赖 :在项目的pom.xml文件中引入必要的依赖,以支持表单编码。

复制代码
<dependency>
  <groupId>io.github.openfeign.form</groupId>
  <artifactId>feign-form</artifactId>
  <version>3.8.0</version>
</dependency>
<dependency>
  <groupId>io.github.openfeign.form</groupId>
  <artifactId>feign-form-spring</artifactId>
  <version>3.8.0</version>
</dependency>

创建Feign配置类 :定义一个配置类,为Feign客户端提供一个支持表单编码的Encoder

复制代码
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;

@Configuration
public class FeignMultipartSupportConfig {

    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Encoder feignFormEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }
}

定义Feign客户端接口:在接口中声明文件上传方法,并应用刚才的配置。

注意:一定要加 consumes = MediaType.MULTIPART_FORM_DATA_VALUE),以及使用RequestPart注解!!!!否则会报错

复制代码
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(name = "file-service", configuration = FeignMultipartSupportConfig.class)
// 确保FeignClient指向正确的服务名称
public interface FileServiceClient {

    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    // 服务提供方的上传接口路径
    String handleFileUpload(@RequestPart("file") MultipartFile file);
    // 使用@RequestPart注解,参数名与提供方一致
}

服务提供方接口 :确保文件接收方的Controller正确使用了**@RequestPart**注解并指定了consumes属性。

复制代码
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String handleFileUpload(@RequestPart("file") MultipartFile file) {
    // 处理文件上传的逻辑
}

转换为MockMultipartFile

MockMultipartFile是Spring框架提供的一个类,常用于测试环境中模拟文件上传。如果你的MultipartFile对象需要被转换为MockMultipartFile(例如,为了在测试中模拟或修改文件内容),可以按照以下步骤操作。

添加依赖 :确保项目中包含了spring-test依赖。

复制代码
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>5.3.9</version> <!-- 请使用与你的Spring Boot版本兼容的版本 -->
  <scope>test</scope>
</dependency>

执行转换 :使用MockMultipartFile的构造函数进行转换。这里提供两种常见场景的转换方法。场景一:从已有的MultipartFile转换(保留原文件信息)

复制代码
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

public MockMultipartFile convertMultipartFile(MultipartFile originalFile) throws IOException {
    return new MockMultipartFile(
        "file", // 通常保持与接收时一致的参数名
        originalFile.getOriginalFilename(),
        originalFile.getContentType(),
        originalFile.getBytes() // 获取原文件的字节数据
    );
}

场景二:从本地File对象创建MockMultipartFile

复制代码
import java.io.File;
import java.io.FileInputStream;

public MockMultipartFile convertLocalFile(File file) throws IOException {
    try (FileInputStream fileInputStream = new FileInputStream(file)) {
        return new MockMultipartFile(
            "file",
            file.getName(),
            "application/octet-stream", // 或其他准确的MIME类型,如"image/jpeg"
            fileInputStream
        );
    }
}

转换后得到的MockMultipartFile对象,就可以像普通的MultipartFile一样使用了,例如通过上面配置好的Feign客户端进行传输。

重要注意事项

  • 注解使用 :在Feign接口和方法参数中,务必使用@RequestPart("file"),而不是@RequestParam("file"),否则可能引发Required request part 'file' is not present错误。
  • Hystrix超时设置:如果项目中使用Hystrix,文件上传时间较长,可能需要调整Hystrix的超时时间,避免上传未完成就触发超时回退。
  • 多文件上传 :如果需要上传多个文件(如MultipartFile[]),默认配置可能导致问题。你可能需要自定义一个继承SpringFormEncoder的编码器,并重写其encode方法,以确保多个文件能被正确处理。
  • 依赖版本兼容性 :注意feign-form等依赖的版本与你的Spring Cloud版本保持兼容,以避免不必要的冲突。
  • consumes****属性: 使用 multipart/form-data格式而非JSON格式来上传文件。

报错

报错信息提取为文本,如下所示:

复制代码
feign.codec.EncodeException: Error converting request body

Type definition error: [simple type, class java.io.ByteArrayInputStream]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException:

No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.LinkedHashMap["file"]->util.CustomMultipartFile["inputStream"])

错误摘要 :此错误表明,在通过Feign客户端发送请求时,尝试将包含 java.io.ByteArrayInputStream对象的请求体序列化为JSON失败。根本原因是Jackson库无法序列化 ByteArrayInputStream类型的对象。错误路径显示,该对象位于一个 LinkedHashMap中,键为 "file",其 inputStream属性即为这个无法序列化的流对象。

建议 :请参照上一轮回复中的解决方案,使用 multipart/form-data格式而非JSON格式来上传文件。

解决:

确保文件接收方的Controller正确使用了**@RequestPart注解并指定了consumes****属性。**

必须使用 @RequestPart****和加上consumes,否则会以上错误!!!

复制代码
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(name = "file-service", configuration = FeignMultipartSupportConfig.class)
// 确保FeignClient指向正确的服务名称
public interface FileServiceClient {

    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    // 服务提供方的上传接口路径
    String handleFileUpload(@RequestPart("file") MultipartFile file);
    // 使用@RequestPart注解,参数名与提供方一致
}
相关推荐
_周游2 小时前
Java8 API文档搜索引擎_使用内存缓冲区优化
java·搜索引擎·intellij-idea
twj_one2 小时前
java中23种设计模式
java·开发语言·设计模式
tsyjjOvO2 小时前
JDBC(Java Database Connectivity)
java·数据库
qq_12498707532 小时前
基于springboot的尿毒症健康管理系统的设计与实现(源码+论文+部署+安装)
java·spring boot·spring·毕业设计·计算机毕业设计
编程彩机2 小时前
互联网大厂Java面试:从Spring Boot到微服务优化场景解析
spring boot·分布式事务·微服务架构·java面试·技术解析
猿小羽2 小时前
Flyway + Spring Boot:实现数据库迁移的最佳实践
spring boot·编程·flyway·最佳实践·数据库迁移
黎子越3 小时前
python相关练习
java·前端·python
eso19833 小时前
如何确保程序化广告系统中微服务架构的高可用性和可扩展性?
微服务·云原生·架构
电商API&Tina3 小时前
电商数据采集 API 接口 全维度解析(技术 + 商业 + 合规)
java·大数据·开发语言·数据库·人工智能·json