Recently, people often ask Spring Cloud Feign how to upload files. There are new members of the team and brothers from other companies. This article briefly summarizes it -
In early Spring Cloud, Feign itself did not have the ability to upload files (1 year ago). To achieve this, you need to write Encoder by yourself to implement upload. Now we are much happier. Because Feign official provides the subproject feign-form, which implements the Encoder required for uploading.
Note: The version I tested is Edgware.RELEASE. Camden and Dalston also adapt to the description in this article.
Add dependency
<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>
Writing Feign Client
@FeignClient(name = "ms-content-sample", configuration = UploadFeignClient.MultipartSupportConfig.class)public interface UploadFeignClient { @RequestMapping(value = "/upload", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumer = MediaType.MULTIPART_FORM_DATA_VALUE) @ResponseBody String handleFileUpload(@RequestPart(value = "file") MultipartFile file); class MultipartSupportConfig { @Bean public Encoder feignFormEncoder() { return new SpringFormEncoder(); } }}As the code shows, in this Feign Client, we reference the configuration class MultipartSupportConfig, and in MultipartSupportConfig, we instantiate SpringFormEncoder. This way the Feign Client can be uploaded.
Note
@RequestMapping(value = "/upload", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumer = MediaType.MULTIPART_FORM_DATA_VALUE) must not be missing;The annotation @RequestPart(value = "file") in the interface definition cannot be written as @RequestParam(value = "file" .
It is best to set the timeout of Hystrix a little longer, such as 5 seconds, otherwise Hystrix may time out before the file is uploaded, resulting in an error on the client side.
The pitfalls of using Feign in SpringCloud
Examples are as follows:
@FeignClient("service-resource")//@RequestMapping("/api/test")public interface TestResourceItg { @RequestMapping(value = "/api/test/raw", method = RequestMethod.POST, consumers = "application/x-www-form-urlencoded") public String raw1(@PathVariable("subject") String subject, // Title @RequestParam("content") String content); // Content} illustrate:
* Use consumptions in RequestMapping to specify the Content-Type of the generated request
*The parameters specified by RequestParam will be spliced after the URL, such as: ?name=xxx&age=18
*PathVariable parameters are sent to a LinkedHashMap<String, ?> into the feign Encoder for processing. The Encoder that implements this interface in Spring is SpringEncoder, and this implementation will use the HttpMessageConverter in Spring to write the request body.
Pit:
*Don't use RequestMapping on the interface class name. Although it can be used, SpringMVC will open the instance of the interface as a controller. This can be viewed in the startup Mapping log.
*Use the default SpringEncoder, when consumption is not specified, the parameters in PathVariable will generate JSON strings to send, and the Form form generation method is not supported by default. The reason is that FormHttpMessageConverter can only handle MultiValueMap, while the use of PathVariable parameters is placed in HashMap. File upload is not supported by default. In fact, there is already an HttpMessageConverter that supports handling various situations.
Fill in the pit:
*Support Form form submission: you only need to write a FormHttpMessageConverter that supports Map. You can call the method of FormHttpMessageConverter internally to simplify operations.
*Support file upload: Just encapsulate the file to be uploaded into a Resource (the Resource must implement the filename interface, which is the identifier of parsing the request parameters into a file), and use the default ResourceHttpMessageConverter to process.
*Support to handle MultipartFile parameters: just write a MultipartFileHttpMessageConverter that supports MultipartFile. You can call ResourceHttpMessageConverter implementation internally. At the same time, please note that it needs to be added to the Parts of FormHttpMessageConverter, and rewrite the getFilename method of FormHttpMessageConverter to support obtaining filename from MultipartFile.
*All HttpMessageConverter can be generated directly in the @Bean mode, and spring will automatically recognize and add
Perfect support for form and file upload:
Plan 1:
Use MapFormHttpMessageConverter.java and MultipartFileHttpMessageConverter.java in attachments
Make the following configuration in Spring
@Beanpublic MapFormHttpMessageConverter mapFormHttpMessageConverter(MultipartFileHttpMessageConverter multipartFileHttpMessageConverter) { MapFormHttpMessageConverter mapFormHttpMessageConverter = new MapFormHttpMessageConverter(); mapFormHttpMessageConverter.addPartConverter(multipartFileHttpMessageConverter); return mapFormHttpMessageConverter;}@Beanpublic MultipartFileHttpMessageConverter multipartFileHttpMessageConverter() { return new MultipartFileHttpMessageConverter();} Plan 2:
Using FeignSpringFormEncoder.java
In Spring, configure it as follows:
@Beanpublic Encoder feignEncoder(ObjectFactory<HttpMessageConverters> messageConverters) { return new FeignSpringFormEncoder(messageConverters);} Recommended usage plan 1
Plan 2 is for reference https://github.com/pcan/feign-client-test, untested
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.