Last time explained how to realize file download with Feign
.
This time I would like to explain how to realize file upload with Feign
.
I implemented my own Decoder
in the download, but I will use this because there is a dedicated module called feign-form for uploading. .. In addition, Official page of GitHub explains as follows.
This module adds support for encoding application/x-www-form-urlencoded and multipart/form-data forms.
feign-form
is a separate module, so add it to the dependency. Please refer to Another article for the basic pom.xml
when using Feign
.
pom.xml
<!-- add feign-form for multipart : start -->
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.3.0</version>
</dependency>
<!-- add feign-form for multipart : end -->
Defines the API interface. There are the following three types of argument data types that can be used for file upload data conversion (serialization).
java.io.File
: Set the upload file as File
byte []
: Set the file data of the upload file as byte []
feign.form.FormData
: Set the upload file with a dedicated classAs a sample, I would like to use three types of data this time.
UploadApi.java
package com.example.feign.demo.upload;
import java.io.File;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
import feign.form.FormData;
public interface UploadApi {
@RequestLine("POST /data/upload")
@Headers("Content-Type: multipart/form-data")
String upload(@Param("remarks") String remarks, @Param("uploadFile") File uploadFile);
@RequestLine("POST /data/upload")
@Headers("Content-Type: multipart/form-data")
String upload(@Param("remarks") String remarks, @Param("uploadFile") byte[] uploadFile);
@RequestLine("POST /data/upload")
@Headers("Content-Type: multipart/form-data")
String upload(@Param("remarks") String remarks, @Param("uploadFile") FormData uploadFile);
}
** Please note that all three types do not work the same. Check the specifications on the API provider (server) side and use the appropriate one. ** **
Data type | Content-Disposition:Filename | Content-Type: |
---|---|---|
java.io.File |
○: Set | ◯: Set (automatic judgment from extension) |
byte[] |
×: Not set | ×: Not set Uniform application/octet-stream Becomes |
feign.form.FormData |
×: Not set | ○: Set (explicitly set by the program) |
The point is to set an instance of the feign.form.FormEncoder
class in the ʻencodermethod. Others are the same as the basic usage of
Feign`.
DownloadDemo.java
package com.example.feign.demo.upload;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import feign.Feign;
import feign.Logger;
import feign.form.FormData;
import feign.form.FormEncoder;
import feign.jackson.JacksonEncoder;
import feign.okhttp.OkHttpClient;
import feign.slf4j.Slf4jLogger;
public class UploadDemo {
public static void main(String[] args) {
// 1. create instance of api interface with feign
UploadApi uploadApi = Feign.builder()
.client(new OkHttpClient())
// use FormEncoder with JacksonEncoder
.encoder(new FormEncoder(new JacksonEncoder()))
// .encoder(new FormEncoder())
.logger(new Slf4jLogger())
.logLevel(Logger.Level.FULL)
.target(UploadApi.class, "http://localhost:3000");
// 2. call api
// File
File uploadFile = new File("C:/tmp/test.png ");
String remarks = "I send a image file.";
String result = uploadApi.upload(remarks, uploadFile);
System.out.println(result);
try (FileInputStream iStream = new FileInputStream(uploadFile);) {
// byte[]
byte[] uploadFileByte = new byte[(int) uploadFile.length()];
iStream.read(uploadFileByte);
String result2 = uploadApi.upload(remarks, uploadFileByte);
System.out.println(result2);
// FormData
FormData formData = new FormData("image/png", uploadFileByte);
String result3 = uploadApi.upload(remarks, formData);
System.out.println(result3);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The implementation code of feign-form is open to the public, so you can see the difference between the three types of operations.
FormData
can be solved by having a field of filename
, but it is a mystery why it is not retained. (Although it retains contentType
)
5.1. File
https://github.com/OpenFeign/feign-form/blob/master/feign-form/src/main/java/feign/form/multipart/SingleFileWriter.java
SingleFileWriter.Where the writeFileMetadata method of the parent class (AbstractWriter) is called in java
writeFileMetadata(output, key, file.getName(), null);
https://github.com/OpenFeign/feign-form/blob/master/feign-form/src/main/java/feign/form/multipart/AbstractWriter.java
AbstractWriter.java writeFileMetadata method
@SneakyThrows
protected void writeFileMetadata (Output output, String name, String fileName, String contentType) {
val contentDesposition = new StringBuilder()
.append("Content-Disposition: form-data; name=\"").append(name).append("\"; ")
.append("filename=\"").append(fileName).append("\"")
.toString();
String fileContentType = contentType;
if (fileContentType == null) {
if (fileName != null) {
fileContentType = URLConnection.guessContentTypeFromName(fileName);
}
if (fileContentType == null) {
fileContentType = "application/octet-stream";
}
}
val string = new StringBuilder()
.append(contentDesposition).append(CRLF)
.append("Content-Type: ").append(fileContentType).append(CRLF)
.append("Content-Transfer-Encoding: binary").append(CRLF)
.append(CRLF)
.toString();
output.write(string);
}
In other words, in the case of File
, it will be as follows.
File.getName ()
is set to filename
in Content-Disposition:
Content-Type:
is set to ʻURLConnection.guessContentTypeFromName (fileName)`5.2. byte[]
https://github.com/OpenFeign/feign-form/blob/master/feign-form/src/main/java/feign/form/multipart/ByteArrayWriter.java
ByteArrayWriter.Where the writeFileMetadata method of the parent class (AbstractWriter) is called in java
writeFileMetadata(output, key, null, null);
In other words, in the case of byte []
, it will be as follows.
Content-Disposition:
filename
is set to null
Content-Type:
is set to ʻapplication / octet-stream`5.3. FormData
https://github.com/OpenFeign/feign-form/blob/master/feign-form/src/main/java/feign/form/multipart/FormDataWriter.java
FormDataWriter.Where the writeFileMetadata method of the parent class (AbstractWriter) is called in java
writeFileMetadata(output, key, null, formData.getContentType());
In other words, in the case of FormData
, it will be as follows.
Content-Disposition:
filename
is set to null
Content-Type:
is set to formData.getContentType ()
This time, I explained how to realize file upload with Feign
. I think it was easier than downloading because of the modules provided.
Recommended Posts