FTP-kliens megvalósítása Java-ban

1. Áttekintés

Ebben az oktatóanyagban megvizsgáljuk, hogyan lehet kihasználni az Apache Commons Net könyvtárat egy külső FTP-kiszolgálóval való interakcióra.

2. Beállítás

A külső rendszerekkel való interakcióra használt könyvtárak használatakor gyakran érdemes további integrációs teszteket írni annak biztosítása érdekében, hogy a könyvtárat helyesen használjuk.

Manapság általában a Dockert használtuk ezeknek a rendszereknek az integrációs tesztjeihez. Különösen passzív módban használva azonban az FTP-kiszolgáló nem a legkönnyebben átláthatóan futtatható alkalmazás a tárolóban, ha dinamikus port-hozzárendeléseket akarunk használni (ami gyakran szükséges ahhoz, hogy a tesztek futtathatók legyenek megosztott CI-kiszolgálón) ).

Ezért használjuk helyette a MockFtpServert, egy Java-ban írt Fake / Stub FTP szervert, amely kiterjedt API-t biztosít a JUnit tesztek egyszerű használatához:

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

Javasoljuk, hogy mindig a legújabb verziót használja. Ezek megtalálhatók itt és itt.

3. FTP támogatás a JDK-ban

Meglepő módon az FTP-nek már alapvető támogatottsága van egyes JDK ízekben, ezek formájában sun.net.www.protocol.ftp.FtpURLConnection.

Azonban nem szabad ezt az osztályt közvetlenül használnunk, és ehelyett lehetséges a JDK-k használata java.net.URL osztály absztrakcióként.

Ez az FTP támogatás nagyon egyszerű, de kihasználja a java.nio.file.Files, elegendő lehet egyszerű használat esetén:

@Test public void givenRemoteFile_whenDownloading_thenItIsOnTheLocalFilesystem () dobja az IOException {String ftpUrl = String.format ("ftp: // felhasználó: [e-mail védett]:% d / foobar.txt", fakeFtpServer.getSorter URLConnection urlConnection = új URL (ftpUrl) .openConnection (); InputStream inputStream = urlConnection.getInputStream (); Files.copy (inputStream, új File ("letöltött_buz.txt"). ToPath ()); inputStream.close (); assertThat (új Fájl ("letöltött_buz.txt")). létezik (); új Fájl ("letöltött_buz.txt"). delete (); // takarítás}

Mivel ez az alapvető FTP-támogatás már hiányzik az alapvető funkciókból, például a fájlok listájából, az alábbi példákban az FTP-támogatást fogjuk használni az Apache Net Commons könyvtárban.

4. Csatlakozás

Először csatlakoznunk kell az FTP szerverhez. Kezdjük egy osztály létrehozásával FtpClient.

Absztrakciós API-ként szolgál majd a tényleges Apache Commons Net FTP kliens számára:

osztály FtpClient {privát String szerver; privát int kikötő; privát String felhasználó; privát karakterlánc jelszó; privát FTPClient ftp; // konstruktor void open () dobja az IOException-t {ftp = new FTPClient (); ftp.addProtocolCommandListener (új PrintCommandListener (új PrintWriter (System.out))); ftp.connect (szerver, port); int válasz = ftp.getReplyCode (); if (! FTPReply.isPositiveCompletion (válasz)) {ftp.disconnect (); dobja az új IOException-t ("Kivétel az FTP-kiszolgálóhoz való csatlakozáskor"); } ftp.login (felhasználó, jelszó); } void close () dobja az IOException {ftp.disconnect (); }}

Szükségünk van a szerver címére és a portra, valamint a felhasználónévre és a jelszóra. A csatlakozás után ellenőrizni kell a válaszkódot, hogy a kapcsolat sikeres legyen. Hozzáadunk még egy PrintCommandListener, hogy kinyomtassuk azokat a válaszokat, amelyeket általában akkor látunk, amikor FTP-kiszolgálóhoz csatlakozunk parancssori eszközökkel a stdout számára.

Mivel az integrációs tesztjeink tartalmaznak valamilyen kazán kódot, például a MockFtpServer elindítását / leállítását és az ügyfelünk csatlakoztatását / leválasztását, ezeket a @Előtt és @Utána mód:

nyilvános osztály FtpClientIntegrationTest {private FakeFtpServer fakeFtpServer; privát FtpClient ftpClient; @A nyilvános void beállítása előtt () az IOException dobja {fakeFtpServer = új FakeFtpServer (); fakeFtpServer.addUserAccount (új UserAccount ("felhasználó", "jelszó", "/ adatok")); FileSystem fileSystem = új UnixFakeFileSystem (); fileSystem.add (új DirectoryEntry ("/ data")); fileSystem.add (új FileEntry ("/ data / foobar.txt", "abcdef 1234567890")); fakeFtpServer.setFileSystem (fájlrendszer); fakeFtpServer.setServerControlPort (0); hamisFtpServer.start (); ftpClient = new FtpClient ("localhost", fakeFtpServer.getServerControlPort (), "felhasználó", "jelszó"); ftpClient.open (); } @A nyilvános érvénytelen lebontás () után az IOException dob {ftpClient.close (); hamisFtpServer.stop (); }}

Az álkiszolgáló vezérlő portjának 0 értékre állításával elindítjuk az álkiszolgálót és egy szabad véletlenszerű portot.

Ezért meg kell szereznünk a tényleges portot a FtpClient a szerver elindítása után a fakeFtpServer.getServerControlPort ().

5. Fájlok listázása

Az első tényleges felhasználási eset a fájlok felsorolása lesz.

Kezdjük először a teszttel, TDD-stílusban:

@Test public void givenRemoteFile_whenListingRemoteFiles_thenItIsContainedInList () dobja az IOException {Gyűjtemény fájlok = ftpClient.listFiles (""); assertThat (fájlok) .contains ("foobar.txt"); }

Maga a megvalósítás ugyanolyan egyszerű. Annak érdekében, hogy a visszaküldött adatstruktúra egy kicsit egyszerűbb legyen a példa kedvéért, a visszaküldöttet átalakítjuk FTPFile tömb átalakul a Húrok Java 8 használatával Patakok:

Gyűjtemény listFiles (karakterlánc elérési út) dobja az IOException {FTPFile [] fájlokat = ftp.listFiles (elérési út); return Arrays.stream (fájlok) .map (FTPFile :: getName) .collect (Collectors.toList ()); }

6. Letöltés

Egy fájl letöltéséhez az FTP szerverről meghatározunk egy API-t.

Itt definiáljuk a forrásfájlt és a rendeltetési helyet a helyi fájlrendszeren:

@Test public void givenRemoteFile_whenDownloading_thenItIsOnTheLocalFilesystem () dobja az IOException {ftpClient.downloadFile ("/ buz.txt", "letöltött_buz.txt"); assertThat (új Fájl ("letöltött_buz.txt")). létezik (); új Fájl ("letöltött_buz.txt"). delete (); // takarítás}

Az Apache Net Commons FTP kliens egy kényelmes API-t tartalmaz, amely közvetlenül egy megadottra fog írni OutputStream. Ez azt jelenti, hogy ezt közvetlenül használhatjuk:

void downloadFile (karakterlánc-forrás, karakterlánc-cél) az IOException-t dobja ki {FileOutputStream out = új FileOutputStream (cél); ftp.retrieveFile (forrás, ki); }

7. Feltöltés

A MockFtpServer hasznos módszereket kínál a fájlrendszer tartalmának eléréséhez. Ezzel a funkcióval egyszerű integrációs tesztet írhatunk a feltöltési funkcióhoz:

@Test public void givenLocalFile_whenUploadingIt_thenItExistsOnRemoteLocation () dobja az URISyntaxException, IOException {File file = new File (getClass (). GetClassLoader (). GetResource ("baz.txt"). ToURI () ftpClient.putFileToPath (fájl, "/buz.txt"); assertThat (fakeFtpServer.getFileSystem (). létezik ("/ buz.txt")). isTrue (); }

A fájl feltöltése az API-khoz hasonlóan működik, mint a letöltés, de ahelyett, hogy egy OutputStream, meg kell adnunk egy InputStream helyette:

void putFileToPath (Fájlfájl, Karakterlánc-elérési út) dobja az IOException {ftp.storeFile (elérési út, új FileInputStream (fájl)); }

8. Következtetés

Láttuk, hogy a Java és az Apache Net Commons együttes használata lehetővé teszi számunkra, hogy egyszerűen kölcsönhatásba lépjünk egy külső FTP szerverrel, olvasási és írási hozzáférés céljából.

Szokás szerint a cikk teljes kódja elérhető a GitHub adattárunkban.