⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/qq_34147021/article/details/86681408 「slagsea」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

最近在使用Spring Cloud封装的Feign,自己在项目中暴露的feign接口中有一个接口是上传文件的,使用了常规的@RequsetParam去获取,然后报错:

The current request is not a multipart request

然后以为是自己前端使用layui没有指定上传类型,修改以后依然无效。然后自己用http直接请求没有feign的服务接口是可以的,最后定位问题在feign接口上。发现,确实在目前版本的spring cloud feign不支持文件上传,需要添加拓展包。

解决思路如下:

服务提供方(接收文件)

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Application {

@RestController
public class UploadController {

@PostMapping(value = "/uploadFile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String handleFileUpload(@RequestPart(value = "file") MultipartFile file) {
return file.getName();
}

}

public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}

}

在服务消费方由于会使用Feign客户端,所以在这里需引入feign对表单提交的依赖,具体如下:


<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>

定义文件上传方的应用主类和FeignClient,假设服务提供方的服务名为up-loader

在启动了服务提供方之后,尝试在服务消费方编写测试用例来通过上面定义的Feign客户端来传文件,比如:

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Application {

public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}

}

@FeignClient(value = "upload-server", configuration = UploadService.MultipartSupportConfig.class)
public interface UploadService {

@PostMapping(value = "/uploadFile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String handleFileUpload(@RequestPart(value = "file") MultipartFile file);

@Configuration
class MultipartSupportConfig {
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder();
}
}

}

除了在接口内部定义配置,也可以使用以下这种方式:

@FeignClient(name = "scau-bbs-rest",configuration = FeignMultipartSupportConfig.class) 引入自己自己定义的配置类,配置类的代码就是上面feign接口的这部分代码:

@Configuration
class MultipartSupportConfig {
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder();
}
}

测试文件功能:

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UploadTester {

@Autowired
private UploadService uploadService;

@Test
@SneakyThrows
public void testHandleFileUpload() {

File file = new File("upload.txt");
DiskFileItem fileItem = (DiskFileItem) new DiskFileItemFactory().createItem("file",
MediaType.TEXT_PLAIN_VALUE, true, file.getName());

try (InputStream input = new FileInputStream(file); OutputStream os = fileItem.getOutputStream()) {
IOUtils.copy(input, os);
} catch (Exception e) {
throw new IllegalArgumentException("Invalid file: " + e, e);
}

MultipartFile multi = new CommonsMultipartFile(fileItem);

log.info(uploadService.handleFileUpload(multi));
}

}

解决上面问题按照例子的思路做久没什么问题,需要注意接收文件的注解使用@RequestPart。

之后自己研究以下源码再补一篇feign原理。

文章目录