• トップ
  • ブログ一覧
  • 【Java】スプレッドシートの表をHTML化する
  • 【Java】スプレッドシートの表をHTML化する

    かじー(エンジニア)かじー(エンジニア)
    2024.01.23

    IT技術

    概要

    Googleスプレッドシートに記載されている表をHTMLとして生成することができるツールの開発について記事にしました。

    前提

    言語はJavaです。そしてスプレッドシートの内容を読み込み、JavaクラスにマッピングするツールとしてXlsMapperというライブラリを使用します。詳細な前提条件はリンク先に記載あるのでそちらを確認してください。

    [完成イメージ]

    スプレッドシート

    HTML

    ちなみにプロジェクトのディレクトリ構成は以下になります。

    解説

    スプレッドシートの内容をJavaに読み込ませるには手元のPCにxlsxファイルをダウンロードしてくる必要があります。今回は以下のようなスプレッドシートをsample.xlsxとして"com.sample"直下に配置します。

    そしてsample.xlsxからデータを読み込み、取得したデータを元にHTMLを生成するメインの処理を記述したコードが以下になります。(packageやimportの記載は省略)

    SampleConverter.java

    1public class SampleConverter {
    2  public static void main(String[] args) {
    3    var xlsMapper = new XlsMapper();
    4
    5    // 配置したSample.xlsxからデータを取得
    6    try {
    7      var sheet = xlsMapper.load(
    8        new FileInputStream("src/main/java/com/sample/sample.xlsx"),
    9        SampleSheet.class
    10      );
    11      // 取得したデータをもとにhtmlを生成
    12      convertToHtml(sheet);
    13    } catch (IOException e) {
    14      throw new RuntimeException(e);
    15    }
    16  }
    17
    18  /*
    19   * Excelから取得したデータを元にHTMLを生成
    20   *
    21   * @param sheet sample.xlsxから取得したデータ
    22   */
    23  private static void convertToHtml(SampleSheet sheet) {
    24
    25    // テンプレートエンジンの初期化
    26    var engine = initializeTemplateEngine();
    27
    28    // テンプレートに渡すコンテキストを作成
    29    var context = new Context();
    30
    31    // 表データを1行分ずつ格納したリストを作成
    32    var recordList = new ArrayList<LinkedHashMap>();
    33    for (SampleRecord record : sheet.getRecords()) {
    34      createRecordList(recordList, record);
    35    }
    36
    37    // 表データをcontextに設定
    38    context.setVariable("recordList", recordList);
    39
    40    // templateからhtmlを生成
    41    try {
    42      var writer = new FileWriter("result/sample.html");
    43      engine.process("sample-template", context, writer);
    44    } catch (IOException e) {
    45      throw new RuntimeException(e);
    46    }
    47  }
    48
    49  /**
    50   * テンプレートエンジンを初期化
    51   *
    52   * @return テンプレートエンジン
    53   */
    54  private static TemplateEngine initializeTemplateEngine() {
    55    var templateEngine = new TemplateEngine();
    56    var resolver = new ClassLoaderTemplateResolver();
    57    resolver.setTemplateMode("HTML");
    58    resolver.setSuffix(".html");
    59    templateEngine.setTemplateResolver(resolver);
    60    return templateEngine;
    61  }
    62
    63  /**
    64   * 1行ごとの表データを格納したリストを作成
    65   *
    66   * @param recordList 1行ごとの表データを格納するリスト
    67   * @param record 1行分の表データ
    68   * @return 1行ごとの表データを格納したリスト
    69   */
    70  private static void createRecordList(
    71    ArrayList<LinkedHashMap> recordList, SampleRecord record) {
    72    var columnDataMap = new LinkedHashMap();
    73
    74    // SampleRecordクラスのフィールド情報を取得
    75    var fields = record.getClass().getDeclaredFields();
    76
    77    // 各フィールド名と値の組み合わせをMapにつめる
    78    for (Field field : fields) {
    79      field.setAccessible(true);
    80      try {
    81        columnDataMap.put(field.getName(), field.get(record));
    82      } catch (IllegalAccessException e) {
    83        throw new RuntimeException(e);
    84      }
    85    }
    86    // 作成したMapをListにつめる
    87    recordList.add(columnDataMap);
    88  }
    89}

    SampleSheet.java

    1@XlsSheet(name = "sample")
    2@Data
    3public class SampleSheet {
    4  @XlsHorizontalRecords(headerAddress = "A1")
    5  List records;
    6}

    見慣れないアノテーションが2つありますね。
    @XlsSheetはxlsxファイルの指定されたシートを読み込んでJavaクラスにマッピングしてくれます。今回はsampleシートを読み込むため、nameプロパティの値がsampleとなっています。

    もう一つの@XlsHorizontalRecordsは水平方向に連続する行をCollection(List, Map等)にマッピングしてくれます。ヘッダーが横並びの表をマッピングしたい場合にこのアノテーションを使用します。(他の表形式に対応するアノテーションもあるのでドキュメントを参照してみてください)

    SampleRecord.java

    1@Data
    2public class SampleRecord {
    3  @XlsColumn(columnName = "ID")
    4  private int id;
    5
    6  @XlsColumn(columnName = "Name")
    7  private String name;
    8
    9  @XlsColumn(columnName = "Age")
    10  private int age;
    11
    12  @XlsColumn(columnName = "Gender")
    13  private String gender;
    14}

    このクラスでもxlsMapperのアノテーションが使用されています。@XlsColumnはcolumnName属性で指定したカラム名に紐づくセルの値をフィールドにマッピングしてくれます。

    以下の図でいうとcolumnName属性にカラム名である"ID" を指定するとidフィールドに数字の1がマッピングされます。

    ここまでスプレッドシートから取得したデータを加工しhtmlファイルにレコード情報を渡す準備ができました。最後にデータの渡し先になるsample-template.htmlの内容が以下になります。

    1<!DOCTYPE html>
    2<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    3<head>
    4    <meta charset="UTF-8" />
    5    <title>Sample</title>
    6    <style>
    7        table {
    8            border-collapse: collapse;
    9        }
    10        th, td {
    11            border: 1px solid #dddddd;
    12            text-align: left;
    13            padding: 8px;
    14        }
    15        th {
    16            text-align: center;
    17            background-color: #f2f2f2;
    18        }
    19    </style>
    20</head>
    21<body>
    22<div>
    23    <table>
    24        <thead>
    25            <tr>
    26                <th>ID</th>
    27                <th>Name</th>
    28                <th>Age</th>
    29                <th>Gender</th>
    30            </tr>
    31        </thead>
    32        <tbody>
    33            <tr th:each="record: ${recordList}">
    34                <td th:each="cell, iterStat : ${record}" th:text="${cell.value}"></td>
    35            </tr>
    36        </tbody>
    37    </table>
    38</div>
    39</body>
    40</html>

    Java側からデータを受け取って繰り返し処理をするため、Thymeleafを使用しています。

    必要なコードは以上になります。あとはSampleConverter.javaのmainメソッドを実行するとresultディレクトリ配下にsample.htmlが生成されます。

    かじー(エンジニア)

    かじー(エンジニア)

    おすすめ記事