Browse Source

Merge branch 'main' of http://172.14.1.63:3000/nextosd/ds-yamoto-farm-server

zdsong 1 month ago
parent
commit
efaa37ae8b

+ 79 - 79
farm-quartz/src/main/java/jp/yamoto/farm/quartz/task/MastCustomerTask.java

@@ -35,10 +35,10 @@ public class MastCustomerTask {
     private AwsSesUtils awsSesUtils;
 
     /**
-     * 定时任务方法 - 顧客マスタ詳細情報CSVファイルを読み込み処理
+     * スケジュールタスクメソッド - 顧客マスタ詳細情報CSVファイルを読み込み処理
      */
     public void executeMastCustomer(String cooperationDate) {
-        logger.info("开始执行顧客マスタ詳細情報CSVファイル読み込み処理");
+        logger.info("顧客マスタ詳細情報CSVファイル読み込み処理を開始実行");
 
         try {
             if (cooperationDate == null || cooperationDate.isEmpty()) {
@@ -46,126 +46,126 @@ public class MastCustomerTask {
             }
 
             mastCustomerOperations(cooperationDate);
-            logger.info("顧客マスタ詳細情報CSVファイルを読み込み処理完成");
+            logger.info("顧客マスタ詳細情報CSVファイル読み込み処理完了");
         } catch (Exception e) {
-            logger.error("顧客マスタ詳細情報CSVファイル読み込み処理失敗: {}", e.getMessage());
+            logger.error("顧客マスタ詳細情報CSVファイル読み込み処理失敗: {}", e.getMessage());
         }
     }
 
     /**
-     * 顧客マスタ詳細情報流程
+     * 顧客マスタ詳細情報処理フロー
      */
     public void mastCustomerOperations(String cooperationDate) {
-        logger.info("开始読み込处理流程");
-        // 1. 下载SFTP文件到本地
+        logger.info("読み込み処理フローを開始");
+        // 1. SFTPファイルをローカルにダウンロード
         String localPath = downloadSftpFile(cooperationDate);
         String[][] csvData = null;
         if (localPath.isEmpty()) {
-            logger.error("顧客マスタ詳細情報 SFTP文件下载失败");
+            logger.error("顧客マスタ詳細情報 SFTPファイルダウンロード失敗");
             return;
         } else {
-            // 2. 解析CSV文件
+            // 2. CSVファイルを解析
             try {
                 csvData = CsvUtils.readCsv(localPath);
                 if (csvData == null || csvData.length == 0) {
-                    logger.error("顧客マスタ詳細情報 CSV文件解析失败");
+                    logger.error("顧客マスタ詳細情報 CSVファイル解析失敗");
                     return;
                 }
-                logger.info("CSV文件解析成功,共读取{}行数据", csvData.length);
+                logger.info("CSVファイル解析成功、合計{}行データを読み込み", csvData.length);
             } catch (java.io.IOException e) {
-                logger.error("顧客マスタ詳細情報 CSV文件读取失败: {}", e.getMessage());
+                logger.error("顧客マスタ詳細情報 CSVファイル読み込み失敗: {}", e.getMessage());
                 return;
             }
         }
 
-        // 3. 顧客マスタ詳細情報CSV文件内容检查和数据库插
+        // 3. 顧客マスタ詳細情報CSVファイル内容チェックとデータベース挿
         int successCount = 0;
         int errorCount = 0;
 
         if (csvData != null && csvData.length > 1) {
 
-            // 跳过表头行,从第1行开始(索引0是表头
+            // ヘッダー行をスキップ、1行目から開始(インデックス0はヘッダー
             for (int i = 1; i < csvData.length; i++) {
                 String[] rowData = csvData[i];
 
                 try {
-                    // 字段长度检查
+                    // フィールド長チェック
                     if (!validateFieldLengths(rowData)) {
-                        logger.warn("第{}行数据字段长度检查失败,跳过插入", i + 1);
+                        logger.warn("第{}行データフィールド長チェック失敗、挿入をスキップ", i + 1);
                         errorCount++;
                         continue;
                     }
 
-                    // 创建实体对象
+                    // エンティティオブジェクトを作成
                     MastCustomerEntity customer = createCustomerEntity(rowData);
 
-                    // 插入数据库
+                    // データベースに挿入
                     int result = mastCustomerBaseService.insert(customer);
                     if (result > 0) {
                         successCount++;
-                        logger.info("第{}行数据插入成功,顾客ID: {}", i + 1, customer.getCustomerId());
+                        logger.info("第{}行データ挿入成功、顧客ID: {}", i + 1, customer.getCustomerId());
                     } else {
                         errorCount++;
-                        logger.warn("第{}行数据插入失败", i + 1);
+                        logger.warn("第{}行データ挿入失敗", i + 1);
                     }
 
                 } catch (Exception e) {
-                    // 继续处理下一行
+                    // 次の行を続けて処理
                     errorCount++;
-                    logger.error("第{}行数据处理异常: {}", i + 1, e.getMessage());
+                    logger.error("第{}行データ処理異常: {}", i + 1, e.getMessage());
                 }
             }
 
-            logger.info("顧客マスタデータ插入完成 - 成功: {}行, 失败: {}行", successCount, errorCount);
+            logger.info("顧客マスタデータ挿入完了 - 成功: {}行, 失敗: {}行", successCount, errorCount);
         } else {
-            logger.warn("CSV数据为空或只有表头,跳过数据库插入");
+            logger.warn("CSVデータが空またはヘッダーのみ、データベース挿入をスキップ");
         }
 
-        // 4.将顧客マスタ詳細情報CSV文件ZIP压缩
+        // 4. 顧客マスタ詳細情報CSVファイルをZIP圧縮
         String zipFilePath = localPath.replace(".txt", ".zip");
         boolean isCompressSuccess = ZipUtils.compressFile(localPath, zipFilePath);
         if (!isCompressSuccess) {
-            logger.error("顧客マスタ詳細情報 CSV文件ZIP压缩失败");
+            logger.error("顧客マスタ詳細情報 CSVファイルZIP圧縮失敗");
             return;
         } else {
-            logger.info("顧客マスタ詳細情報 CSV文件ZIP压缩成功 - 压缩文件: {}", zipFilePath);
+            logger.info("顧客マスタ詳細情報 CSVファイルZIP圧縮成功 - 圧縮ファイル: {}", zipFilePath);
         }
 
-        // 5.将压缩文件上传到AWS S3服务器
+        // 5. 圧縮ファイルをAWS S3サーバーにアップロード
         boolean isUploadSuccess = awsS3Utils.uploadFile("mast_customer/" + cooperationDate + ".zip", zipFilePath);
         if (!isUploadSuccess) {
-            logger.error("顧客マスタ詳細情報 ZIP文件上传到AWS S3服务器失败");
+            logger.error("顧客マスタ詳細情報 ZIPファイルAWS S3サーバーへのアップロード失敗");
             return;
         } else {
-            logger.info("顧客マスタ詳細情報 ZIP文件上传到AWS S3服务器成功 - 存储路径: s3://{}/mast_customer/{}.zip", "my-unencrypted-bucket",
+            logger.info("顧客マスタ詳細情報 ZIPファイルAWS S3サーバーへのアップロード成功 - 保存パス: s3://{}/mast_customer/{}.zip", "my-unencrypted-bucket",
                     cooperationDate);
         }
 
-        // 6.发送电子邮件通知
+        // 6. 電子メール通知を送信
         sendBatchCompletionEmail(cooperationDate, successCount, errorCount);
 
-        logger.info("顧客マスタ詳細情報連携処理流程完成");
+        logger.info("顧客マスタ詳細情報連携処理フロー完了");
 
     }
 
     /**
-     * 发送批量处理完成邮件通知
+     * バッチ処理完了メール通知を送信
      * 
-     * @param cooperationDate 合作日期
-     * @param successCount 成功记录
-     * @param errorCount 失败记录
+     * @param cooperationDate 連携日
+     * @param successCount 成功レコード
+     * @param errorCount 失敗レコード
      */
     private void sendBatchCompletionEmail(String cooperationDate, int successCount, int errorCount) {
         try {
-            // 获取当前时间
+            // 現在時刻を取得
             java.time.LocalDateTime currentTime = java.time.LocalDateTime.now();
             java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
             String currentTimeStr = currentTime.format(formatter);
             
-            // 构建邮件主题
+            // メール件名を構築
             String subject = "顧客マスタ連携バッチ実行状況報告" + cooperationDate;
             
-            // 构建邮件内容(使用您提供的模板
+            // メール内容を構築(提供されたテンプレートを使用
             String content = "管理者 様:\n\n" +
                     "今日の顧客マスタ連携バッチ実行状況を報告致します。\n\n" +
                     currentTimeStr + "時点に顧客マスタ連携バッチが実施完了しました。\n" +
@@ -180,27 +180,27 @@ public class MastCustomerTask {
                     "送信専用メールアカウントのため、ご返信することが出来ませんのでご注意下さい。\n\n" +
                     "以上です。\nよろしくお願い致します。";
             
-            // 发送邮件(需要配置收件人邮箱
-            // 这里需要配置实际的收件人邮箱地址
-            String toEmail = "admin@example.com"; // 请修改为实际收件人邮箱
+            // メールを送信(受信者メールアドレスの設定が必要
+            // ここに実際の受信者メールアドレスを設定してください
+            String toEmail = "admin@example.com"; // 実際の受信者メールアドレスに変更してください
             
             boolean emailSent = awsSesUtils.sendSimpleEmail(toEmail, subject, content);
             
             if (emailSent) {
-                logger.info("批量处理完成邮件发送成功");
+                logger.info("バッチ処理完了メール送信成功");
             } else {
-                logger.error("批量处理完成邮件发送失败");
+                logger.error("バッチ処理完了メール送信失敗");
             }
             
         } catch (Exception e) {
-            logger.error("发送邮件通知异常: {}", e.getMessage());
+            logger.error("メール通知送信異常: {}", e.getMessage());
         }
     }
 
     /**
-     * 获取当前系统时间(YYYYMMDD格式)
+     * 現在のシステム時刻を取得(YYYYMMDD形式)
      * 
-     * @return 当前日期字符串(YYYYMMDD)
+     * @return 現在の日付文字列(YYYYMMDD)
      */
     public String getCurrentDateYYYYMMDD() {
         java.time.LocalDate currentDate = java.time.LocalDate.now();
@@ -209,10 +209,10 @@ public class MastCustomerTask {
     }
 
     /**
-     * 下载SFTP文件到本地
+     * SFTPファイルをローカルにダウンロード
      * 
-     * @param cooperationDate 合作日期,用于生成文件名
-     * @return 下载成功的本地文件路径,失败返回null
+     * @param cooperationDate 連携日、ファイル名生成に使用
+     * @return ダウンロード成功のローカルファイルパス、失敗時はnullを返す
      */
     public String downloadSftpFile(String cooperationDate) {
         String host = "172.14.3.40";
@@ -225,23 +225,23 @@ public class MastCustomerTask {
         try {
             channel = SftpUtils.connect(host, username, password);
 
-            // 检查文件是否存在
+            // ファイルが存在するかチェック
             if (SftpUtils.fileExists(channel, remotePath)) {
                 boolean success = SftpUtils.downloadFile(channel, remotePath, localPath);
                 if (success) {
-                    logger.info("SFTP文件下载成功 - 远程文件: {}, 本地文件: {}", remotePath, localPath);
+                    logger.info("SFTPファイルダウンロード成功 - リモートファイル: {}, ローカルファイル: {}", remotePath, localPath);
                     return localPath;
                 } else {
-                    logger.error("SFTP文件下载失败");
+                    logger.error("SFTPファイルダウンロード失敗");
                     return "";
                 }
             } else {
-                logger.warn("远程文件不存在: {}", remotePath);
+                logger.warn("リモートファイルが存在しません: {}", remotePath);
                 return "";
             }
 
         } catch (JSchException e) {
-            logger.error("SFTP连接失败: {}", e.getMessage());
+            logger.error("SFTP接続失敗: {}", e.getMessage());
             return "";
         } finally {
             if (channel != null) {
@@ -251,100 +251,100 @@ public class MastCustomerTask {
     }
 
     /**
-     * 验证字段长度是否符合数据库表定义
+     * フィールド長がデータベーステーブル定義に合致するか検証
      * 
-     * @param rowData CSV行数据
-     * @return 验证通过返回true,否则返回false
+     * @param rowData CSV行データ
+     * @return 検証通過はtrue、それ以外はfalseを返す
      */
     private boolean validateFieldLengths(String[] rowData) {
         if (rowData == null || rowData.length < 2) {
-            logger.warn("CSV行数据为空或列数不足");
+            logger.warn("CSV行データが空または列数不足");
             return false;
         }
 
         try {
-            // 根据表定义检查字段长度
+            // テーブル定義に基づいてフィールド長をチェック
             // id: varchar(20)
             if (rowData.length > 0 && rowData[0] != null && rowData[0].length() > 20) {
-                logger.warn("ID字段长度超过20字符限制: {}", rowData[0]);
+                logger.warn("IDフィールド長が20文字制限を超えています: {}", rowData[0]);
                 return false;
             }
 
             // customer_id: varchar(20)
             if (rowData.length > 1 && rowData[1] != null && rowData[1].length() > 20) {
-                logger.warn("顾客ID字段长度超过20字符限制: {}", rowData[1]);
+                logger.warn("顧客IDフィールド長が20文字制限を超えています: {}", rowData[1]);
                 return false;
             }
 
             // first_name: varchar(64)
             if (rowData.length > 2 && rowData[2] != null && rowData[2].length() > 64) {
-                logger.warn("姓名字段长度超过64字符限制: {}", rowData[2]);
+                logger.warn("姓フィールド長が64文字制限を超えています: {}", rowData[2]);
                 return false;
             }
 
             // last_name: varchar(32)
             if (rowData.length > 3 && rowData[3] != null && rowData[3].length() > 32) {
-                logger.warn("名字字段长度超过32字符限制: {}", rowData[3]);
+                logger.warn("名フィールド長が32文字制限を超えています: {}", rowData[3]);
                 return false;
             }
 
             // customer_name: varchar(128)
             if (rowData.length > 4 && rowData[4] != null && rowData[4].length() > 128) {
-                logger.warn("顾客名字段长度超过128字符限制: {}", rowData[4]);
+                logger.warn("顧客名フィールド長が128文字制限を超えています: {}", rowData[4]);
                 return false;
             }
 
             // phone_number: varchar(256)
             if (rowData.length > 5 && rowData[5] != null && rowData[5].length() > 256) {
-                logger.warn("电话号码字段长度超过256字符限制: {}", rowData[5]);
+                logger.warn("電話番号フィールド長が256文字制限を超えています: {}", rowData[5]);
                 return false;
             }
 
-            // 其他字段长度检查...
+            // その他のフィールド長チェック...
             // sys_customer_id: varchar(20)
             if (rowData.length > 6 && rowData[6] != null && rowData[6].length() > 20) {
-                logger.warn("系统顾客ID字段长度超过20字符限制: {}", rowData[6]);
+                logger.warn("システム顧客IDフィールド長が20文字制限を超えています: {}", rowData[6]);
                 return false;
             }
 
             // member_id: varchar(20)
             if (rowData.length > 7 && rowData[7] != null && rowData[7].length() > 20) {
-                logger.warn("会员ID字段长度超过20字符限制: {}", rowData[7]);
+                logger.warn("会員IDフィールド長が20文字制限を超えています: {}", rowData[7]);
                 return false;
             }
 
             // furigana_sei: varchar(56)
             if (rowData.length > 8 && rowData[8] != null && rowData[8].length() > 56) {
-                logger.warn("姓フリガナ字段长度超过56字符限制: {}", rowData[8]);
+                logger.warn("姓フリガナフィールド長が56文字制限を超えています: {}", rowData[8]);
                 return false;
             }
 
             // furigana_mei: varchar(56)
             if (rowData.length > 9 && rowData[9] != null && rowData[9].length() > 56) {
-                logger.warn("名フリガナ字段长度超过56字符限制: {}", rowData[9]);
+                logger.warn("名フリガナフィールド長が56文字制限を超えています: {}", rowData[9]);
                 return false;
             }
 
-            // 继续检查其他字段...
+            // 他のフィールドを引き続きチェック...
 
             return true;
 
         } catch (Exception e) {
-            logger.error("字段长度检查异常: {}", e.getMessage());
+            logger.error("フィールド長チェック異常: {}", e.getMessage());
             return false;
         }
     }
 
     /**
-     * 根据CSV行数据创建顾客实体对象
+     * CSV行データに基づいて顧客エンティティオブジェクトを作成
      * 
-     * @param rowData CSV行数据
-     * @return 顾客实体对象
+     * @param rowData CSV行データ
+     * @return 顧客エンティティオブジェクト
      */
     private MastCustomerEntity createCustomerEntity(String[] rowData) {
         MastCustomerEntity customer = new MastCustomerEntity();
 
-        // 设置必填字段
+        // 必須フィールドを設定
         if (rowData.length > 0)
             customer.setId(rowData[0]);
         if (rowData.length > 1)
@@ -358,7 +358,7 @@ public class MastCustomerTask {
         if (rowData.length > 5)
             customer.setPhoneNumber(rowData[5]);
 
-        // 设置可选字段
+        // オプションフィールドを設定
         if (rowData.length > 6)
             customer.setSysCustomerId(rowData[6]);
         if (rowData.length > 7)
@@ -392,7 +392,7 @@ public class MastCustomerTask {
         if (rowData.length > 21)
             customer.setFarmerId(rowData[21]);
 
-        // 设置默认值
+        // デフォルト値を設定
         customer.setSystemSourceFlg("0");
         customer.setDiscontinuedFlg("0");
         customer.setVersion(1);

+ 66 - 53
farm-quartz/src/main/java/jp/yamoto/farm/quartz/util/AwsS3Utils.java

@@ -2,6 +2,7 @@ package jp.yamoto.farm.quartz.util;
 
 import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
 import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.core.ResponseInputStream;
 import software.amazon.awssdk.core.sync.RequestBody;
 import software.amazon.awssdk.regions.Region;
 import software.amazon.awssdk.services.s3.S3Client;
@@ -24,8 +25,8 @@ import java.nio.file.Paths;
 import java.time.Duration;
 
 /**
- * AWS S3工具类
- * 提供文件上传、下载、删除、生成预签名URL等功能
+ * AWS S3ユーティリティクラス
+ * ファイルアップロード、ダウンロード、削除、署名付きURL生成などの機能を提供
  * 
  * @author yamoto
  * @version 1.0
@@ -48,7 +49,7 @@ public class AwsS3Utils {
     private String bucketName;
     
     /**
-     * 创建S3客户端
+     * S3クライアントを作成
      */
     private S3Client createS3Client() {
         return S3Client.builder()
@@ -59,17 +60,17 @@ public class AwsS3Utils {
     }
     
     /**
-     * 上传文件到S3
+     * ファイルをS3にアップロード
      * 
-     * @param key S3对象键
-     * @param filePath 本地文件路径
-     * @return 上传成功返回true
+     * @param key S3オブジェクトキー
+     * @param filePath ローカルファイルパス
+     * @return アップロード成功時はtrueを返す
      */
     public boolean uploadFile(String key, String filePath) {
         try (S3Client s3Client = createS3Client()) {
             File file = new File(filePath);
             if (!file.exists()) {
-                logger.error("文件不存在: {}", filePath);
+                logger.error("ファイルが存在しません: {}", filePath);
                 return false;
             }
             
@@ -79,24 +80,24 @@ public class AwsS3Utils {
                     .build();
             
             s3Client.putObject(putObjectRequest, RequestBody.fromFile(file));
-            logger.info("文件上传成功: {} -> {}/{}", filePath, bucketName, key);
+            logger.info("ファイルアップロード成功: {} -> {}/{}", filePath, bucketName, key);
             return true;
             
         } catch (S3Exception e) {
-            logger.error("S3文件上传失败: {}", e.awsErrorDetails().errorMessage());
+            logger.error("S3ファイルアップロード失敗: {}", e.awsErrorDetails().errorMessage());
             return false;
         } catch (Exception e) {
-            logger.error("文件上传异常: {}", e.getMessage());
+            logger.error("ファイルアップロード異常: {}", e.getMessage());
             return false;
         }
     }
     
     /**
-     * 上传字节数组到S3
+     * バイト配列をS3にアップロード
      * 
-     * @param key S3对象键
-     * @param data 字节数组数据
-     * @return 上传成功返回true
+     * @param key S3オブジェクトキー
+     * @param data バイト配列データ
+     * @return アップロード成功時はtrueを返す
      */
     public boolean uploadBytes(String key, byte[] data) {
         try (S3Client s3Client = createS3Client()) {
@@ -106,24 +107,24 @@ public class AwsS3Utils {
                     .build();
             
             s3Client.putObject(putObjectRequest, RequestBody.fromBytes(data));
-            logger.info("字节数据上传成功: {}/{}", bucketName, key);
+            logger.info("バイトデータアップロード成功: {}/{}", bucketName, key);
             return true;
             
         } catch (S3Exception e) {
-            logger.error("S3字节数据上传失败: {}", e.awsErrorDetails().errorMessage());
+            logger.error("S3バイトデータアップロード失敗: {}", e.awsErrorDetails().errorMessage());
             return false;
         } catch (Exception e) {
-            logger.error("字节数据上传异常: {}", e.getMessage());
+            logger.error("バイトデータアップロード異常: {}", e.getMessage());
             return false;
         }
     }
     
     /**
-     * 从S3下载文件
+     * S3からファイルをダウンロード
      * 
-     * @param key S3对象键
-     * @param downloadPath 下载到本地的路径
-     * @return 下载成功返回true
+     * @param key S3オブジェクトキー
+     * @param filePath ローカル保存パス
+     * @return ダウンロード成功時はtrueを返す
      */
     public boolean downloadFile(String key, String downloadPath) {
         try (S3Client s3Client = createS3Client()) {
@@ -137,23 +138,23 @@ public class AwsS3Utils {
             Files.createDirectories(path.getParent());
             
             s3Client.getObject(getObjectRequest, path);
-            logger.info("文件下载成功: {}/{} -> {}", bucketName, key, downloadPath);
+            logger.info("ファイルダウンロード成功: {}/{} -> {}", bucketName, key, downloadPath);
             return true;
             
         } catch (S3Exception e) {
-            logger.error("S3文件下载失败: {}", e.awsErrorDetails().errorMessage());
+            logger.error("S3ファイルダウンロード失敗: {}", e.awsErrorDetails().errorMessage());
             return false;
         } catch (Exception e) {
-            logger.error("文件下载异常: {}", e.getMessage());
+            logger.error("ファイルダウンロード異常: {}", e.getMessage());
             return false;
         }
     }
     
     /**
-     * 从S3下载文件为字节数组
+     * S3からファイルをバイト配列としてダウンロード
      * 
-     * @param key S3对象键
-     * @return 文件字节数组,失败返回null
+     * @param key S3オブジェクトキー
+     * @return バイト配列、失敗時はnullを返す
      */
     public byte[] downloadBytes(String key) {
         try (S3Client s3Client = createS3Client()) {
@@ -162,24 +163,26 @@ public class AwsS3Utils {
                     .key(key)
                     .build();
             
-            try (InputStream inputStream = s3Client.getObject(getObjectRequest)) {
-                return inputStream.readAllBytes();
+            try (ResponseInputStream<GetObjectResponse> inputStream = s3Client.getObject(getObjectRequest)) {
+                byte[] data = inputStream.readAllBytes();
+                logger.info("バイトデータダウンロード成功: {}/{}", bucketName, key);
+                return data;
             }
             
         } catch (S3Exception e) {
-            logger.error("S3文件下载失败: {}", e.awsErrorDetails().errorMessage());
+            logger.error("S3バイトデータダウンロード失敗: {}", e.awsErrorDetails().errorMessage());
             return null;
         } catch (Exception e) {
-            logger.error("文件下载异常: {}", e.getMessage());
+            logger.error("バイトデータダウンロード異常: {}", e.getMessage());
             return null;
         }
     }
     
     /**
-     * 删除S3文件
+     * S3ファイルを削除
      * 
-     * @param key S3对象键
-     * @return 删除成功返回true
+     * @param key S3オブジェクトキー
+     * @return 削除成功時はtrueを返す
      */
     public boolean deleteFile(String key) {
         try (S3Client s3Client = createS3Client()) {
@@ -189,24 +192,24 @@ public class AwsS3Utils {
                     .build();
             
             s3Client.deleteObject(deleteObjectRequest);
-            logger.info("文件删除成功: {}/{}", bucketName, key);
+            logger.info("ファイル削除成功: {}/{}", bucketName, key);
             return true;
             
         } catch (S3Exception e) {
-            logger.error("S3文件删除失败: {}", e.awsErrorDetails().errorMessage());
+            logger.error("S3ファイル削除失敗: {}", e.awsErrorDetails().errorMessage());
             return false;
         } catch (Exception e) {
-            logger.error("文件删除异常: {}", e.getMessage());
+            logger.error("ファイル削除異常: {}", e.getMessage());
             return false;
         }
     }
     
     /**
-     * 生成预签名URL(用于临时访问)
+     * 署名付きURLを生成
      * 
-     * @param key S3对象键
-     * @param expirationMinutes 过期时间(分钟
-     * @return 预签名URL
+     * @param key S3オブジェクトキー
+     * @param expirationMinutes 有効期限(分
+     * @return 署名付きURL
      */
     public String generatePresignedUrl(String key, int expirationMinutes) {
         try (S3Presigner presigner = S3Presigner.builder()
@@ -228,20 +231,20 @@ public class AwsS3Utils {
             PresignedGetObjectRequest presignedRequest = presigner.presignGetObject(presignRequest);
             URL url = presignedRequest.url();
             
-            logger.info("生成预签名URL: {}", url);
+            logger.info("署名付きURLを生成: {}", url);
             return url.toString();
             
         } catch (Exception e) {
-            logger.error("生成预签名URL异常: {}", e.getMessage());
+            logger.error("署名付きURL生成異常: {}", e.getMessage());
             return null;
         }
     }
     
     /**
-     * 检查文件是否存在
+     * S3ファイルが存在するかチェック
      * 
-     * @param key S3对象键
-     * @return 存在返回true
+     * @param key S3オブジェクトキー
+     * @return 存在する場合はtrueを返す
      */
     public boolean fileExists(String key) {
         try (S3Client s3Client = createS3Client()) {
@@ -251,21 +254,26 @@ public class AwsS3Utils {
                     .build();
             
             s3Client.headObject(headObjectRequest);
+            logger.debug("ファイルが存在: {}/{}", bucketName, key);
             return true;
             
         } catch (NoSuchKeyException e) {
+            logger.debug("ファイルが存在しません: {}/{}", bucketName, key);
+            return false;
+        } catch (S3Exception e) {
+            logger.error("ファイル存在チェック異常: {}", e.awsErrorDetails().errorMessage());
             return false;
         } catch (Exception e) {
-            logger.error("检查文件存在异常: {}", e.getMessage());
+            logger.error("ファイル存在チェック異常: {}", e.getMessage());
             return false;
         }
     }
     
     /**
-     * 获取文件大小
+     * ファイルサイズを取得
      * 
-     * @param key S3对象键
-     * @return 文件大小(字节),失败返回-1
+     * @param key S3オブジェクトキー
+     * @return ファイルサイズ(バイト)、失敗時は-1を返す
      */
     public long getFileSize(String key) {
         try (S3Client s3Client = createS3Client()) {
@@ -275,10 +283,15 @@ public class AwsS3Utils {
                     .build();
             
             HeadObjectResponse response = s3Client.headObject(headObjectRequest);
-            return response.contentLength();
+            long size = response.contentLength();
+            logger.debug("ファイルサイズ: {}/{} -> {} バイト", bucketName, key, size);
+            return size;
             
+        } catch (S3Exception e) {
+            logger.error("ファイルサイズ取得失敗: {}", e.awsErrorDetails().errorMessage());
+            return -1;
         } catch (Exception e) {
-            logger.error("获取文件大小异常: {}", e.getMessage());
+            logger.error("ファイルサイズ取得異常: {}", e.getMessage());
             return -1;
         }
     }

+ 43 - 43
farm-quartz/src/main/java/jp/yamoto/farm/quartz/util/AwsSesUtils.java

@@ -13,8 +13,8 @@ import org.springframework.stereotype.Component;
 import java.util.List;
 
 /**
- * AWS SES邮件服务工具类
- * 提供邮件发送、验证等功能
+ * AWS SESメールサービスユーティリティクラス
+ * メール送信、検証などの機能を提供
  * 
  * @author yamoto
  * @version 1.0
@@ -37,7 +37,7 @@ public class AwsSesUtils {
     private String fromEmail;
     
     /**
-     * 创建SES客户端
+     * SESクライアントを作成
      */
     private SesClient createSesClient() {
         return SesClient.builder()
@@ -48,12 +48,12 @@ public class AwsSesUtils {
     }
     
     /**
-     * 发送简单文本邮件
+     * シンプルなテキストメールを送信
      * 
-     * @param toEmail 收件人邮箱
-     * @param subject 邮件主题
-     * @param content 邮件内容
-     * @return 发送成功返回true
+     * @param toEmail 受信者メールアドレス
+     * @param subject メール件名
+     * @param content メール内容
+     * @return 送信成功時はtrueを返す
      */
     public boolean sendSimpleEmail(String toEmail, String subject, String content) {
         try (SesClient sesClient = createSesClient()) {
@@ -69,25 +69,25 @@ public class AwsSesUtils {
                     .build();
             
             sesClient.sendEmail(emailRequest);
-            logger.info("邮件发送成功: {} -> {}", fromEmail, toEmail);
+            logger.info("メール送信成功: {} -> {}", fromEmail, toEmail);
             return true;
             
         } catch (SesException e) {
-            logger.error("SES邮件发送失败: {}", e.awsErrorDetails().errorMessage());
+            logger.error("SESメール送信失敗: {}", e.awsErrorDetails().errorMessage());
             return false;
         } catch (Exception e) {
-            logger.error("邮件发送异常: {}", e.getMessage());
+            logger.error("メール送信異常: {}", e.getMessage());
             return false;
         }
     }
     
     /**
-     * 发送HTML格式邮件
+     * HTML形式のメールを送信
      * 
-     * @param toEmail 收件人邮箱
-     * @param subject 邮件主题
-     * @param htmlContent HTML邮件内容
-     * @return 发送成功返回true
+     * @param toEmail 受信者メールアドレス
+     * @param subject メール件名
+     * @param htmlContent HTMLメール内容
+     * @return 送信成功時はtrueを返す
      */
     public boolean sendHtmlEmail(String toEmail, String subject, String htmlContent) {
         try (SesClient sesClient = createSesClient()) {
@@ -103,46 +103,46 @@ public class AwsSesUtils {
                     .build();
             
             sesClient.sendEmail(emailRequest);
-            logger.info("HTML邮件发送成功: {} -> {}", fromEmail, toEmail);
+            logger.info("HTMLメール送信成功: {} -> {}", fromEmail, toEmail);
             return true;
             
         } catch (SesException e) {
-            logger.error("SES HTML邮件发送失败: {}", e.awsErrorDetails().errorMessage());
+            logger.error("SES HTMLメール送信失敗: {}", e.awsErrorDetails().errorMessage());
             return false;
         } catch (Exception e) {
-            logger.error("HTML邮件发送异常: {}", e.getMessage());
+            logger.error("HTMLメール送信異常: {}", e.getMessage());
             return false;
         }
     }
     
     /**
-     * 发送带附件的邮件
+     * 添付ファイル付きメールを送信
      * 
-     * @param toEmail 收件人邮箱
-     * @param subject 邮件主题
-     * @param content 邮件内容
-     * @param attachmentPath 附件文件路径
-     * @return 发送成功返回true
+     * @param toEmail 受信者メールアドレス
+     * @param subject メール件名
+     * @param content メール内容
+     * @param attachmentPath 添付ファイルパス
+     * @return 送信成功時はtrueを返す
      */
     public boolean sendEmailWithAttachment(String toEmail, String subject, String content, String attachmentPath) {
         try (SesClient sesClient = createSesClient()) {
-            // 这里需要实现MIME格式的邮件发送,简化版本先返回false
-            logger.warn("带附件邮件功能暂未实现");
+            // ここではMIME形式のメール送信を実装する必要があります。簡易版はfalseを返します
+            logger.warn("添付ファイル付きメール機能はまだ実装されていません");
             return false;
             
         } catch (Exception e) {
-            logger.error("带附件邮件发送异常: {}", e.getMessage());
+            logger.error("添付ファイル付きメール送信異常: {}", e.getMessage());
             return false;
         }
     }
     
     /**
-     * 批量发送邮件
+     * バッチメール送信
      * 
-     * @param toEmails 收件人邮箱列表
-     * @param subject 邮件主题
-     * @param content 邮件内容
-     * @return 成功发送的数量
+     * @param toEmails 受信者メールアドレスリスト
+     * @param subject メール件名
+     * @param content メール内容
+     * @return 成功した送信数
      */
     public int sendBulkEmail(List<String> toEmails, String subject, String content) {
         int successCount = 0;
@@ -153,15 +153,15 @@ public class AwsSesUtils {
             }
         }
         
-        logger.info("批量邮件发送完成: 成功 {} 封,总共 {} 封", successCount, toEmails.size());
+        logger.info("バッチメール送信完了: 成功 {} 件、合計 {} 件", successCount, toEmails.size());
         return successCount;
     }
     
     /**
-     * 验证邮箱地址
+     * メールアドレスを検証
      * 
-     * @param email 需要验证的邮箱地址
-     * @return 验证成功返回true
+     * @param email 検証が必要なメールアドレス
+     * @return 検証成功時はtrueを返す
      */
     public boolean verifyEmail(String email) {
         try (SesClient sesClient = createSesClient()) {
@@ -170,20 +170,20 @@ public class AwsSesUtils {
                     .build();
             
             sesClient.verifyEmailIdentity(verifyRequest);
-            logger.info("邮箱验证请求已发送: {}", email);
+            logger.info("メールアドレス検証リクエストを送信しました: {}", email);
             return true;
             
         } catch (SesException e) {
-            logger.error("邮箱验证失败: {}", e.awsErrorDetails().errorMessage());
+            logger.error("メールアドレス検証失敗: {}", e.awsErrorDetails().errorMessage());
             return false;
         } catch (Exception e) {
-            logger.error("邮箱验证异常: {}", e.getMessage());
+            logger.error("メールアドレス検証異常: {}", e.getMessage());
             return false;
         }
     }
     
     /**
-     * 获取发送统计信息
+     * 送信統計情報を取得
      */
     public void getSendStatistics() {
         try (SesClient sesClient = createSesClient()) {
@@ -192,13 +192,13 @@ public class AwsSesUtils {
             
             List<SendDataPoint> dataPoints = response.sendDataPoints();
             for (SendDataPoint dataPoint : dataPoints) {
-                logger.info("发送统计 - 时间: {}, 投递尝试: {}, 退回: {}, 投诉: {}", 
+                logger.info("送信統計 - 時間: {}, 配信試行: {}, 返送: {}, 苦情: {}", 
                         dataPoint.timestamp(), dataPoint.deliveryAttempts(), 
                         dataPoint.bounces(), dataPoint.complaints());
             }
             
         } catch (Exception e) {
-            logger.error("获取发送统计异常: {}", e.getMessage());
+            logger.error("送信統計取得異常: {}", e.getMessage());
         }
     }
 }

+ 85 - 138
farm-quartz/src/main/java/jp/yamoto/farm/quartz/util/SftpUtils.java

@@ -14,7 +14,7 @@ import java.util.Properties;
 import java.util.Vector;
 
 /**
- * SFTP工具类 - 提供SFTP连接管理、文件下载、上传和存在判断功能
+ * SFTPユーティリティクラス - SFTP接続管理、ファイルダウンロード、アップロード、存在確認機能を提供
  * 
  * @author yamoto
  * @version 1.0
@@ -24,29 +24,29 @@ public class SftpUtils {
     private static final Logger logger = LoggerFactory.getLogger(SftpUtils.class);
     
     /**
-     * 默认SFTP端口
+     * デフォルトSFTPポート
      */
     private static final int DEFAULT_SFTP_PORT = 22;
     
     /**
-     * 默认连接超时时间(毫秒)
+     * デフォルト接続タイムアウト時間(ミリ秒)
      */
     private static final int DEFAULT_CONNECT_TIMEOUT = 10000;
     
     /**
-     * 默认会话超时时间(毫秒)
+     * デフォルトセッションタイムアウト時間(ミリ秒)
      */
     private static final int DEFAULT_SESSION_TIMEOUT = 30000;
     
     /**
-     * 建立SFTP
+     * SFTP接続を確立
      * 
-     * @param host 主机地址
-     * @param port 端口
-     * @param username 用户
-     * @param password 密码
-     * @return ChannelSftp对象
-     * @throws JSchException SFTP连接异常
+     * @param host ホストアドレス
+     * @param port ポート番
+     * @param username ユーザー
+     * @param password パスワード
+     * @return ChannelSftpオブジェクト
+     * @throws JSchException SFTP接続例外
      */
     public static ChannelSftp connect(String host, int port, String username, String password) throws JSchException {
         JSch jsch = new JSch();
@@ -63,27 +63,27 @@ public class SftpUtils {
         ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
         channel.connect();
         
-        logger.info("SFTP连接成功 - 主机: {}, 端口: {}, 用户: {}", host, port, username);
+        logger.info("SFTP接続成功 - ホスト: {}, ポート: {}, ユーザー: {}", host, port, username);
         return channel;
     }
     
     /**
-     * 建立SFTP连接(使用默认端口22
+     * SFTP接続を確立(デフォルトポート22を使用
      * 
-     * @param host 主机地址
-     * @param username 用户
-     * @param password 密码
-     * @return ChannelSftp对象
-     * @throws JSchException SFTP连接异常
+     * @param host ホストアドレス
+     * @param username ユーザー
+     * @param password パスワード
+     * @return ChannelSftpオブジェクト
+     * @throws JSchException SFTP接続例外
      */
     public static ChannelSftp connect(String host, String username, String password) throws JSchException {
         return connect(host, DEFAULT_SFTP_PORT, username, password);
     }
     
     /**
-     * 关闭SFTP
+     * SFTP接続を閉じる
      * 
-     * @param channel SFTP通道
+     * @param channel SFTPチャネル
      */
     public static void disconnect(ChannelSftp channel) {
         if (channel != null) {
@@ -93,152 +93,152 @@ public class SftpUtils {
                 session = channel.getSession();
                 channel.disconnect();
             } catch (Exception e) {
-                logger.warn("关闭SFTP通道时发生异常: {}", e.getMessage());
+                logger.warn("SFTPチャネルを閉じる際に例外が発生: {}", e.getMessage());
             }
             
-            // 断开session连接
+            // セッション接続を切
             if (session != null && session.isConnected()) {
                 try {
                     session.disconnect();
                 } catch (Exception e) {
-                    logger.warn("关闭SFTP会话时发生异常: {}", e.getMessage());
+                    logger.warn("SFTPセッションを閉じる際に例外が発生: {}", e.getMessage());
                 }
             }
             
-            logger.info("SFTP连接已关闭");
+            logger.info("SFTP接続が閉じられました");
         }
     }
     
     /**
-     * 下载SFTP服务器上的文件
+     * SFTPサーバー上のファイルをダウンロード
      * 
-     * @param channel SFTP通道
-     * @param remotePath 远程文件路径
-     * @param localPath 本地保存路径
-     * @return 下载是否成功
+     * @param channel SFTPチャネル
+     * @param remotePath リモートファイルパス
+     * @param localPath ローカル保存パス
+     * @return ダウンロードが成功したかどうか
      */
     public static boolean downloadFile(ChannelSftp channel, String remotePath, String localPath) {
         if (channel == null || !channel.isConnected()) {
-            logger.error("SFTP通道未连接或已断开");
+            logger.error("SFTPチャネルが接続されていないか、切断されています");
             return false;
         }
         
         try (OutputStream outputStream = new FileOutputStream(localPath)) {
             channel.get(remotePath, outputStream);
-            logger.info("文件下载成功 - 远程路径: {}, 本地路径: {}", remotePath, localPath);
+            logger.info("ファイルダウンロード成功 - リモートパス: {}, ローカルパス: {}", remotePath, localPath);
             return true;
         } catch (SftpException | IOException e) {
-            logger.error("文件下载失败 - 远程路径: {}, 本地路径: {}, 错误: {}", 
+            logger.error("ファイルダウンロード失敗 - リモートパス: {}, ローカルパス: {}, エラー: {}", 
                 remotePath, localPath, e.getMessage());
             return false;
         }
     }
     
     /**
-     * 下载SFTP服务器上的文件到字节数组
+     * SFTPサーバー上のファイルをバイト配列としてダウンロード
      * 
-     * @param channel SFTP通道
-     * @param remotePath 远程文件路径
-     * @return 文件内容的字节数组,失败返回null
+     * @param channel SFTPチャネル
+     * @param remotePath リモートファイルパス
+     * @return ファイル内容のバイト配列、失敗した場合はnullを返す
      */
     public static byte[] downloadFileToBytes(ChannelSftp channel, String remotePath) {
         if (channel == null || !channel.isConnected()) {
-            logger.error("SFTP通道未连接或已断开");
+            logger.error("SFTPチャネルが接続されていないか、切断されています");
             return null;
         }
         
         try (InputStream inputStream = channel.get(remotePath)) {
             byte[] fileData = IOUtils.toByteArray(inputStream);
-            logger.info("文件下载到字节数组成功 - 远程路径: {}, 文件大小: {} bytes", 
+            logger.info("ファイルをバイト配列としてダウンロード成功 - リモートパス: {}, ファイルサイズ: {} バイト", 
                 remotePath, fileData.length);
             return fileData;
         } catch (SftpException | IOException e) {
-            logger.error("文件下载到字节数组失败 - 远程路径: {}, 错误: {}", 
+            logger.error("ファイルをバイト配列としてダウンロード失敗 - リモートパス: {}, エラー: {}", 
                 remotePath, e.getMessage());
             return null;
         }
     }
     
     /**
-     * 上传本地文件到SFTP服务器
+     * ファイルをSFTPサーバーにアップロード
      * 
-     * @param channel SFTP通道
-     * @param localPath 本地文件路径
-     * @param remotePath 远程保存路径
-     * @return 上传是否成功
+     * @param channel SFTPチャネル
+     * @param localPath ローカルファイルパス
+     * @param remotePath リモート保存パス
+     * @return アップロードが成功したかどうか
      */
     public static boolean uploadFile(ChannelSftp channel, String localPath, String remotePath) {
         if (channel == null || !channel.isConnected()) {
-            logger.error("SFTP通道未连接或已断开");
+            logger.error("SFTPチャネルが接続されていないか、切断されています");
             return false;
         }
         
         try (InputStream inputStream = new FileInputStream(localPath)) {
-            // 确保远程目录存在
+            // リモートディレクトリが存在することを確認
             createRemoteDirectory(channel, remotePath);
             
             channel.put(inputStream, remotePath);
-            logger.info("文件上传成功 - 本地路径: {}, 远程路径: {}", localPath, remotePath);
+            logger.info("ファイルアップロード成功 - ローカルパス: {}, リモートパス: {}", localPath, remotePath);
             return true;
         } catch (SftpException | IOException e) {
-            logger.error("文件上传失败 - 本地路径: {}, 远程路径: {}, 错误: {}", 
+            logger.error("ファイルアップロード失敗 - ローカルパス: {}, リモートパス: {}, エラー: {}", 
                 localPath, remotePath, e.getMessage());
             return false;
         }
     }
     
     /**
-     * 上传字节数组到SFTP服务器
+     * バイト配列をSFTPサーバーにアップロード
      * 
-     * @param channel SFTP通道
-     * @param fileData 文件数据字节数组
-     * @param remotePath 远程保存路径
-     * @return 上传是否成功
+     * @param channel SFTPチャネル
+     * @param fileData ファイルデータのバイト配列
+     * @param remotePath リモート保存パス
+     * @return アップロードが成功したかどうか
      */
     public static boolean uploadBytesToFile(ChannelSftp channel, byte[] fileData, String remotePath) {
         if (channel == null || !channel.isConnected()) {
-            logger.error("SFTP通道未连接或已断开");
+            logger.error("SFTPチャネルが接続されていないか、切断されています");
             return false;
         }
         
         try (InputStream inputStream = new ByteArrayInputStream(fileData)) {
-            // 确保远程目录存在
+            // リモートディレクトリが存在することを確認
             createRemoteDirectory(channel, remotePath);
             
             channel.put(inputStream, remotePath);
-            logger.info("字节数组上传成功 - 远程路径: {}, 数据大小: {} bytes", 
+            logger.info("バイト配列のアップロード成功 - リモートパス: {}, データサイズ: {} バイト", 
                 remotePath, fileData.length);
             return true;
         } catch (SftpException | IOException e) {
-            logger.error("字节数组上传失败 - 远程路径: {}, 错误: {}", 
+            logger.error("バイト配列のアップロード失敗 - リモートパス: {}, エラー: {}", 
                 remotePath, e.getMessage());
             return false;
         }
     }
     
     /**
-     * 判断SFTP服务器上的文件是否存在
+     * SFTPサーバー上のファイルが存在するか判断
      * 
-     * @param channel SFTP通道
-     * @param remotePath 远程文件路径
-     * @return 文件是否存在
+     * @param channel SFTPチャネル
+     * @param remotePath リモートファイルパス
+     * @return ファイルが存在するかどうか
      */
     public static boolean fileExists(ChannelSftp channel, String remotePath) {
         if (channel == null || !channel.isConnected()) {
-            logger.error("SFTP通道未连接或已断开");
+            logger.error("SFTPチャネルが接続されていないか、切断されています");
             return false;
         }
         
         try {
             channel.lstat(remotePath);
-            logger.debug("文件存在 - 远程路径: {}", remotePath);
+            logger.debug("ファイルが存在します - リモートパス: {}", remotePath);
             return true;
         } catch (SftpException e) {
             if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
-                logger.debug("文件不存在 - 远程路径: {}", remotePath);
+                logger.debug("ファイルが存在しません - リモートパス: {}", remotePath);
                 return false;
             } else {
-                logger.error("检查文件存在性时发生异常 - 远程路径: {}, 错误: {}", 
+                logger.error("ファイルの存在確認中に例外が発生しました - リモートパス: {}, エラー: {}", 
                     remotePath, e.getMessage());
                 return false;
             }
@@ -246,62 +246,62 @@ public class SftpUtils {
     }
     
     /**
-     * 删除SFTP服务器上的文件
+     * SFTPサーバー上のファイルを削除
      * 
-     * @param channel SFTP通道
-     * @param remotePath 远程文件路径
-     * @return 删除是否成功
+     * @param channel SFTPチャネル
+     * @param remotePath リモートファイルパス
+     * @return 削除が成功したかどうか
      */
     public static boolean deleteFile(ChannelSftp channel, String remotePath) {
         if (channel == null || !channel.isConnected()) {
-            logger.error("SFTP通道未连接或已断开");
+            logger.error("SFTPチャネルが接続されていないか、切断されています");
             return false;
         }
         
         try {
             channel.rm(remotePath);
-            logger.info("文件删除成功 - 远程路径: {}", remotePath);
+            logger.info("ファイル削除成功 - リモートパス: {}", remotePath);
             return true;
         } catch (SftpException e) {
-            logger.error("文件删除失败 - 远程路径: {}, 错误: {}", remotePath, e.getMessage());
+            logger.error("ファイル削除失敗 - リモートパス: {}, エラー: {}", remotePath, e.getMessage());
             return false;
         }
     }
     
     /**
-     * 列出SFTP服务器上指定目录的文件
+     * リモートディレクトリ内のファイルをリスト表示
      * 
-     * @param channel SFTP通道
-     * @param remoteDir 远程目录路径
-     * @return 文件列表,失败返回null
+     * @param channel SFTPチャネル
+     * @param remoteDir リモートディレクトリパス
+     * @return ファイルリスト,失敗した場合はnull
      */
     public static Vector<ChannelSftp.LsEntry> listFiles(ChannelSftp channel, String remoteDir) {
         if (channel == null || !channel.isConnected()) {
-            logger.error("SFTP通道未连接或已断开");
+            logger.error("SFTPチャネルが接続されていないか、切断されています");
             return null;
         }
         
         try {
             Vector<ChannelSftp.LsEntry> files = channel.ls(remoteDir);
-            logger.debug("列出文件成功 - 远程目录: {}, 文件数量: {}", remoteDir, files.size());
+            logger.debug("ファイルのリスト表示に成功 - リモートディレクトリ: {}, ファイル数: {}", remoteDir, files.size());
             return files;
         } catch (SftpException e) {
-            logger.error("列出文件失败 - 远程目录: {}, 错误: {}", remoteDir, e.getMessage());
+            logger.error("ファイルのリスト表示に失敗 - リモートディレクトリ: {}, エラー: {}", remoteDir, e.getMessage());
             return null;
         }
     }
     
     /**
-     * 创建远程目录(如果不存在
+     * リモートディレクトリを作成(存在しない場合
      * 
-     * @param channel SFTP通道
-     * @param remotePath 远程路径
+     * @param channel SFTPチャネル
+     * @param remotePath リモートパス
      */
     private static void createRemoteDirectory(ChannelSftp channel, String remotePath) {
         try {
             String directory = remotePath.substring(0, remotePath.lastIndexOf('/'));
             if (!directory.isEmpty()) {
-                // 递归创建目录
+                // 再帰的にディレクトリを作成
                 String[] dirs = directory.split("/");
                 StringBuilder currentPath = new StringBuilder();
                 
@@ -311,7 +311,7 @@ public class SftpUtils {
                         try {
                             channel.mkdir(currentPath.toString());
                         } catch (SftpException e) {
-                            // 目录已存在,忽略异常
+                            // ディレクトリが既に存在する場合、例外を無視
                             if (e.id != ChannelSftp.SSH_FX_FAILURE) {
                                 throw e;
                             }
@@ -320,61 +320,8 @@ public class SftpUtils {
                 }
             }
         } catch (SftpException e) {
-            logger.warn("创建远程目录失败: {}", e.getMessage());
+            logger.warn("リモートディレクトリの作成に失敗: {}", e.getMessage());
         }
     }
     
-    /**
-     * 测试SFTP连接
-     * 
-     * @param host 主机地址
-     * @param port 端口号
-     * @param username 用户名
-     * @param password 密码
-     * @return 连接是否成功
-     */
-    public static boolean testConnection(String host, int port, String username, String password) {
-        ChannelSftp channel = null;
-        try {
-            channel = connect(host, port, username, password);
-            return channel != null && channel.isConnected();
-        } catch (JSchException e) {
-            logger.error("SFTP连接测试失败 - 主机: {}, 端口: {}, 用户: {}, 错误: {}", 
-                host, port, username, e.getMessage());
-            return false;
-        } finally {
-            if (channel != null) {
-                disconnect(channel);
-            }
-        }
-    }
-    
-    /**
-     * 测试SFTP连接(使用默认端口22)
-     * 
-     * @param host 主机地址
-     * @param username 用户名
-     * @param password 密码
-     * @return 连接是否成功
-     */
-    public static boolean testConnection(String host, String username, String password) {
-        return testConnection(host, DEFAULT_SFTP_PORT, username, password);
-    }
-    
-    /**
-     * 主方法 - 测试SFTP功能
-     */
-    public static void main(String[] args) {
-        // 测试连接
-        String host = "sftp.example.com";
-        String username = "testuser";
-        String password = "testpass";
-        
-        boolean connected = testConnection(host, username, password);
-        System.out.println("SFTP连接测试: " + (connected ? "成功" : "失败"));
-        
-        if (connected) {
-            System.out.println("SFTP工具类功能测试完成");
-        }
-    }
 }

+ 76 - 76
farm-quartz/src/main/java/jp/yamoto/farm/quartz/util/ZipUtils.java

@@ -10,7 +10,7 @@ import java.util.List;
 import java.util.zip.*;
 
 /**
- * ZIP文件压缩和解压共通工具类
+ * ZIPファイル圧縮・解凍共通ユーティリティクラス
  * 
  * @author Yamoto Farm
  * @version 1.0
@@ -22,26 +22,26 @@ public class ZipUtils {
     private static final int BUFFER_SIZE = 1024;
     
     /**
-     * 压缩单个文件到ZIP
+     * 単一ファイルをZIPに圧縮
      * 
-     * @param sourceFile 源文件路径
-     * @param zipFile ZIP文件路径
-     * @return 压缩是否成功
+     * @param sourceFile ソースファイルパス
+     * @param zipFile ZIPファイルパス
+     * @return 圧縮成功時はtrueを返す
      */
     public static boolean compressFile(String sourceFile, String zipFile) {
         return compressFiles(new String[]{sourceFile}, zipFile);
     }
     
     /**
-     * 压缩多个文件到ZIP
+     * 複数ファイルをZIPに圧縮
      * 
-     * @param sourceFiles 源文件路径数组
-     * @param zipFile ZIP文件路径
-     * @return 压缩是否成功
+     * @param sourceFiles ソースファイルパス配列
+     * @param zipFile ZIPファイルパス
+     * @return 圧縮成功時はtrueを返す
      */
     public static boolean compressFiles(String[] sourceFiles, String zipFile) {
         if (sourceFiles == null || sourceFiles.length == 0) {
-            logger.error("源文件列表为空");
+            logger.error("ソースファイルリストが空です");
             return false;
         }
         
@@ -51,29 +51,29 @@ public class ZipUtils {
             for (String sourceFile : sourceFiles) {
                 File file = new File(sourceFile);
                 if (!file.exists()) {
-                    logger.warn("文件不存在: {}", sourceFile);
+                    logger.warn("ファイルが存在しません: {}", sourceFile);
                     continue;
                 }
                 
                 addFileToZip(file, file.getName(), zos);
             }
             
-            logger.info("文件压缩成功 - ZIP文件: {}, 压缩文件数: {}", 
+            logger.info("ファイル圧縮成功 - ZIPファイル: {}, 圧縮ファイル数: {}", 
                 zipFile, sourceFiles.length);
             return true;
             
         } catch (IOException e) {
-            logger.error("文件压缩失败 - ZIP文件: {}, 错误: {}", zipFile, e.getMessage());
+            logger.error("ファイル圧縮失敗 - ZIPファイル: {}, エラー: {}", zipFile, e.getMessage());
             return false;
         }
     }
     
     /**
-     * 压缩目录到ZIP
+     * ディレクトリ全体をZIPに圧縮
      * 
-     * @param sourceDir 源目录路径
-     * @param zipFile ZIP文件路径
-     * @return 压缩是否成功
+     * @param sourceDir ソースディレクトリパス
+     * @param zipFile ZIPファイルパス
+     * @return 圧縮成功時はtrueを返す
      */
     public static boolean compressDirectory(String sourceDir, String zipFile) {
         return compressDirectory(sourceDir, zipFile, true);
@@ -90,7 +90,7 @@ public class ZipUtils {
     public static boolean compressDirectory(String sourceDir, String zipFile, boolean includeSubdirs) {
         File dir = new File(sourceDir);
         if (!dir.exists() || !dir.isDirectory()) {
-            logger.error("目录不存在或不是目录: {}", sourceDir);
+            logger.error("ディレクトリが存在しないか、ディレクトリではありません: {}", sourceDir);
             return false;
         }
         
@@ -99,39 +99,39 @@ public class ZipUtils {
             
             int fileCount = addDirectoryToZip(dir, dir.getName(), zos, includeSubdirs);
             
-            logger.info("目录压缩成功 - ZIP文件: {}, 源目录: {}, 压缩文件数: {}", 
+            logger.info("ディレクトリ圧縮成功 - ZIPファイル: {}, ソースディレクトリ: {}, 圧縮ファイル数: {}", 
                 zipFile, sourceDir, fileCount);
             return true;
             
         } catch (IOException e) {
-            logger.error("目录压缩失败 - ZIP文件: {}, 错误: {}", zipFile, e.getMessage());
+            logger.error("ディレクトリ圧縮失敗 - ZIPファイル: {}, エラー: {}", zipFile, e.getMessage());
             return false;
         }
     }
     
     /**
-     * 解压ZIP文件到指定目录
+     * ZIPファイルを指定ディレクトリに解凍
      * 
-     * @param zipFile ZIP文件路径
-     * @param destDir 目标目录路径
-     * @return 解压是否成功
+     * @param zipFile ZIPファイルパス
+     * @param destDir ターゲットディレクトリパス
+     * @return 解凍成功時はtrueを返す
      */
     public static boolean decompress(String zipFile, String destDir) {
         return decompress(zipFile, destDir, true);
     }
     
     /**
-     * 解压ZIP文件到指定目录
+     * ZIPファイルを指定ディレクトリに解凍
      * 
-     * @param zipFile ZIP文件路径
-     * @param destDir 目标目录路径
-     * @param overwriteExisting 是否覆盖已存在的文件
-     * @return 解压是否成功
+     * @param zipFile ZIPファイルパス
+     * @param destDir ターゲットディレクトリパス
+     * @param overwriteExisting 既存ファイルを上書きするかどうか
+     * @return 解凍成功時はtrueを返す
      */
     public static boolean decompress(String zipFile, String destDir, boolean overwriteExisting) {
         File zip = new File(zipFile);
         if (!zip.exists()) {
-            logger.error("ZIP文件不存在: {}", zipFile);
+            logger.error("ZIPファイルが存在しません: {}", zipFile);
             return false;
         }
         
@@ -157,13 +157,13 @@ public class ZipUtils {
                     continue;
                 }
                 
-                // 检查文件是否已存在
+                // ファイルが既に存在するかチェック
                 if (entryFile.exists() && !overwriteExisting) {
-                    logger.debug("跳过已存在的文件: {}", entryName);
+                    logger.debug("既存ファイルをスキップ: {}", entryName);
                     continue;
                 }
                 
-                // 确保父目录存在
+                // 親ディレクトリが存在することを確認
                 File parentDir = entryFile.getParentFile();
                 if (!parentDir.exists()) {
                     parentDir.mkdirs();
@@ -181,26 +181,26 @@ public class ZipUtils {
                 zis.closeEntry();
             }
             
-            logger.info("ZIP文件解压成功 - ZIP文件: {}, 目标目录: {}, 解压文件数: {}", 
+            logger.info("ZIPファイル解凍成功 - ZIPファイル: {}, ターゲットディレクトリ: {}, 解凍ファイル数: {}", 
                 zipFile, destDir, fileCount);
             return true;
             
         } catch (IOException e) {
-            logger.error("ZIP文件解压失败 - ZIP文件: {}, 错误: {}", zipFile, e.getMessage());
+            logger.error("ZIPファイル解凍失敗 - ZIPファイル: {}, エラー: {}", zipFile, e.getMessage());
             return false;
         }
     }
     
     /**
-     * 获取ZIP文件中的文件列表
+     * ZIPファイル内のファイルリストを取得
      * 
-     * @param zipFile ZIP文件路径
-     * @return 文件列表,失败返回null
+     * @param zipFile ZIPファイルパス
+     * @return ファイルリスト、失敗時はnullを返す
      */
     public static List<String> listZipEntries(String zipFile) {
         File zip = new File(zipFile);
         if (!zip.exists()) {
-            logger.error("ZIP文件不存在: {}", zipFile);
+            logger.error("ZIPファイルが存在しません: {}", zipFile);
             return null;
         }
         
@@ -214,28 +214,28 @@ public class ZipUtils {
                 zis.closeEntry();
             }
             
-            logger.debug("获取ZIP文件列表成功 - ZIP文件: {}, 文件数: {}", 
+            logger.debug("ZIPファイルリスト取得成功 - ZIPファイル: {}, ファイル数: {}", 
                 zipFile, entries.size());
             return entries;
             
         } catch (IOException e) {
-            logger.error("获取ZIP文件列表失败 - ZIP文件: {}, 错误: {}", zipFile, e.getMessage());
+            logger.error("ZIPファイルリスト取得失敗 - ZIPファイル: {}, エラー: {}", zipFile, e.getMessage());
             return null;
         }
     }
     
     /**
-     * 从ZIP文件中提取单个文件
+     * ZIPファイルから単一ファイルを抽出
      * 
-     * @param zipFile ZIP文件路径
-     * @param entryName ZIP中的文件路径
-     * @param destFile 目标文件路径
-     * @return 提取是否成功
+     * @param zipFile ZIPファイルパス
+     * @param entryName ZIP内のファイルパス
+     * @param destFile ターゲットファイルパス
+     * @return 抽出成功時はtrueを返す
      */
     public static boolean extractSingleFile(String zipFile, String entryName, String destFile) {
         File zip = new File(zipFile);
         if (!zip.exists()) {
-            logger.error("ZIP文件不存在: {}", zipFile);
+            logger.error("ZIPファイルが存在しません: {}", zipFile);
             return false;
         }
         
@@ -260,27 +260,27 @@ public class ZipUtils {
                         }
                     }
                     
-                    logger.info("提取文件成功 - ZIP文件: {}, 源文件: {}, 目标文件: {}", 
+                    logger.info("ファイル抽出成功 - ZIPファイル: {}, ソースファイル: {}, ターゲットファイル: {}", 
                         zipFile, entryName, destFile);
                     return true;
                 }
                 zis.closeEntry();
             }
             
-            logger.error("ZIP文件中未找到指定文件: {}", entryName);
+            logger.error("ZIPファイル内に指定ファイルが見つかりません: {}", entryName);
             return false;
             
         } catch (IOException e) {
-            logger.error("提取文件失败 - ZIP文件: {}, 错误: {}", zipFile, e.getMessage());
+            logger.error("ファイル抽出失敗 - ZIPファイル: {}, エラー: {}", zipFile, e.getMessage());
             return false;
         }
     }
     
     /**
-     * 检查ZIP文件是否有效
+     * ZIPファイルが有効かどうかをチェック
      * 
-     * @param zipFile ZIP文件路径
-     * @return 是否有效ZIP文件
+     * @param zipFile ZIPファイルパス
+     * @return 有効なZIPファイルの場合はtrueを返す
      */
     public static boolean isValidZipFile(String zipFile) {
         File zip = new File(zipFile);
@@ -291,34 +291,34 @@ public class ZipUtils {
         try (FileInputStream fis = new FileInputStream(zip);
              ZipInputStream zis = new ZipInputStream(fis)) {
             
-            // 尝试读取第一个条目
+            // 最初のエントリを読み込む
             ZipEntry entry = zis.getNextEntry();
             return true;
             
         } catch (ZipException e) {
-            logger.debug("无效的ZIP文件: {}, 错误: {}", zipFile, e.getMessage());
+            logger.debug("無効なZIPファイル: {}, エラー: {}", zipFile, e.getMessage());
             return false;
         } catch (IOException e) {
-            logger.debug("检查ZIP文件时发生异常: {}, 错误: {}", zipFile, e.getMessage());
+            logger.debug("ZIPファイルチェック中に例外が発生: {}, エラー: {}", zipFile, e.getMessage());
             return false;
         }
     }
     
-    // ========== 私有辅助方法 ==========
+    // ========== プライベートヘルパーメソッド ==========
     
     /**
-     * 添加文件到ZIP输出流
+     * ファイルをZIP出力ストリームに追加
      */
     private static void addFileToZip(File file, String entryName, ZipOutputStream zos) throws IOException {
         if (file.isDirectory()) {
-            // 添加目录条目
+            // ディレクトリエントリを追加
             if (!entryName.endsWith("/")) {
                 entryName += "/";
             }
             zos.putNextEntry(new ZipEntry(entryName));
             zos.closeEntry();
         } else {
-            // 添加文件条目
+            // ファイルエントリを追加
             zos.putNextEntry(new ZipEntry(entryName));
             
             try (FileInputStream fis = new FileInputStream(file)) {
@@ -334,7 +334,7 @@ public class ZipUtils {
     }
     
     /**
-     * 递归添加目录到ZIP输出流
+     * ディレクトリを再帰的にZIP出力ストリームに追加
      */
     private static int addDirectoryToZip(File dir, String basePath, ZipOutputStream zos, boolean includeSubdirs) throws IOException {
         int fileCount = 0;
@@ -348,7 +348,7 @@ public class ZipUtils {
                     addFileToZip(file, entryName, zos);
                     fileCount++;
                 } else if (file.isDirectory() && includeSubdirs) {
-                    // 递归处理子目录
+                    // サブディレクトリを再帰的に処理
                     addFileToZip(file, entryName + "/", zos);
                     fileCount += addDirectoryToZip(file, entryName, zos, includeSubdirs);
                 }
@@ -359,47 +359,47 @@ public class ZipUtils {
     }
     
     /**
-     * 主方法 - 测试ZIP功能
+     * メインメソッド - ZIP機能をテスト
      */
     public static void main(String[] args) {
-        // 测试压缩功能
+        // 圧縮機能をテスト
         String testDir = "test_dir";
         String zipFile = "test.zip";
         
-        // 创建测试目录和文件
+        // テストディレクトリとファイルを作成
         File dir = new File(testDir);
         dir.mkdirs();
         
         try {
-            // 创建测试文件
+            // テストファイルを作成
             File testFile1 = new File(testDir + "/test1.txt");
             File testFile2 = new File(testDir + "/test2.txt");
             
             try (FileWriter fw1 = new FileWriter(testFile1);
                  FileWriter fw2 = new FileWriter(testFile2)) {
-                fw1.write("这是测试文件1");
-                fw2.write("这是测试文件2");
+                fw1.write("これはテストファイル1です");
+                fw2.write("これはテストファイル2です");
             }
             
-            // 测试目录压缩
+            // ディレクトリ圧縮をテスト
             boolean compressResult = compressDirectory(testDir, zipFile);
-            System.out.println("目录压缩测试: " + (compressResult ? "成功" : "失败"));
+            System.out.println("ディレクトリ圧縮テスト: " + (compressResult ? "成功" : "失敗"));
             
-            // 测试解压
+            // 解凍をテスト
             String extractDir = "extracted_dir";
             boolean decompressResult = decompress(zipFile, extractDir);
-            System.out.println("文件解压测试: " + (decompressResult ? "成功" : "失败"));
+            System.out.println("ファイル解凍テスト: " + (decompressResult ? "成功" : "失敗"));
             
-            // 测试文件列表
+            // ファイルリストをテスト
             List<String> entries = listZipEntries(zipFile);
             if (entries != null) {
-                System.out.println("ZIP文件内容:");
+                System.out.println("ZIPファイル内容:");
                 for (String entry : entries) {
                     System.out.println("  - " + entry);
                 }
             }
             
-            // 清理测试文件
+            // テストファイルをクリーンアップ
             testFile1.delete();
             testFile2.delete();
             dir.delete();
@@ -407,7 +407,7 @@ public class ZipUtils {
             new File(extractDir).delete();
             
         } catch (IOException e) {
-            System.err.println("测试过程中发生错误: " + e.getMessage());
+            System.err.println("テスト中にエラーが発生しました: " + e.getMessage());
         }
     }
 }

+ 14 - 14
farm-quartz/src/main/resources/application-aws.yml

@@ -1,32 +1,32 @@
-# AWS相关配置
+# AWS関連設定
 aws:
   s3:
-    # AWS访问密钥ID (LocalStack使用任意值)
+    # AWSアクセスキーID (LocalStackでは任意の値を使用)
     access-key: ${AWS_ACCESS_KEY_ID:test}
-    # AWS秘密访问密钥 (LocalStack使用任意值)
+    # AWSシークレットアクセスキー (LocalStackでは任意の値を使用)
     secret-key: ${AWS_SECRET_ACCESS_KEY:test}
-    # AWS区域
+    # AWSリージョン
     region: ${AWS_REGION:us-east-1}
-    # 存储桶名称
+    # バケット名
     bucket-name: ${AWS_S3_BUCKET:my-unencrypted-bucket}
-    # 文件存储路径前缀
+    # ファイル保存パスプレフィックス
     path-prefix: ${AWS_S3_PATH_PREFIX:uploads/}
-    # 文件访问URL前缀 (用于生成文件访问链接)
+    # ファイルアクセスURLプレフィックス (ファイルアクセスリンク生成用)
     url-prefix: ${AWS_S3_URL_PREFIX:http://172.14.3.142:4566/my-unencrypted-bucket/}
-    # LocalStack端点URL
+    # LocalStackエンドポイントURL
     endpoint-url: ${AWS_S3_ENDPOINT_URL:http://172.14.3.142:4566}
   ses:
-    # AWS访问密钥ID
+    # AWSアクセスキーID
     access-key: ${AWS_SES_ACCESS_KEY:test}
-    # AWS秘密访问密钥
+    # AWSシークレットアクセスキー
     secret-key: ${AWS_SES_SECRET_KEY:test}
-    # AWS区域
+    # AWSリージョン
     region: ${AWS_SES_REGION:us-east-1}
-    # 发件人邮箱 (LocalStack中任意邮箱都可用)
+    # 送信者メールアドレス (LocalStackでは任意のメールアドレスが使用可能)
     from-email: ${AWS_SES_FROM_EMAIL:sender@nextosd.com}
-    # 邮件编码
+    # メールエンコーディング
     charset: ${AWS_SES_CHARSET:UTF-8}
-    # LocalStack端点URL
+    # LocalStackエンドポイントURL
     endpoint-url: ${AWS_SES_ENDPOINT_URL:http://172.14.3.142:4566}