[JAVA] Comment réaliser le téléchargement de fichiers avec Feign

1.Tout d'abord

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.

2. Définition de la classe de modèle

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
}

3. Définition de l'interface API

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);
}

4. Définir le décodeur pour le téléchargement de fichiers

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);
    }
}

5. Course d'essai

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]

6. Enfin

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

Comment réaliser le téléchargement de fichiers avec Feign
Comment réaliser le téléchargement de fichiers avec Feign
Comment télécharger Oracle JDK 8 rpm avec curl
Comment numéroter (nombre) avec html.erb
Comment mettre à jour avec activerecord-import
Comment télécharger des fichiers (Servlet, HTML, Apache, Tomcat)
Comment demander un fichier CSV au format JSON avec jMeter
Comment inverser la compilation du fichier apk en code source Java avec MAC
[Facile] Comment formater automatiquement les fichiers Ruby erb avec vsCode
Comment configurer un proxy avec authentification dans Feign
Comment démarrer avec Slim
Comment convertir un fichier erb en haml
Implémenter le téléchargement de fichiers avec Spring MVC
Comment utiliser mssql-tools avec Alpine
Comment atteindre le rang D de Paiza
[Débutant] Comment supprimer AUCUN FICHIER
Comment démarrer Camunda avec Docker
Comment réaliser un téléchargement de fichiers volumineux avec TERASOLUNA 5.x (= Spring MVC)
Comment ouvrir un fichier de script à partir d'Ubuntu avec du code VS
Comment réaliser un téléchargement de fichiers volumineux avec Rest Template of Spring
Comment recadrer une image avec libGDX
Comment ajuster TextPosition avec l'extension de clavier iOS
Comment partager des fichiers avec Docker Toolbox
[Java] Comment utiliser la classe File
Comment compiler Java avec VsCode & Ant
[Java] Résumez comment comparer avec la méthode equals
[Android] Comment gérer les thèmes sombres
Comment changer d'images miniatures avec JavaScript
[Note] Comment démarrer avec Rspec
Comment faire un contrôle basé sur l'API avec cancancan
Comment mettre à jour les modèles associés avec accepte_nested_attributes_for
Comment définir JAVA_HOME avec l'appassembler-maven-plugin de Maven
Comment implémenter TextInputLayout avec la fonction de validation
Comment gérer les erreurs de connexion avec l'appareil
Comment supprimer des données avec une clé externe
Comment tester l'étendue privée avec JUnit
Comment surveiller nginx avec docker-compose avec datadog
Comment gérer les actifs de précompilation a échoué.
Comment diviser un fichier de message Spring Boot
Comment exécuter Blazor (C #) avec Docker
Comment créer un environnement Rails 6 avec Docker
Comment démarrer un conteneur Docker avec un volume monté dans un fichier de commandes
[Java] Comment tester s'il est nul dans JUnit
Comment se moquer de chaque cas avec Mockito 1x
[Rails] Comment lire le fichier XML téléchargé depuis l'écran en type Hash
[Ruby] Comment convertir un fichier CSV en Yaml (Yml)
Comment se moquer de chaque cas avec PowerMock + Mockito1x
Comment utiliser MyBatis2 (iBatis) avec Spring Boot 1.4 (Spring 4)
Comment enregistrer dans plusieurs tables avec une seule entrée
Comment tester les interruptions pendant Thread.sleep avec JUnit
Comment vider de la base de données (DB) vers le fichier de départ
Comment utiliser le framework Java avec AWS Lambda! ??
Comment créer plusieurs menus déroulants avec ActiveHash