5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

JasperReportsでExcelを作成する

Last updated at Posted at 2022-08-17

背景

  • JasperReportsでPDFを作成する記事は結構あるけどExcelに関する記事は少なかったので
  • JasperReports自体はJavaで動作する帳票出力ライブラリ。昔からあるライブラリで日本語の情報も豊富。

環境

  • Java 11
  • jasperreports 6.19.1
  • Gradle 7.4.2

実装

下準備

  • 関連ライブラリを入れておく
build.gradle
plugins {
    id 'java'
}

group = 'qiita.jasper.sample'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
targetCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {

    // Test
    testImplementation 'org.junit.jupiter:junit-jupiter:5.5.2'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.0.1'

    // Jasper
    // https://mvnrepository.com/artifact/net.sf.jasperreports/jasperreports
    implementation 'net.sf.jasperreports:jasperreports:6.19.1'

    // Jasper Excel操作用
    // Excelを操作するライブラリで入れないと実行時にエラーになるので注意
    implementation 'org.apache.poi:poi:4.0.1'
}
  • イメージだけですが以下のような帳票テンプレートを作成
  • パラメーター名とフィールド名があっていればよいのでEXCEL出力においては重要なとこじゃないです

image.png

メインのとこ

  • 出力データの読み込みといった処理の大筋はPDFを出力する場合と同じ。ざっくり以下のような流れ。
    1. 帳票テンプレートの保存場所とかの基本設定を読込
    2. 出力データを設定
    3. 帳票テンプレートをコンパイル
    4. 出力データとコンパイルしたものから出力形式などを決めるJasperPrintクラスのインスタンスを生成
    5. お好みの形式で出力
  • 出力の時にJRXlsExporterクラスを使うところが違う。ここだけ気をつければOK。
ReportSample.java
package qiita.jasper.sample;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.export.OutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;

public class ReportSample {
	protected JasperReportConfig jasperReportConfig;
	/** 生成した帳票のパス */
	protected Path path;

	public Path getPath() {
		return path;
	}

    /** 
     * 帳票の設定値を読込
     */
	protected ReportSample() {
		this.jasperReportConfig = new JasperReportConfig();
	}

	/**
	 * 帳票を生成する
	 * 
	 * @throws IOException
	 * @throws JRException
	 * @throws FileNotFoundException
	 */
	public void generateExcelReport() throws FileNotFoundException, JRException, IOException {
		// サマリー(繰返し部分以外)を詰める
		Map<String, Object> params = makeBeansParams();

		// 明細(繰返し部分)を詰める
		JRDataSource dataSource = makeBeansDataSource();

		// 作成実行
		executeExcelReportGeneration(params, dataSource);
	}

	/**
	 * JasperReportsのParamtersに渡すインスタンスを生成する
	 * ※. 適当なサマリーデータを生成しているので、使う際は要修正
	 * 
	 * @return サマリーデータ
	 */
	protected Map<String, Object> makeBeansParams() {
		Map<String, Object> params = new HashMap<>();
		params.put("title", "サンプルのタイトル");
		params.put("pageHeader", "サンプルのページヘッダー");
		params.put("columnHeader", "サンプルのカラムヘッダー");
		params.put("columnFooter", "サンプルのカラムフッター");
		params.put("pageFooter", "サンプルのページフッター");
		params.put("summary", "サンプルのサマリー");
		return params;
	}

	/**
	 * JasperReportsのFieldsに渡すインスタンスを生成する
	 * ※. 適当な明細データを生成しているので、使う際は要修正
	 * 
	 * @return 明細データ
	 */
	protected JRDataSource makeBeansDataSource() {
		List<Detail> items = IntStream.range(1, 10).boxed().map(i -> new Detail("明細名" + i, i * 10, "個"))
				.collect(Collectors.toList());
		return new JRBeanCollectionDataSource(items);
	}

	/**
	 * jasperReportsを使用してExcelファイルを作成する。 今回の一番重要な処理!!!
	 *
	 * @param params サマリーデータ
	 * @param dataSource 明細データ
	 * @throws JRException
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	private void executeExcelReportGeneration(Map<String, Object> params, JRDataSource dataSource)
			throws JRException, FileNotFoundException, IOException {
		complieJasperReports();

		JasperPrint basePrint = JasperFillManager.fillReport(jasperReportConfig.jasperFilePath, params, dataSource);

        // ↓↓ここ以降の処理がPDFの場合と異なる ↓↓
		JRXlsExporter exporter = new JRXlsExporter();
		exporter.setExporterInput(new SimpleExporterInput(basePrint));

		// EXCELファイルの出力先を指定
		String outputExcelFilePath = jasperReportConfig.outputExcelFilePath;
		try (ByteArrayOutputStream excelStream = new ByteArrayOutputStream();
				FileOutputStream fos = new FileOutputStream(outputExcelFilePath)) {
			OutputStreamExporterOutput exporterOutput = new SimpleOutputStreamExporterOutput(excelStream);
			exporter.setExporterOutput(exporterOutput);
			exporter.exportReport();

			excelStream.writeTo(fos);
		}
        // 生成したEXCELファイルのパスを入れておく
		path = FileSystems.getDefault().getPath(outputExcelFilePath);
	}

	/**
	 * jrxmlファイルをコンパイルする。
	 * 
	 * @throws JRException
	 *
	 */
	private void complieJasperReports() throws JRException {
		JasperCompileManager.compileReportToFile(jasperReportConfig.jrxmlFilePath, jasperReportConfig.jasperFilePath);
	}

	/**
	 * JasperReportのファイル参照設定
	 */
	private class JasperReportConfig {
        /** 帳票テンプレート */
		private String jrxmlFilePath;
        /** コンパイルしたもの */
		private String jasperFilePath;
        /** 生成したEXCELファイル */
		private String outputExcelFilePath;

		JasperReportConfig() {
			File jrxmlFile = new File("src/main/resources/input/sample.jrxml");
			this.jrxmlFilePath = jrxmlFile.getAbsolutePath();
			File jasperFile = new File("src/main/resources/output/sample.jasper");
			this.jasperFilePath = jasperFile.getAbsolutePath();
			File outputPdfFile = new File("src/main/resources/output/sample.xls");
			this.outputExcelFilePath = outputPdfFile.getAbsolutePath();
		}
	}

	/**
	 * 帳票の明細部
	 */
	public class Detail {
		private String name;
		private Integer volume;
		private String unit;

		public String getName() {
			return name;
		}

		public Integer getVolume() {
			return volume;
		}

		public String getUnit() {
			return unit;
		}

		public Detail(String name, Integer volume, String unit) {
			super();
			this.name = name;
			this.volume = volume;
			this.unit = unit;
		}
	}
}

テスト

  • EXCEL作成とは直接関係はないです
ReportSampleTest.java
/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package qiita.jasper.sample;

import static org.junit.jupiter.api.Assertions.*;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import net.sf.jasperreports.engine.JRException;

public class ReportSampleTest {

	private static final String WORK_DIR = "src/main/resources/output/";

	@BeforeAll
	public static void initAll() throws IOException {
		// 作業フォルダを空にする
		cleanAllFile(WORK_DIR);
	}

	/**
	 * ディレクトリ以外のファイルを削除する。
	 * 
	 * @param dir
	 * @throws IOException
	 */
	private static void cleanAllFile(String dir) throws IOException {
		Path workDir = FileSystems.getDefault().getPath(dir);
		try (Stream<Path> stream = Files.list(workDir).filter(p -> p.toFile().isFile())) {
			stream.forEach(p -> {
				try {
					Files.deleteIfExists(p);
				} catch (IOException e) {
					// TODO 自動生成された catch ブロック
					e.printStackTrace();
				}
			});
		}
	}

	@Test
	public void エクセルが生成されること() throws FileNotFoundException, JRException, IOException {
		Path expected = FileSystems.getDefault().getPath(WORK_DIR + "sample.xls").toAbsolutePath();
		ReportSample report = new ReportSample();
		report.generateExcelReport();
		Path actual = report.getPath().toAbsolutePath();
		assertEquals(expected, actual);
	}
}

結果

  • 以下のように出力される

image.png

image.png

感想

  • PDFとEXCELを1フォーマットで両方作成できるのはやっぱり便利

参考

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?