Implementácia klienta FTP v prostredí Java

1. Prehľad

V tomto výučbe sa pozrieme na to, ako využiť knižnicu Apache Commons Net na interakciu s externým serverom FTP.

2. Inštalácia

Pri používaní knižníc, ktoré sa používajú na interakciu s externými systémami, je často dobré napísať nejaké ďalšie integračné testy, aby sme sa ubezpečili, že knižnicu používame správne.

V dnešnej dobe by sme normálne používali Docker na roztočenie týchto systémov pre naše integračné testy. Avšak najmä pri použití v pasívnom režime nie je server FTP najjednoduchšou aplikáciou, ktorá sa dá transparentne spustiť vo vnútri kontajnera, ak chceme využiť dynamické mapovanie portov (čo je často potrebné pre spustenie testov na zdieľanom serveri CI. ).

Preto namiesto toho použijeme MockFtpServer, Fake / Stub FTP server napísaný v Jave, ktorý poskytuje rozsiahle API pre ľahké použitie v testoch JUnit:

 commons-net commons-net 3.6 org.mockftpserver MockFtpServer 2.7.1 test 

Odporúča sa vždy používať najnovšiu verziu. Tie nájdete tu a tu.

3. Podpora FTP v JDK

Prekvapivo už existuje základná podpora pre FTP v niektorých príchutiach JDK vo forme sun.net.www.protocol.ftp.FtpURLConnection.

Nemali by sme však používať túto triedu priamo a namiesto toho je možné používať JDK java.net.Trieda URL ako abstrakcia.

Táto podpora FTP je veľmi jednoduchá, ale využíva pohodlie API z java.nio.file.files, mohlo by to stačiť na jednoduché prípady použitia:

@Test public void givenRemoteFile_whenDownloading_thenItIsOnTheLocalFilesystem () vyvolá IOException {String ftpUrl = String.format ("ftp: // user: [email protected]:% d / foobar.txt", fakeFtpServer.getServerControl) URLConnection urlConnection = nová URL (ftpUrl) .openConnection (); InputStream inputStream = urlConnection.getInputStream (); Files.copy (inputStream, nový súbor ("stiahnutý_buz.txt"). ToPath ()); inputStream.close (); assertThat (nový súbor ("stiahnutý_buz.txt")). existuje (); nový súbor („stiahnutý_buz.txt“). delete (); // vyčistiť }

Pretože v tejto základnej podpore FTP už chýbajú základné funkcie, ako sú výpisy súborov, v nasledujúcich príkladoch použijeme podporu FTP v knižnici Apache Net Commons.

4. Pripojenie

Najprv sa musíme pripojiť k serveru FTP. Začnime vytvorením triedy FtpClient.

Bude slúžiť ako abstrakčné API pre skutočného FTP klienta Apache Commons Net:

trieda FtpClient {súkromný reťazcový server; súkromný int port; súkromný používateľ reťazca; súkromné ​​reťazcové heslo; súkromný FTPClient ftp; // constructor void open () throws IOException {ftp = new FTPClient (); ftp.addProtocolCommandListener (nový PrintCommandListener (nový PrintWriter (System.out))); ftp.connect (server, port); int odpoveď = ftp.getReplyCode (); if (! FTPReply.isPositiveCompletion (odpoveď)) {ftp.disconnect (); vyvolať novú IOException ("Výnimka pri pripojení k FTP serveru"); } ftp.login (používateľ, heslo); } void close () hodí IOException {ftp.disconnect (); }}

Potrebujeme adresu servera a port, ako aj používateľské meno a heslo. Po pripojení je potrebné skutočne skontrolovať kód odpovede, aby ste sa uistili, že pripojenie bolo úspešné. Pridáme aj a PrintCommandListener, na vytlačenie odpovedí, ktoré by sme za normálnych okolností videli pri pripojení k serveru FTP pomocou nástrojov príkazového riadku na štandardný výstup.

Pretože naše integračné testy budú mať nejaký základný kód, napríklad spustenie / zastavenie MockFtpServeru a pripojenie / odpojenie nášho klienta, môžeme tieto veci robiť v @ Predtým a @ Potom metódy:

verejná trieda FtpClientIntegrationTest {private FakeFtpServer fakeFtpServer; súkromný FtpClient ftpClient; @ Pred public void setup () hodí IOException {fakeFtpServer = nový FakeFtpServer (); fakeFtpServer.addUserAccount (nový účet používateľa ("používateľ", "heslo", "/ údaje")); FileSystem fileSystem = nový UnixFakeFileSystem (); fileSystem.add (nový DirectoryEntry ("/ data")); fileSystem.add (nový FileEntry ("/ data / foobar.txt", "abcdef 1234567890")); fakeFtpServer.setFileSystem (fileSystem); fakeFtpServer.setServerControlPort (0); fakeFtpServer.start (); ftpClient = nový FtpClient ("localhost", fakeFtpServer.getServerControlPort (), "užívateľ", "heslo"); ftpClient.open (); } @After public void teardown () vyvolá IOException {ftpClient.close (); fakeFtpServer.stop (); }}

Nastavením falošného riadiaceho portu servera na hodnotu 0 začíname falošný server a voľný náhodný port.

Preto pri vytváraní súboru musíme zistiť skutočný port FtpClient po spustení servera pomocou fakeFtpServer.getServerControlPort ().

5. Zoznam súborov

Prvým skutočným prípadom použitia bude výpis súborov.

Začnime najskôr testom v štýle TDD:

@Test public void givenRemoteFile_whenListingRemoteFiles_thenItIsContainedInList () vyvolá IOException {Collection files = ftpClient.listFiles (""); assertThat (súbory) .obsahuje ("foobar.txt"); }

Samotná implementácia je rovnako jednoduchá. Aby sme vrátili dátovú štruktúru kvôli tomuto príkladu o niečo jednoduchšou, vrátenú transformujeme FTPFile pole sa transformuje do zoznamu Struny pomocou Java 8 Streamy:

Collection listFiles (reťazcová cesta) vyvolá súbory IOException {FTPFile [] = ftp.listFiles (cesta); návrat Arrays.stream (súbory) .map (FTPFile :: getName) .collect (Collectors.toList ()); }

6. Sťahovanie

Pre stiahnutie súboru zo servera FTP definujeme API.

Tu definujeme zdrojový súbor a cieľ v lokálnom súborovom systéme:

@Test public void givenRemoteFile_whenDownloading_thenItIsOnTheLocalFilesystem () hodí IOException {ftpClient.downloadFile ("/ buz.txt", "stiahnuté_buz.txt"); assertThat (nový súbor ("stiahnutý_buz.txt")). existuje (); nový súbor („stiahnutý_buz.txt“). delete (); // vyčistiť }

Klient Apache Net Commons FTP obsahuje pohodlné API, ktoré bude priamo zapisovať do definovaného OutputStream. To znamená, že to môžeme použiť priamo:

void downloadFile (zdroj reťazca, cieľ reťazca) vyhodí IOException {FileOutputStream out = nový FileOutputStream (cieľ); ftp.retrieveFile (zdroj, von); }

7. Nahrávanie

MockFtpServer poskytuje niekoľko užitočných metód na prístup k obsahu svojho súborového systému. Túto funkciu môžeme použiť na napísanie jednoduchého integračného testu pre funkciu nahrávania:

@Test public void givenLocalFile_whenUploadingIt_thenItExistsOnRemoteLocation () hodí URISyntaxException, IOException {File file = new File (getClass (). GetClassLoader (). GetResource ("baz.txt"). ToURI ()); ftpClient.putFileToPath (súbor, "/buz.txt"); assertThat (fakeFtpServer.getFileSystem (). existuje ("/ buz.txt")). isTrue (); }

Nahrávanie súboru funguje z hľadiska API dosť podobne ako jeho stiahnutie, ale namiesto použitia súboru OutputStream, musíme poskytnúť InputStream namiesto toho:

void putFileToPath (súbor súboru, cesta reťazca) hodí IOException {ftp.storeFile (cesta, nový FileInputStream (súbor)); }

8. Záver

Videli sme, že použitie Java spolu s Apache Net Commons nám umožňuje ľahkú interakciu s externým FTP serverom pre prístup na čítanie aj na zápis.

Úplný kód tohto článku je ako obvykle k dispozícii v našom úložisku GitHub.