|
|
@@ -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(","));
|
|
|
+ }
|
|
|
+
|
|
|
}
|