La fonction par défaut de Feign
ne prend pas en charge les opérations des requêtes HTTP qui gèrent les binaires tels que le téléchargement et le téléchargement de fichiers.
Cette fois, je voudrais expliquer comment réaliser le téléchargement de fichiers avec Feign
.
L'utilisation de base de Feign
est expliquée dans l'article suivant, veuillez donc vous y référer.
Cette classe contient les données d'en-tête, de statut et de raison de réponse qui peuvent être obtenues à partir de feign.Response
.
On suppose que les données binaires d'un fichier sont stockées dans le corps de la réponse HTTP et que la spécification ne doit contenir qu'un seul fichier.
Ce n'est pas très courant, mais si vous souhaitez gérer des réponses HTTP en plusieurs parties, modifiez-les en conséquence.
FileEntity.java
package com.example.feign.demo.download;
import java.io.File;
import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
public class FileEntity implements Serializable {
private static final long serialVersionUID = 1L;
private int status;
private Map<String, Collection<String>> headers;
private String reason;
private File file;
public FileEntity() {
}
public FileEntity(int status, Map<String, Collection<String>> headers,
String reason, File file) {
super();
this.status = status;
this.headers = headers;
this.reason = reason;
this.file = file;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("FileEntity [status=");
builder.append(status);
builder.append(", headers=");
builder.append(headers);
builder.append(", reason=");
builder.append(reason);
builder.append(", file=");
builder.append(file);
builder.append("]");
return builder.toString();
}
// setter, getter omitted
}
L'API est aussi simple que de télécharger un fichier avec le chemin spécifié.
La valeur de retour est le FileEntity
de la classe de modèle définie précédemment.
Si java.io.File
ou java.nio.file.Path
est utilisé comme valeur de retour, les informations autres que les données de fichier (en-tête, code d'état, etc.) ne peuvent pas être obtenues, donc FileEntity
est préparé.
DownloadApi.java
package com.example.feign.demo.download;
import feign.Param;
import feign.RequestLine;
public interface DownloadApi {
@RequestLine("GET {path}")
FileEntity download(@Param("path") String path);
}
Tel est le but de cet article. Decoder
est en charge du traitement de la conversion des données (désérialisation) de la réponse HTTP.
Implémente Decoder
pour le téléchargement de fichiers avec l'interface feign.codec.Decoder
ʻimplements. Implémentez le traitement souhaité dans la méthode
decode`. La valeur de retour de cette méthode sera la valeur de retour de l'interface API.
Cette fois, les données BODY de la réponse sont enregistrées telles quelles car elles sont supposées être un seul fichier, mais veuillez noter qu'il est nécessaire de les analyser et de les enregistrer en tant que fichiers multiples dans le cas d'une réponse HTTP en plusieurs parties.
FileEntityDecoder.java
package com.example.feign.demo.download;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import feign.FeignException;
import feign.Response;
import feign.Util;
import feign.codec.DecodeException;
import feign.codec.Decoder;
public class FileEntityDecoder implements Decoder {
private static final int BUFFER_SIZE = 1 * 1024 * 1024;
private String filePath;
public FileEntityDecoder() {
}
public FileEntityDecoder(String filePath) {
this.filePath = filePath;
}
/**
* @see feign.codec.Decoder#decode(feign.Response, java.lang.reflect.Type)
*/
@Override
public Object decode(Response response,
Type type) throws IOException, DecodeException, FeignException {
if (response.status() == 404) {
return Util.emptyValueOf(type);
}
if (response.body() == null) {
return null;
}
return createFileEntity(response, filePath);
}
/**
* Save download file on instructed filePath.
* @param response feign's response
* @param filePath download file path
* @return FileEntity instance
* @throws IOException
*/
private FileEntity createFileEntity(Response response,
String filePath) throws IOException {
// 1. create File object on instructed file path or temporary
File downloadFile = null;
if (filePath == null) {
downloadFile = File.createTempFile("download", null);
} else {
downloadFile = new File(filePath);
}
// 2. copy contents with buffering
try (InputStream input = new BufferedInputStream(
response.body().asInputStream());
OutputStream out = new BufferedOutputStream(
new FileOutputStream(downloadFile));) {
byte[] buffer = new byte[BUFFER_SIZE];
long total = 0;
int len = 0;
while ((len = input.read(buffer)) != -1) {
out.write(buffer, 0, len);
out.flush();
total = total + len;
// System.out.println("writed : " + total);
}
}
// 3. create FileEntity instance
return new FileEntity(response.status(), response.headers(),
response.reason(), downloadFile);
}
}
Lors de la création d'une instance de l'interface API, spécifiez l'instance du FileEntityDecoder
implémentée cette fois dans l'argument de la méthode decoder
.
J'ai utilisé un exemple pour télécharger un fichier PDF sur Internet via Proxy
, qui nécessite une authentification.
Veuillez vous référer à Article précédent pour l'implémentation de la méthode createOkHttpClientCorrespondedProxy
, qui est la clé de la prise en charge de Proxy
.
Remplacez l'URL du point de terminaison http: // www.example.com
par le chemin / document / 2018 / pdf / sample.pdf
vous-même.
DownloadDemo.java
package com.example.feign.demo.download;
import feign.Feign;
import feign.Logger;
import feign.slf4j.Slf4jLogger;
import okhttp3.OkHttpClient;
public class DownloadDemo {
public static void main(String[] args) {
// create instance of okhttp3.OkHttpClient corresponded proxy
OkHttpClient client = createOkHttpClientCorrespondedProxy("yourProxyHost",
8080, "proxyUserId", "proxyPass");
// feign use proxy with authentication
DownloadApi downloadApi = Feign.builder()
// set instance of feign.Client.OkHttpClient
.client(new feign.okhttp.OkHttpClient(client))
.decoder(new FileEntityDecoder()) // use FileEntityDecoder
.logger(new Slf4jLogger()) // use Slf4j
.logLevel(Logger.Level.FULL) // setting log level to most detail
.target(DownloadApi.class, "http://www.example.com");
// call api [GET /documents/2018/pdf/sample.pdf]
FileEntity fileEntity = downloadApi.download(
"/document/2018/pdf/sample.pdf");
System.out.println(fileEntity);
}
// omitted createOkHttpClientCorrespondedProxy method
// see Corresponded Proxy
}
python
22:32:58.703 [main] DEBUG feign.Logger - [DownloadApi#download] ---> GET http://www.example.com/documents/2018/pdf/sample.pdf HTTP/1.1
22:32:58.705 [main] DEBUG feign.Logger - [DownloadApi#download] ---> END HTTP (0-byte body)
22:32:58.819 [main] DEBUG feign.Logger - [DownloadApi#download] <--- HTTP/1.1 200 OK (113ms)
22:32:58.820 [main] DEBUG feign.Logger - [DownloadApi#download] accept-ranges: bytes
22:32:58.820 [main] DEBUG feign.Logger - [DownloadApi#download] content-length: 1656363
22:32:58.820 [main] DEBUG feign.Logger - [DownloadApi#download] content-type: application/pdf
22:32:58.820 [main] DEBUG feign.Logger - [DownloadApi#download] date: Thu, 05 Apr 2018 13:32:56 GMT
22:32:58.820 [main] DEBUG feign.Logger - [DownloadApi#download] proxy-connection: Keep-Alive
22:32:58.820 [main] DEBUG feign.Logger - [DownloadApi#download] server: Apache
22:32:58.820 [main] DEBUG feign.Logger - [DownloadApi#download] set-cookie: server-20480-%3Fmntdlb01%3Fsfarm-web_ap=ECBBGDAKFAAA; Path=/
22:32:58.820 [main] DEBUG feign.Logger - [DownloadApi#download]
22:32:59.678 [main] DEBUG feign.Logger - [DownloadApi#download] Binary data
22:32:59.678 [main] DEBUG feign.Logger - [DownloadApi#download] <--- END HTTP (1656363-byte body)
FileEntity [status=200, headers={accept-ranges=[bytes], content-length=[1656363], content-type=[application/pdf], date=[Thu, 05 Apr 2018 13:32:56 GMT], proxy-connection=[Keep-Alive], server=[Apache], set-cookie=[server-20480-%3Fmntdlb01%3Fsfarm-web_ap=ECBBGDAKFAAA; Path=/]}, reason=OK, file=C:\Users\feign\AppData\Local\Temp\download4121273495791641378.tmp]
Cette fois, j'ai expliqué comment utiliser votre propre Decoder
pour réaliser le téléchargement de fichiers avec Feign
.
La prochaine fois, j'aimerais expliquer comment réaliser le téléchargement de fichiers avec Feign
.
Recommended Posts