Spring BootでJasperReportsを使ってPDFを返却するAPIを作る方法

Spring Bootアプリケーションに JasperReports を組み合わせると、データを元にしたレポートを簡単に PDF や XML などの形式で出力できます。本記事では、商品価格の一覧を PDF として返却する REST API を作成する方法を解説します。JasperReports はプリンタや画面だけでなく、PDF、XLS、RTF、CSV、XML、HTML、ODT など多様な形式に出力できる Java 製のレポーティングツールで、Spring Boot と組み合わせることでダウンロード可能なレポート API を構築できます。


1. 概要

  • 目的:商品価格一覧を PDF として返却する REST API を Spring Boot で構築する。
  • 使用するツール/ライブラリ
  • Spring Boot
  • JasperReports ライブラリ
  • Jaspersoft Studio(レポートテンプレート作成用)
  • アウトプット/item-price-report/pdf などのエンドポイントにアクセスすると、商品名と価格を一覧にした PDF ファイルがダウンロードされます。

2. JasperReports の準備

2.1 依存関係の追加

Maven プロジェクトの場合、pom.xml に以下を追加します。最新バージョンは Maven Central で確認してください。Spring のロギング機構を利用するため、commons‑logging を除外しています。

<dependency>
  <groupId>net.sf.jasperreports</groupId>
  <artifactId>jasperreports</artifactId>
  <version>6.20.5</version>
  <exclusions>
    <exclusion>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
    </exclusion>
  </exclusions>
</dependency>

2.2 テンプレート(JRXML)の作成

  1. Jaspersoft Studio(または iReport)をインストールして起動します。テンプレートは .jrxml 拡張子の XML ファイルで、Jaspersoft Studio で自由に設計できます。JasperReports はテンプレートをもとにデータをバインドしてレポートを生成します。レポートテンプレートの作成はこの記事の範囲外ですが、Jaspersoft Studio を使用して作成するのが一般的です。
  2. 今回は「商品名」と「価格」の 2 列を持つ簡単なテーブルを作成し、タイトルやサブタイトルも追加します。作成後、ファイルを src/main/resources/reports/item-price-report.jrxml としてプロジェクトに保存します。

テンプレート設計時に以下のポイントを意識すると実装がスムーズです。

  • フィールド定義$F{name}$F{price} など、データソースの Java Bean のプロパティ名と一致させます。
  • パラメータ:レポートタイトルなど動的に変更したい値は $P{title} のようにパラメータとして定義し、プログラム側から Map で渡します。
  • レイアウト:用紙サイズやマージン、列幅などを指定できます。サンプルの item-report.jrxml では report タイトルと item 列を定義しています。

3. サービス実装

以下に示す JasperReportService クラスは、JRXML テンプレートを読み込み、商品データを埋め込み、PDF バイト配列を返すサービスです。

3.1 テンプレートをコンパイルする

JasperReports は JRXML ファイルを コンパイル して JasperReport インスタンスに変換する必要があります。通常は起動時または初回リクエスト時にコンパイルし、パフォーマンスを向上させるために .jasper ファイルとして保存して再利用します。Spring の ResourceUtils を使うと classpath からテンプレートを読み込めます。コンパイル後は JRSaver.saveObject() で保存し、次回以降は JRLoader.loadObject() で読み込みます。

@Service
public class JasperReportService {
    public byte[] generateItemPriceReport(List<Product> products) throws JRException, IOException {
        // 既にコンパイル済みのレポートがあれば再利用
        JasperReport jasperReport;
        File compiledFile = ResourceUtils.getFile("classpath:reports/item-price-report.jasper");
        if (compiledFile.exists()) {
            jasperReport = (JasperReport) JRLoader.loadObject(compiledFile);
        } else {
            // JRXML を読み込みコンパイル
            File file = ResourceUtils.getFile("classpath:reports/item-price-report.jrxml");
            jasperReport = JasperCompileManager.compileReport(file.getAbsolutePath());
            // コンパイル済みファイルを保存
            JRSaver.saveObject(jasperReport, compiledFile.getAbsolutePath());
        }

        // パラメータ設定(レポートタイトルなど)
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("title", "商品価格一覧");

        // データソース設定:JRBeanCollectionDataSource に Java のリストを渡す
        JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(products);

        // レポートを埋め込み
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);

        // PDF にエクスポート
        return JasperExportManager.exportReportToPdf(jasperPrint);
    }
}

上記コードでは、商品を表す Product エンティティのリストを JRBeanCollectionDataSource に渡し、テンプレート内で $F{name}$F{price} として参照できるようにしています。JasperFillManager.fillReport() はテンプレート、パラメータ、データソースを受け取り、埋め込み済みレポート (JasperPrint) を生成します。最終的に JasperExportManager.exportReportToPdf() を呼び出して PDF 形式のバイト配列に変換します。

ポイント:レポート生成は CPU・I/O 負荷の高い処理になりやすいので、必要に応じてジョブ化やキャッシュ、非同期処理を検討してください。

3.2 エンティティとリポジトリの例

以下は簡単な Product エンティティと Spring Data JPA リポジトリの例です。実際にはデータベース設計に応じてフィールドや型を変更してください。

@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private BigDecimal price;

    // getters and setters
}

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {}

4. コントローラ実装

Spring MVC の @RestController を使って PDF を返却するエンドポイントを定義します。生成された PDF バイト配列を ResponseEntity<byte[]> に包み、HTTP ヘッダーで Content-Type や Content-Disposition を設定します。

@RestController
@RequestMapping("/item-price-report")
public class ReportController {
    private final ProductRepository productRepository;
    private final JasperReportService jasperReportService;

    public ReportController(ProductRepository productRepository, JasperReportService jasperReportService) {
        this.productRepository = productRepository;
        this.jasperReportService = jasperReportService;
    }

    @GetMapping("/pdf")
    public ResponseEntity<byte[]> exportPdf() throws JRException, IOException {
        // 商品データを取得(例ではすべて取得)
        List<Product> products = productRepository.findAll();
        byte[] pdfBytes = jasperReportService.generateItemPriceReport(products);

        // HTTP レスポンスの設定
        return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_TYPE, "application/pdf; charset=UTF-8")
            // ダウンロード時のファイル名を指定
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=item-price-report.pdf")
            .body(pdfBytes);
    }
}

上記のように、GET /item-price-report/pdf へアクセスすると Spring Boot が自動的に PDF ファイルをダウンロードさせます。レスポンスヘッダー Content-Disposition: attachmentinline に変更すると、ブラウザで直接表示させることも可能です。

5. 動作確認

  1. Spring Boot アプリケーションを起動します。
  2. ブラウザまたは Postman から http://localhost:8080/item-price-report/pdf にアクセスします。データが存在すれば、商品名と価格を一覧にした PDF がダウンロードされるはずです。
  3. JRXML テンプレートを変更するとレポートのレイアウトや項目が変わるので、必要に応じてカラムを追加・削除してください。

6. まとめ

  • JasperReports は Java アプリケーションから PDF などのレポートを生成できるライブラリで、Spring Boot と組み合わせることで REST API からレポートをダウンロードする機能が簡単に実現できます。
  • テンプレート (.jrxml) は Jaspersoft Studio などでデザインし、JasperCompileManager.compileReport() でコンパイルして使用します。
  • JRBeanCollectionDataSource を使うと Java のリストをデータソースとして簡単に利用できます。
  • レポート生成は重い処理になる場合があるので、ジョブ化やキャッシュ、非同期処理を検討するとスケーラビリティが向上します。

この手順に従えば、商品価格一覧や他のドメインに応用した PDF 出力 API を簡単に実装できます。必要に応じてレポート形式(HTML、Excel など)を切り替えたい場合は、JasperExportManager.exportReportToXml()JasperExportManager.exportReportToHtmlFile() などのメソッドを利用してください。

是非フォローしてください

最新の情報をお伝えします

類似投稿