《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原理。

文章目录