R e i - D r e a m
for Laravel
Guest
login

最終投稿日:2026年09月20日

おまけにFTP送信

環境作成

システム連携のもう一つの主役と言えば『FTP(File Transfer Protocol)』ですよね。
実は、Jakarta EE10仕様ではFTP送信を扱うモジュールはありません。
そのため標準的に使われる「Apache Commons Net」の外部ライブラリを使用します。
○ 依存関係の追加
お約束の『pom.xml』に依存関係を追加します。
pom.xml

<!-- FTP送信 -->
<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.10.0</version>
</dependency>

ファイル転送(PUT)処理

出来るだけシンプルなコードで記述したいと思います。
以下の様な構成とします。
○ SampleBean.java
FTP転送アクションとして処理を呼び出します。
○ SampleService.java
個別のサービス層となり、転送結果を《真|偽》で受取ります。
ここでは記述しませんが、本来は個別の処理を記述するイメージです。
○ CommonService.java
共通のサービス層となります。
ここで各種FTP接続設定をします。
○ CommonLogic.java
共通のロジック層となります。
実際のFTP実行処理となります。
以下がサンプルソースとなります。
○ CommonLogic.java
CommonLogic.java

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();
            }
        }
    }
}

○ CommonService.java
CommonService.java

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
            );
    }
}

○ SampleService.java
SampleService.java

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();
    }
}

○ SampleBean.java
SampleBean.java

@Inject
private SampleService appService;
~ 省略 ~
public void submit() {
    appService.exeFtp();
}

○ 処理のポイント
ズバリ『CommonService.java』が全てと言っても過言ではありません。
このメソッドでFTP送信に必要な全てのパラメータを決定します。
① 接続IP(またはドメイン名)
② ポート(通常は[21]です)
③ FTP接続ユーザー名
④ FTP接続パスワード
⑤ リモート側の対象Path(リネームが可能なので、保存したいフルパス)
⑥ [InputStream]型の送信ファイル
パラメータを設定したら『CommonLogic.java』が良きに計らってくれます。
ポイント

サンプルでは送信ファイルを文字列で作成していますが、当然ファイルパスを指定して送信も可能です。
ただし、[InputStream]型にする必要はあるので以下の様なコードにします。

import java.nio.file.Paths;
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;
}

その他のFTP処理

○ 転送先のディレクトリやファイル一覧を参照する
『CommonLogic.java』を改修します。
以下ファイル送信部分のコードを以下の様に修正します。
送信部分コード

// ファイル送信
boolean storeSuccess = ftpClient.storeFile(remotePath, localInputStream);
if (!storeSuccess) {
    // 転送開始または転送中のエラー
    return false;
}

差し替え用コード
CommonLogic.java

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("/");

取得した一覧は『isDirectory()』メソッドを使い判別が可能です。

○ リモート上のファイルをダウンロード(GET)する
転送(PUT)とは逆の処理となります。
転送では『InputStream』型にしたので、今度は『OutputStream』型となります。
『CommonLogic.java』の先ほど改修した部分を再度改修します。
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』で管理をすると便利ですよね。
またはバッチ処理に組込んで、大量のファイルを転送する要件もでてくるかもしれません。
ログインしてコメントを残そう!!


レンズモード 【新規購入限定用】
きっぷる