おまけにFTP送信
環境作成
実は、Jakarta EE10仕様ではFTP送信を扱うモジュールはありません。
そのため標準的に使われる「Apache Commons Net」の外部ライブラリを使用します。
<!-- FTP送信 -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.10.0</version>
</dependency>
ファイル転送(PUT)処理
以下の様な構成とします。
ここでは記述しませんが、本来は個別の処理を記述するイメージです。
ここで各種FTP接続設定をします。
実際のFTP実行処理となります。
package logic;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import annotation.BaseLogic;
import dao.ContractDao;
import dao.UserDao;
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject;
@BaseLogic
@Dependent
public class CommonLogic implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
protected UserDao userDao;
@Inject
protected ContractDao contractDao;
// FTP送信処理
public boolean uploadFile(String server, int port, String user
, String pass, String remotePath, InputStream localInputStream) {
FTPClient ftpClient = new FTPClient();
try {
// 接続とログイン
ftpClient.connect(server, port);
if (!ftpClient.login(user, pass)) {
return false;
}
// 設定(パッシブモード & バイナリモード推奨)
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// ファイル送信
boolean storeSuccess = ftpClient.storeFile(remotePath, localInputStream);
if (!storeSuccess) {
// 転送開始または転送中のエラー
return false;
}
// サーバーからの最終応答コードが 2xx(成功)か確認する
int replyCode = ftpClient.getReplyCode();
if (!storeSuccess || !FTPReply.isPositiveCompletion(replyCode)) {
// 送信失敗またはサーバー側の保存失敗
return false;
}
// ログアウト
ftpClient.logout();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.disconnect();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
package service;
import java.io.Serializable;
import annotation.BaseLogic;
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import logic.CommonLogic;
@Dependent
public class CommonService implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
@BaseLogic
private CommonLogic commonLogic;
// FTP送信
public boolean putFtpFile() {
// テキストデータをInputStreamとして送信
String content = "Hello, Jakarta EE 10 FTP!";
InputStream inputStream = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
return commonLogic.uploadFile(
"xxx.xxx.xx.xxx", 21, "user_nama_xxx", "password_xxx",
"/test.txt", inputStream
);
}
}
package service;
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import logic.SampleLogic;
@Dependent
@Transactional(value = Transactional.TxType.REQUIRED, rollbackOn = {Exception.class})
public class SampleService extends CommonService {
private static final long serialVersionUID = 1L;
@Inject
private SampleLogic appLogic;
public void exeFtp() {
boolean sendFlg = this.putFtpFile();
}
}
@Inject
private SampleService appService;
~ 省略 ~
public void submit() {
appService.exeFtp();
}
このメソッドでFTP送信に必要な全てのパラメータを決定します。
② ポート(通常は[21]です)
③ FTP接続ユーザー名
④ FTP接続パスワード
⑤ リモート側の対象Path(リネームが可能なので、保存したいフルパス)
⑥ [InputStream]型の送信ファイル
その他のFTP処理
以下ファイル送信部分のコードを以下の様に修正します。
// ファイル送信
boolean storeSuccess = ftpClient.storeFile(remotePath, localInputStream);
if (!storeSuccess) {
// 転送開始または転送中のエラー
return false;
}
boolean storeSuccess = true;
// リモートの指定ディレクトリ配下の一覧を取得(ルートなら "/")
FTPFile[] files = ftpClient.listFiles("/");
for (FTPFile file : files) {
if (file.isDirectory()) {
System.out.println("[DIR] " + file.getName());
} else {
System.out.println("[FILE] " + file.getName() + " (" + file.getSize() + " bytes)");
}
}
1行目の以下コードで参照したいパスを指定します。
FTPFile[] files = ftpClient.listFiles("/");
転送では『InputStream』型にしたので、今度は『OutputStream』型となります。 『CommonLogic.java』の先ほど改修した部分を再度改修します。
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
~ 省略 ~
// リモート側のパスとファイル名の設定
String remoteFilePath = "/hoge.txt";
// ローカル側のパスとファイル名の設定
Path localSavePath = Paths.get("C:/Users/xxx/OneDrive/デスクトップ/xxx/hoge.txt");
try {
// 1. バイナリモードに設定(画像、PDF、ZIPなどの破壊防止)
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// 2. ローカル側の書き込み用 OutputStream を開いてダウンロード実行
try (OutputStream localOutputStream = Files.newOutputStream(localSavePath)) {
boolean success = ftpClient.retrieveFile(remoteFilePath, localOutputStream);
if (success) {
System.out.println("ダウンロード成功: " + localSavePath);
} else {
System.err.println("ダウンロード失敗: リモートファイルが存在しない等の可能性があります");
}
}
} catch (IOException e) {
e.printStackTrace();
}
この3種類があればFTPの大部分の事はできますね。 ただし、これまで紹介したコードは恐ろしく単純なものなのでカスタマイズは必須となります。
例えば各種接続パラメータを『appinfo.properties』で管理をすると便利ですよね。
またはバッチ処理に組込んで、大量のファイルを転送する要件もでてくるかもしれません。





サンプルでは送信ファイルを文字列で作成していますが、当然ファイルパスを指定して送信も可能です。
ただし、[InputStream]型にする必要はあるので以下の様なコードにします。
import java.nio.file.Path;
~ 省略 ~
Path filePath = Paths.get("/path/to/local/file.txt");
try (InputStream localInputStream = Files.newInputStream(filePath)) {
// [localInputStream]をパラメータとして渡す
} catch (IOException e) {
return false;
}