Spring BootのサーバでFTP接続をして接続先のファイルの書き換え操作を実装したいです。グーグル検索では、SpringIntegrationのFTPアダプターというライブラリが出てきましたが、認識合っていますか。
はい、その認識で合っています。Spring IntegrationのFTPアダプターは、Spring BootアプリケーションでFTP操作を実装する一般的な方法の1つです。
シンプルなFTPクライアントの実装例を示します。
// build.gradle
dependencies {
implementation 'org.springframework.integration:spring-integration-ftp'
implementation 'org.springframework.boot:spring-boot-starter-integration'
}
// FTPConfig.java
@Configuration
public class FTPConfig {
@Value("${ftp.host}")
private String host;
@Value("${ftp.port}")
private int port;
@Value("${ftp.username}")
private String username;
@Value("${ftp.password}")
private String password;
@Bean
public DefaultFtpSessionFactory ftpSessionFactory() {
DefaultFtpSessionFactory factory = new DefaultFtpSessionFactory();
factory.setHost(host);
factory.setPort(port);
factory.setUsername(username);
factory.setPassword(password);
return factory;
}
@Bean
public FtpTemplate ftpTemplate(DefaultFtpSessionFactory ftpSessionFactory) {
return new FtpTemplate(ftpSessionFactory);
}
}
// FTPService.java
@Service
@Slf4j
public class FTPService {
@Autowired
private FtpTemplate ftpTemplate;
// ファイルの読み込み
public String readFile(String remoteFilePath) {
try {
return ftpTemplate.execute(session -> {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
session.read(remoteFilePath, outputStream);
return new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
});
} catch (Exception e) {
log.error("Failed to read file: " + remoteFilePath, e);
throw new RuntimeException("File read error", e);
}
}
// ファイルの書き込み
public void writeFile(String remoteFilePath, String content) {
try {
ftpTemplate.execute(session -> {
InputStream inputStream = new ByteArrayInputStream(
content.getBytes(StandardCharsets.UTF_8)
);
session.write(inputStream, remoteFilePath);
return null;
});
} catch (Exception e) {
log.error("Failed to write file: " + remoteFilePath, e);
throw new RuntimeException("File write error", e);
}
}
// ファイルの削除
public void deleteFile(String remoteFilePath) {
try {
ftpTemplate.execute(session -> {
session.remove(remoteFilePath);
return null;
});
} catch (Exception e) {
log.error("Failed to delete file: " + remoteFilePath, e);
throw new RuntimeException("File delete error", e);
}
}
}
// application.yml
ftp:
host: ftp.example.com
port: 21
username: your-username
password: your-passwordこの実装には以下の特徴があります:
- Spring Integrationの
FtpTemplateを使用して、FTP操作を抽象化しています。 - 設定は
application.ymlで外部化できます。 - 主な機能:
- ファイルの読み込み
- ファイルの書き込み
- ファイルの削除
使用例:
@RestController
public class FTPController {
@Autowired
private FTPService ftpService;
@PostMapping("/update-file")
public void updateFile(@RequestParam String filePath, @RequestBody String content) {
ftpService.writeFile(filePath, content);
}
}これ以外にも必要な機能がありましたら、例えば:
- ディレクトリの作成/削除
- ファイルの移動/コピー
- ファイル一覧の取得
などの機能を追加することができます。具体的にどのような操作が必要でしょうか?
FTPサーバはDockerで構築しており、docker-compose.yamlは以下のように定義しているのですが、アプリから打鍵すると421が発生します。どのような原因が考えられますか
services:
ftp_server:
image: stilliard/pure-ftpd
container_name: ftp-server
ports:
- "21:21"
- "20:20"
- "30000-30009:30000-30009" # 30000~30009のポートは、このDockerイメージのデフォルト・パッシブ・ポートがアサインされているために必要
environment:
- PUBLICHOST=host.docker.internal
- FTP_USER_NAME=uname
- FTP_USER_PASS=uP@ssw0rd
- FTP_USER_HOME=/home/ubuntu
restart: always
421エラーはFTP接続の確立に失敗したことを示すエラーで、この場合いくつかの原因が考えられます。主な確認ポイントは以下の通りです:
- PASVモード設定: Spring Bootアプリケーションがアクティブモードではなくパッシブモード(PASV)を使用するように設定する必要があります。以下のように設定を修正してみましょう:
// FTPConfig.java
@Configuration
public class FTPConfig {
@Value("${ftp.host}")
private String host;
@Value("${ftp.port}")
private int port;
@Value("${ftp.username}")
private String username;
@Value("${ftp.password}")
private String password;
@Bean
public DefaultFtpSessionFactory ftpSessionFactory() {
DefaultFtpSessionFactory factory = new DefaultFtpSessionFactory();
factory.setHost(host);
factory.setPort(port);
factory.setUsername(username);
factory.setPassword(password);
// パッシブモードの設定
factory.setClientMode(FTPClient.PASSIVE_LOCAL_DATA_CONNECTION_MODE);
// 接続タイムアウトの設定
factory.setConnectTimeout(5000);
// 追加のFTPクライアント設定
factory.setControlEncoding("UTF-8");
factory.setDefaultTimeout(5000);
factory.setDataTimeout(5000);
return factory;
}
@Bean
public FtpTemplate ftpTemplate(DefaultFtpSessionFactory ftpSessionFactory) {
FtpTemplate template = new FtpTemplate(ftpSessionFactory);
template.setAutoCreateDirectory(true);
return template;
}
}
// application.yml
ftp:
host: localhost # Docker使用時はlocalhostを指定
port: 21
username: uname
password: uP@ssw0rd- docker-compose.ymlの修正:
services:
ftp_server:
image: stilliard/pure-ftpd
container_name: ftp-server
ports:
- "21:21"
- "20:20"
- "30000-30009:30000-30009"
environment:
- PUBLICHOST=localhost # host.docker.internalではなくlocalhostを試してください
- FTP_USER_NAME=uname
- FTP_USER_PASS=uP@ssw0rd
- FTP_USER_HOME=/home/ubuntu
- ADDED_FLAGS=-O w3c:/var/log/pure-ftpd/transfer.log # ログ出力を有効化
volumes:
- ./ftp/data:/home/ubuntu # データディレクトリをマウント
- ./ftp/logs:/var/log/pure-ftpd # ログディレクトリをマウント
restart: always- 追加の確認ポイント:
-
ファイアウォールの設定:
- ポート21(制御接続)
- ポート30000-30009(パッシブモードのデータ接続)が開いているか確認
-
ネットワーク接続:
# FTPサーバーへの接続テスト
telnet localhost 21
# コンテナのログ確認
docker logs ftp-server- FTPクライアントでのテスト:
- FileZillaなどのFTPクライアントで接続テストを行い、Spring Boot以外でも同じ問題が発生するか確認
-
トラブルシューティング手順:
-
まず、Docker コンテナが正常に起動していることを確認:
docker ps- コンテナのログを確認:
docker logs ftp-server- FTPサーバーの設定を確認:
docker exec -it ftp-server /bin/bash
cat /etc/pure-ftpd/conf/*- Spring Bootアプリケーションのデバッグログを有効化:
# application.yml
logging:
level:
org.springframework.integration.ftp: DEBUG
org.apache.commons.net.ftp: DEBUGこれらの設定を試してみても問題が解決しない場合は、具体的なエラーメッセージやログを共有していただけると、より詳細な原因究明が可能です。