- Реализация FTP-клиента на Java
- 3. Поддержка FTP в JDK
- 4. соединительный
- 5. Список файлов
- 6. загрузка
- 7. Выгрузка
- 8. Заключение
- Java ftp client ftps
- Nested Class Summary
- Nested classes/interfaces inherited from class org.apache.commons.net.ftp.FTPClient
- Field Summary
- Fields inherited from class org.apache.commons.net.ftp.FTPClient
- Fields inherited from class org.apache.commons.net.ftp.FTP
- Fields inherited from class org.apache.commons.net.SocketClient
- Constructor Summary
- Method Summary
- Methods inherited from class org.apache.commons.net.ftp.FTPClient
- Methods inherited from class org.apache.commons.net.ftp.FTP
- Methods inherited from class org.apache.commons.net.SocketClient
- Methods inherited from class java.lang.Object
- Field Detail
- DEFAULT_FTPS_DATA_PORT
- DEFAULT_FTPS_PORT
- KEYSTORE_ALGORITHM
- TRUSTSTORE_ALGORITHM
- PROVIDER
- STORE_TYPE
- Constructor Detail
- FTPSClient
- FTPSClient
- FTPSClient
- FTPSClient
- FTPSClient
- FTPSClient
- Method Detail
- _connectAction_
- _openDataConnection_
- _openDataConnection_
- _prepareDataSocket_
- disconnect
- execADAT
- execAUTH
- execAUTH
- execCCC
- execCONF
- execENC
- execMIC
- execPBSZ
- execPROT
- getAuthValue
- getEnabledCipherSuites
- getEnabledProtocols
- getEnableSessionCreation
- getHostnameVerifier
- getNeedClientAuth
- getTrustManager
- getUseClientMode
- getWantClientAuth
- isEndpointCheckingEnabled
- parseADATReply
- parsePBSZ
- sendCommand
- setAuthValue
- setEnabledCipherSuites
- setEnabledProtocols
- setEnabledSessionCreation
- setEndpointCheckingEnabled
- setHostnameVerifier
- setKeyManager
- setNeedClientAuth
- setTrustManager
- setUseClientMode
- setWantClientAuth
- sslNegotiation
Реализация FTP-клиента на Java
При использовании библиотек, которые используются для взаимодействия с внешними системами, часто рекомендуется написать дополнительные интеграционные тесты, чтобы убедиться, что мы используем библиотеку правильно.
В настоящее время мы обычно используем Docker, чтобы развернуть эти системы для наших интеграционных тестов. Однако, особенно при использовании в пассивном режиме, FTP-сервер — не самое простое приложение для прозрачного запуска внутри контейнера, если мы хотим использовать динамические сопоставления портов (что часто необходимо для возможности запуска тестов на общем CI-сервере. ).
Вот почему мы будем использовать вместо этогоMockFtpServer, FTP-сервер Fake / Stub, написанный на Java, который предоставляет обширный API для удобного использования в тестах JUnit:
commons-net commons-net 3.6 org.mockftpserver MockFtpServer 2.7.1 test
Рекомендуется всегда использовать самую последнюю версию. Их можно найтиhere иhere.
3. Поддержка FTP в JDK
Удивительно, но в некоторых вариантах JDK уже есть базовая поддержка FTP в видеsun.net.www.protocol.ftp.FtpURLConnection.
Однако мы не должны использовать этот класс напрямую, вместо этого можно использовать класс JDKjava.net.URL в качестве абстракции.
Эта поддержка FTP очень проста, но с использованием удобных APIjava.nio.file.Files, этого может быть достаточно для простых случаев использования:
@Test public void givenRemoteFile_whenDownloading_thenItIsOnTheLocalFilesystem() throws IOException < String ftpUrl = String.format( "ftp://user:[email protected]:%d/foobar.txt", fakeFtpServer.getServerControlPort()); URLConnection urlConnection = new URL(ftpUrl).openConnection(); InputStream inputStream = urlConnection.getInputStream(); Files.copy(inputStream, new File("downloaded_buz.txt").toPath()); inputStream.close(); assertThat(new File("downloaded_buz.txt")).exists(); new File("downloaded_buz.txt").delete(); // cleanup >
Поскольку в этой базовой поддержке FTP уже отсутствуют основные функции, такие как списки файлов, мы будем использовать поддержку FTP в библиотеке Apache Net Commons в следующих примерах.
4. соединительный
Сначала нам нужно подключиться к FTP-серверу. Начнем с создания классаFtpClient.
Он будет служить API абстракции для реального FTP-клиента Apache Commons Net:
class FtpClient < private String server; private int port; private String user; private String password; private FTPClient ftp; // constructor void open() throws IOException < ftp = new FTPClient(); ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out))); ftp.connect(server, port); int reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) < ftp.disconnect(); throw new IOException("Exception in connecting to FTP Server"); >ftp.login(user, password); > void close() throws IOException < ftp.disconnect(); >>
Нам нужен адрес сервера и порт, а также имя пользователя и пароль. После подключения необходимо проверить код ответа, чтобы убедиться, что подключение прошло успешно. Мы также добавляемPrintCommandListener, чтобы распечатать ответы, которые мы обычно видим при подключении к FTP-серверу с помощью инструментов командной строки в stdout.
Поскольку наши интеграционные тесты будут иметь некоторый шаблонный код, такой как запуск / остановка MockFtpServer и подключение / отключение нашего клиента, мы можем сделать это с помощью методов@Before и@After:
public class FtpClientIntegrationTest < private FakeFtpServer fakeFtpServer; private FtpClient ftpClient; @Before public void setup() throws IOException < fakeFtpServer = new FakeFtpServer(); fakeFtpServer.addUserAccount(new UserAccount("user", "password", "/data")); FileSystem fileSystem = new UnixFakeFileSystem(); fileSystem.add(new DirectoryEntry("/data")); fileSystem.add(new FileEntry("/data/foobar.txt", "abcdef 1234567890")); fakeFtpServer.setFileSystem(fileSystem); fakeFtpServer.setServerControlPort(0); fakeFtpServer.start(); ftpClient = new FtpClient("localhost", fakeFtpServer.getServerControlPort(), "user", "password"); ftpClient.open(); >@After public void teardown() throws IOException < ftpClient.close(); fakeFtpServer.stop(); >>
Установив для порта управления фиктивным сервером значение 0, мы запускаем фиктивный сервер и свободный случайный порт.
Вот почему мы должны получить фактический порт при созданииFtpClient после запуска сервера, используяfakeFtpServer.getServerControlPort().
5. Список файлов
Первый фактический вариант использования будет список файлов.
Начнем сначала с теста в стиле TDD:
@Test public void givenRemoteFile_whenListingRemoteFiles_thenItIsContainedInList() throws IOException < Collectionfiles = ftpClient.listFiles(""); assertThat(files).contains("foobar.txt"); >
Сама реализация одинаково проста. Чтобы упростить возвращаемую структуру данных для этого примера, мы преобразуем возвращаемый массивFTPFile в списокStrings, используя Java 8Streams:
Collection listFiles(String path) throws IOException
6. загрузка
Для загрузки файла с FTP-сервера мы определяем API.
Здесь мы определяем исходный файл и место назначения в локальной файловой системе:
@Test public void givenRemoteFile_whenDownloading_thenItIsOnTheLocalFilesystem() throws IOException < ftpClient.downloadFile("/buz.txt", "downloaded_buz.txt"); assertThat(new File("downloaded_buz.txt")).exists(); new File("downloaded_buz.txt").delete(); // cleanup >
FTP-клиент Apache Net Commons содержит удобный API, который будет напрямую писать в определенныйOutputStream.. Это означает, что мы можем использовать его напрямую:
void downloadFile(String source, String destination) throws IOException
7. Выгрузка
MockFtpServer предоставляет несколько полезных методов для доступа к содержимому своей файловой системы. Мы можем использовать эту функцию для написания простого интеграционного теста для функции загрузки:
@Test public void givenLocalFile_whenUploadingIt_thenItExistsOnRemoteLocation() throws URISyntaxException, IOException < File file = new File(getClass().getClassLoader().getResource("baz.txt").toURI()); ftpClient.putFileToPath(file, "/buz.txt"); assertThat(fakeFtpServer.getFileSystem().exists("/buz.txt")).isTrue(); >
Загрузка файла с точки зрения API работает аналогично его загрузке, но вместо использованияOutputStream нам нужно вместо этого предоставитьInputStream:
void putFileToPath(File file, String path) throws IOException
8. Заключение
Мы увидели, что использование Java вместе с Apache Net Commons позволяет нам легко взаимодействовать с внешним FTP-сервером как для чтения, так и для записи.
Как обычно, полный код этой статьи доступен в нашихGitHub repository.
Java ftp client ftps
FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to see wire-level SSL details. Warning: the hostname is not verified against the certificate by default, use setHostnameVerifier(HostnameVerifier) or setEndpointCheckingEnabled(boolean) (on Java 1.7+) to enable verification. Verification is only performed on client mode connections.
Nested Class Summary
Nested classes/interfaces inherited from class org.apache.commons.net.ftp.FTPClient
Field Summary
Fields inherited from class org.apache.commons.net.ftp.FTPClient
Fields inherited from class org.apache.commons.net.ftp.FTP
Fields inherited from class org.apache.commons.net.SocketClient
Constructor Summary
Method Summary
Because there are so many connect() methods, the _connectAction_() method is provided as a means of performing some action immediately after establishing a connection, rather than reimplementing all of the connect() methods.
Override the default TrustManager to use; if set to null , the default TrustManager from the JVM will be used.
Configures the socket to request client authentication, but only if such a request is appropriate to the cipher suite negotiated.
Methods inherited from class org.apache.commons.net.ftp.FTPClient
Methods inherited from class org.apache.commons.net.ftp.FTP
Methods inherited from class org.apache.commons.net.SocketClient
Methods inherited from class java.lang.Object
Field Detail
DEFAULT_FTPS_DATA_PORT
DEFAULT_FTPS_PORT
KEYSTORE_ALGORITHM
@Deprecated public static String KEYSTORE_ALGORITHM
TRUSTSTORE_ALGORITHM
@Deprecated public static String TRUSTSTORE_ALGORITHM
PROVIDER
@Deprecated public static String PROVIDER
STORE_TYPE
@Deprecated public static String STORE_TYPE
Constructor Detail
FTPSClient
Constructor for FTPSClient, calls FTPSClient(String, boolean) . Sets protocol to DEFAULT_PROTOCOL — i.e. TLS — and security mode to explicit (isImplicit = false)
FTPSClient
FTPSClient
public FTPSClient(boolean isImplicit, SSLContext context)
Constructor for FTPSClient, using DEFAULT_PROTOCOL — i.e. TLS The default TrustManager is set from TrustManagerUtils.getValidateServerCertificateTrustManager()
FTPSClient
Constructor for FTPSClient, using DEFAULT_PROTOCOL — i.e. TLS and isImplicit false Calls FTPSClient(boolean, SSLContext)
FTPSClient
FTPSClient
public FTPSClient(String protocol, boolean isImplicit)
Constructor for FTPSClient allowing specification of protocol and security mode. If isImplicit is true, the port is set to DEFAULT_FTPS_PORT i.e. 990. The default TrustManager is set from TrustManagerUtils.getValidateServerCertificateTrustManager()
Method Detail
_connectAction_
Because there are so many connect() methods, the _connectAction_() method is provided as a means of performing some action immediately after establishing a connection, rather than reimplementing all of the connect() methods.
_openDataConnection_
@Deprecated protected Socket _openDataConnection_(int command, String arg) throws IOException
Returns a socket of the data connection. Wrapped as an SSLSocket , which carries out handshake processing.
_openDataConnection_
protected Socket _openDataConnection_(String command, String arg) throws IOException
Returns a socket of the data connection. Wrapped as an SSLSocket , which carries out handshake processing.
_prepareDataSocket_
protected void _prepareDataSocket_(Socket socket) throws IOException
Performs any custom initialization for a newly created SSLSocket (before the SSL handshake happens). Called by _openDataConnection_(int, String) immediately after creating the socket. The default implementation is a no-op
disconnect
Closes the connection to the FTP server and restores connection parameters to the default values. Calls setSocketFactory(null) and setServerSocketFactory(null) to reset the factories that may have been changed during the session, e.g. by execPROT(String)
execADAT
public int execADAT(byte[] data) throws IOException
execAUTH
protected void execAUTH() throws SSLException, IOException
execAUTH
public int execAUTH(String mechanism) throws IOException
execCCC
Send the CCC command to the server. The CCC (Clear Command Channel) command causes the underlying SSLSocket instance to be assigned to a plain Socket instances
execCONF
public int execCONF(byte[] data) throws IOException
execENC
public int execENC(byte[] data) throws IOException
execMIC
public int execMIC(byte[] data) throws IOException
execPBSZ
public void execPBSZ(long pbsz) throws SSLException, IOException
execPROT
public void execPROT(String prot) throws SSLException, IOException
- C — Clear
- S — Safe(SSL protocol only)
- E — Confidential(SSL protocol only)
- P — Private
getAuthValue
getEnabledCipherSuites
Returns the names of the cipher suites which could be enabled for use on this connection. When the underlying Socket is not an SSLSocket instance, returns null.
getEnabledProtocols
Returns the names of the protocol versions which are currently enabled for use on this connection. When the underlying Socket is not an SSLSocket instance, returns null.
getEnableSessionCreation
Returns true if new SSL sessions may be established by this socket. When the underlying Socket instance is not SSL-enabled (i.e. an instance of SSLSocket with SSLSocket getEnableSessionCreation() ) enabled, this returns False.
getHostnameVerifier
Get the currently configured HostnameVerifier . The verifier is only used on client mode connections.
getNeedClientAuth
Returns true if the socket will require client authentication. When the underlying Socket is not an SSLSocket instance, returns false.
getTrustManager
getUseClientMode
Returns true if the socket is set to use client mode in its first handshake. When the underlying Socket is not an SSLSocket instance, returns false.
getWantClientAuth
Returns true if the socket will request client authentication. When the underlying Socket is not an SSLSocket instance, returns false.
isEndpointCheckingEnabled
Return whether or not endpoint identification using the HTTPS algorithm on Java 1.7+ is enabled. The default behavior is for this to be disabled. This check is only performed on client mode connections.
parseADATReply
parsePBSZ
public long parsePBSZ(long pbsz) throws SSLException, IOException
PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. Issues the command and parses the response to return the negotiated value.
sendCommand
public int sendCommand(String command, String args) throws IOException
Send an FTP command. A successful CCC (Clear Command Channel) command causes the underlying SSLSocket instance to be assigned to a plain Socket
setAuthValue
setEnabledCipherSuites
Controls which particular cipher suites are enabled for use on this connection. Called before server negotiation.
setEnabledProtocols
Controls which particular protocol versions are enabled for use on this connection. I perform setting before a server negotiation.
setEnabledSessionCreation
setEndpointCheckingEnabled
Automatic endpoint identification checking using the HTTPS algorithm is supported on Java 1.7+. The default behavior is for this to be disabled. This check is only performed on client mode connections.
setHostnameVerifier
public void setHostnameVerifier(HostnameVerifier newHostnameVerifier)
setKeyManager
setNeedClientAuth
setTrustManager
public void setTrustManager(TrustManager trustManager)
Override the default TrustManager to use; if set to null , the default TrustManager from the JVM will be used.
setUseClientMode
setWantClientAuth
Configures the socket to request client authentication, but only if such a request is appropriate to the cipher suite negotiated.
sslNegotiation
SSL/TLS negotiation. Acquires an SSL socket of a control connection and carries out handshake processing.