quyx@nextosd.com 5 months ago
parent
commit
dc5a30cdce

+ 1 - 1
yamato-bbib/src/main/java/com/yamato/bbib/controller/TBaseOrderController.java

@@ -51,7 +51,7 @@ public class TBaseOrderController extends BaseController
     {
         List<TBaseOrder> list = tBaseOrderService.selectCsvList(tBaseOrder);
         ExcelUtil<TBaseOrder> util = new ExcelUtil<TBaseOrder>(TBaseOrder.class);
-        util.exportExcel(response, list, "発注数据");
+        util.exportCsv(response, list, "発注数据");
     }
 
 

+ 2 - 0
yamato-common/src/main/java/com/yamato/common/annotation/Excel.java

@@ -201,6 +201,8 @@ public @interface Excel {
      */
     public InputValueType inputValueType() default InputValueType.NONE;
 
+    int order() default 0;
+
     /**
      * フィールドタイプ
      */

+ 3 - 0
yamato-common/src/main/java/com/yamato/common/exception/ServiceException.java

@@ -39,6 +39,9 @@ public final class ServiceException extends RuntimeException {
         this.code = code;
     }
 
+    public ServiceException(String message, Exception e) {
+    }
+
     public String getDetailMessage() {
         return detailMessage;
     }

+ 101 - 0
yamato-common/src/main/java/com/yamato/common/utils/poi/ExcelUtil.java

@@ -7,6 +7,7 @@ import com.yamato.common.annotation.Excels;
 import com.yamato.common.config.AppConfig;
 import com.yamato.common.core.domain.AjaxResult;
 import com.yamato.common.core.text.Convert;
+import com.yamato.common.exception.ServiceException;
 import com.yamato.common.exception.UtilException;
 import com.yamato.common.utils.*;
 import com.yamato.common.utils.file.FileTypeUtils;
@@ -36,7 +37,10 @@ import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.*;
@@ -1872,4 +1876,101 @@ public class ExcelUtil<T> {
         return method;
     }
 
+    /**
+     * オブジェクトリストをCSVファイルとしてHTTPレスポンスに出力します。
+     * UTF-8 BOMを付与することで、Excel等のソフトウェアでの文字化けを防止します。
+     *
+     * @param response HTTPレスポンスオブジェクト
+     * @param list エクスポート対象のオブジェクトリスト
+     * @param fileName 出力ファイル名(拡張子不要)
+     * @param <T> オブジェクトの型
+     */
+    public static <T> void exportCsv(HttpServletResponse response, List<T> list, String fileName) {
+        try (OutputStream out = response.getOutputStream()) {
+            // レスポンスヘッダー設定:バイナリファイルとしてダウンロードさせる
+            response.setContentType("application/octet-stream");
+            response.setHeader("Content-Disposition", "attachment; filename=" +
+                    URLEncoder.encode(fileName, "UTF-8") + ".csv");
+
+            // UTF-8 BOM(Byte Order Mark)を出力してExcelでの文字化けを防止
+            out.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
+
+            // UTF-8で文字を出力するライターを作成
+            OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
+
+            // ヘッダー行を出力(データがある場合のみ)
+            if (!list.isEmpty()) {
+                writer.write(createCsvHeader(list.get(0)) + "\n");
+            }
+
+            // データ行を順次出力
+            for (T obj : list) {
+                writer.write(createCsvRow(obj) + "\n");
+            }
+
+            // バッファ内容をフラッシュして出力を確定
+            writer.flush();
+        } catch (Exception e) {
+            // 例外発生時はカスタム例外をスロー
+            throw new ServiceException("CSVエクスポートに失敗しました", e);
+        }
+    }
+
+    /**
+     * オブジェクトのフィールドに付与された@Excelアノテーションのname属性を元に
+     * CSVのヘッダー行を生成します。
+     * アノテーションのorder属性で指定された順序でヘッダーを並べます。
+     *
+     * @param obj オブジェクトのインスタンス
+     * @param <T> オブジェクトの型
+     * @return CSVヘッダー行の文字列
+     */
+    private static <T> String createCsvHeader(T obj) {
+        return Arrays.stream(obj.getClass().getDeclaredFields())
+                .filter(f -> f.isAnnotationPresent(Excel.class))
+                .sorted(Comparator.comparingInt(f -> f.getAnnotation(Excel.class).order()))
+                .map(f -> f.getAnnotation(Excel.class).name())
+                .collect(Collectors.joining(","));
+    }
+
+    /**
+     * 日付形式をフォーマットするための共通フォーマッタ
+     * yyyy-MM-dd形式で日付を表現します。
+     */
+    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+
+    /**
+     * オブジェクトのフィールド値を元にCSVのデータ行を生成します。
+     * order属性で指定された順序で値を並べます。
+     * 日付型のフィールドはDATE_FORMATで指定された形式に変換されます。
+     *
+     * @param obj オブジェクトのインスタンス
+     * @param <T> オブジェクトの型
+     * @return CSVデータ行の文字列
+     */
+    private static <T> String createCsvRow(T obj) {
+        return Arrays.stream(obj.getClass().getDeclaredFields())
+                .filter(f -> f.isAnnotationPresent(Excel.class))
+                .sorted(Comparator.comparingInt(f -> f.getAnnotation(Excel.class).order()))
+                .map(f -> {
+                    try {
+                        // アクセス権限を設定してprivateフィールドの値も取得可能にする
+                        f.setAccessible(true);
+                        Object value = f.get(obj);
+
+                        // 日付型のフィールドは指定されたフォーマットに変換
+                        if (value instanceof Date) {
+                            return DATE_FORMAT.format(value);
+                        }
+
+                        // nullの場合は空文字列に変換
+                        return StringUtils.defaultIfEmpty(String.valueOf(value), "");
+                    } catch (Exception e) {
+                        // 値取得に失敗した場合は空文字列を返す
+                        return "";
+                    }
+                })
+                .collect(Collectors.joining(","));
+    }
+
 }