Javaで帳票をPDF出力(JasperReport)


# 概要

* 帳票デザイナはJasper Studioを利用
	* フォントはIPAフォントを利用
	* 帳票デザイナ側でコンパイル
* コンパイルした帳票定義体を使ってJava経由でPDF出力

# インストール

## IPAフォントのインストール

* ライセンス的に利用可能なIPAフォントを使う
* [IPAフォントダウンロードサイト](http://ipafont.ipa.go.jp/node26#jp)からダウンロード

![Kobito.BINfiV.png](https://qiita-image-store.s3.amazonaws.com/0/60056/7f44e5ef-6012-636b-1773-d37d05e535aa.png "Kobito.BINfiV.png")

* 解凍すると```ipaexg.ttf```と```ipaexm.ttf```が出てくるので任意の場所に格納
	* システムフォントへのインストールは不要

## Jaspersoft Studioのインストール

* Jaspersoft Studioは単体インストールとEclipseに組み込む方式の２通りがある

	* 単体インストールの場合は[ここ](http://community.jaspersoft.com/project/jaspersoft-studio/releases)からダウンロードしてインストーラに従えばOK
	* 今回はEclipse組み込みで利用する

* Eclipseを開き、Help -> Eclipse MarketPlaceを開く
* Findのところに```jasper```で検索
* Jaspersoft Studioのinstallを押す

![Kobito.L4u0vb.png](https://qiita-image-store.s3.amazonaws.com/0/60056/0d91ffc2-9261-2da1-54f9-10e8789041d9.png "Kobito.L4u0vb.png")

* あとは流れでインストール。インストール後、eclipse再起動
	* 途中、```Calculating requirements and dependencies.```で30分とか(もっと？)待たされるけど気長に待つ
	
![Kobito.WRjyvH.png](https://qiita-image-store.s3.amazonaws.com/0/60056/ca10f6a3-cc0f-fa54-7ef4-64d707af8230.png "Kobito.WRjyvH.png")


## Jaspersoft Studioにfontの設定

* preference -> Jaspersoft Studio -> Fonts

* Addを押して以下のように２つ登録

![Kobito.GlJ6jD.png](https://qiita-image-store.s3.amazonaws.com/0/60056/9e2c44d9-fa70-ea16-3b88-9c846e2c7309.png "Kobito.GlJ6jD.png")

![Kobito.JJG29W.png](https://qiita-image-store.s3.amazonaws.com/0/60056/47b320e2-1063-1b16-8573-c510c1da5146.png "Kobito.JJG29W.png")

# レポート作成

## projectの作成

* File -> New -> Other -> JasperReport Project
* 任意の名前でprojectを作成
	* 今回はデザイナ用のprojectで分けたかったので
	* 既存のjava projectに帳票を作っていくのでもOK

* Window -> Open Perspective -> Other -> Report Design でJasper用perspectiveを開く

## お試しreportの作成
* project右クリック -> New -> Jasper Report
* 任意のファイル名.jrxmlを作成
* 適当な```Static Text```を配置して日本語を記入

![Kobito.o90mYx.png](https://qiita-image-store.s3.amazonaws.com/0/60056/057adf7d-489a-7e73-1b94-a7e481ac5945.png "Kobito.o90mYx.png")

* PDFフォントやPDF Embedded設定は不要

* 保存するとjasperファイルが出来上がる

## データセットの作成

* CSVファイルを読み込み、プレビューさせるようにする
* 任意の場所にcsvファイルを作成。今回は以下のように

```csv
id, name
1, hoge
2, fuga
```

* Project右クリック -> New -> Data Adapter
* Filenameに任意の名前.xmlを設定してNext
	* １帳票１Data Adapterの方がわかりやすいので帳票名と合わせたほうがよい
* Data Adaptersから```csv```を選択

![Kobito.W2rlTt.png](https://qiita-image-store.s3.amazonaws.com/0/60056/22619013-344c-922e-5a63-e2a79f34a828.png "Kobito.W2rlTt.png")

* Data Adapterの設定をする

![Kobito.8tDv1y.png](https://qiita-image-store.s3.amazonaws.com/0/60056/0aa39542-bf54-ab9f-94b5-ce9981f9f530.png "Kobito.8tDv1y.png")

* Report側にData Adapterの設定をする
* 帳票の何もないところをクリックしてPropertiesを見る
* Reportタブの```Default Data Adapter```を開く

![Kobito.QtcVrJ.png](https://qiita-image-store.s3.amazonaws.com/0/60056/81634d6f-fc3b-6238-4d0a-130ff04f9457.png "Kobito.QtcVrJ.png")

![Kobito.J8Fnlf.png](https://qiita-image-store.s3.amazonaws.com/0/60056/e4ad1c4f-654a-2fdc-1a90-ae51035eb8d5.png "Kobito.J8Fnlf.png")


* これでOutLineとかに```Fields```としてCSVで定義した項目が表示されるのでドラッグアンドドロップで配置

![Kobito.RruCVS.png](https://qiita-image-store.s3.amazonaws.com/0/60056/345a2e65-5139-273e-4abf-e804ef525b39.png "Kobito.RruCVS.png")


* Previewタブを開き、dataadapterの設定をする

![Kobito.OMIByc.png](https://qiita-image-store.s3.amazonaws.com/0/60056/bbcfdcd4-73e4-7cc8-e303-a5b6aa41f1b9.png "Kobito.OMIByc.png")

* ちゃんとpreviewできていることを確認

![Kobito.rlfCRy.png](https://qiita-image-store.s3.amazonaws.com/0/60056/b529b496-c0fc-6e94-94c0-5c53d07b9d1d.png "Kobito.rlfCRy.png")


# PDF出力Javaモジュールの作成

## project作成

* Gradleを利用して作ってみる
* New -> Project -> Gradle Project
* 任意の名前でprojectを作成

## Gradle設定

* Jasperレポート実行に必要な依存ライブラリを定義
* 一部、mavenCentralにないものもあるのでリポジトリもいくつか追加してる
* buildしたら実行可能jarを作りたいのでmanifest定義もここでしている
* jarにまとめた時、bcmailやbctspといった依存ライブラリが悪さをするのでexclude指定している


```build.gradle
buildscript {
    repositories {
      mavenCentral artifactUrls: [
        'http://jasperreports.sourceforge.net/maven2',
        'http://jaspersoft.artifactoryonline.com/jaspersoft/third-party-ce-artifacts/'
      ]

      maven {
        url "https://plugins.gradle.org/m2/"
      }
    }
    dependencies {
    }
}

plugins {
  id 'us.kirchmeier.capsule' version '0.10.0'
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'application'

sourceCompatibility = 1.8

archivesBaseName = 'jasperConverter'

repositories {
    mavenCentral artifactUrls: [
        'http://jasperreports.sourceforge.net/maven2',
        'http://jaspersoft.artifactoryonline.com/jaspersoft/third-party-ce-artifacts/'
    ]
}

configurations {
  all*.exclude module: 'bcmail-jdk14'
  all*.exclude module: 'bctsp-jdk14'
  all*.exclude module: 'bcprov-jdk14'
}

dependencies {
    compile 'commons-collections:commons-collections:3.2'
    compile 'net.sf.jasperreports:jasperreports:6.2.1'
    compile 'com.lowagie:itext:2.1.7'
    testCompile 'junit:junit:4.+'
}

mainClassName = 'sample.Main'

task fatCapsule(type: FatCapsule) {
  applicationClass mainClassName
}

task executableCapsule(type: FatCapsule) {
  applicationClass mainClassName
  reallyExecutable
  archiveName = 'jasperConverter'
}

```

## PDFフォント埋め込み用の設定

* resources配下に以下の感じでファイルを配置

![Kobito.iQKfCW.png](https://qiita-image-store.s3.amazonaws.com/0/60056/c9ce9b90-15c9-8032-b1a1-0d35f5b3017a.png "Kobito.iQKfCW.png")


* resources/font配下にipaフォントのttfを配置
* ```jasperreports_extension.properties```は以下のように記述

```jasperreports_extension.properties
net.sf.jasperreports.extension.registry.factory.fonts=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.simple.font.families.font=fonts/font.xml
```

* ```font.xml```は以下のように
	* この時、fontFamilyに指定する名前＝レポート側で設定したフォント名であるようにする
	* このフォント名でttfファイルとのひも付けをする

```font.xml
<?xml version="1.0" encoding="UTF-8"?>
<fontFamilies>
  <fontFamily name="ipaexg">
    <normal>fonts/ipaexg.ttf</normal>
    <pdfEncoding>Identity-H</pdfEncoding>
    <pdfEmbedded>true</pdfEmbedded>
  </fontFamily>
  <fontFamily name="ipaexm">
    <normal>fonts/ipaexm.ttf</normal>
    <pdfEncoding>Identity-H</pdfEncoding>
    <pdfEmbedded>true</pdfEmbedded>
  </fontFamily>
</fontFamilies>

```

## PDF出力javaメイン処理

* コマンドラインより起動されるとして
* パラメータが以下を渡されるものとする
	* 帳票定義体ファイル(*.jasper)のパス
	* 入力するCSVファイルのパス
	* 出力するPDFファイルのパス

* として記述したもの

```java
package sample.jasperconverter;

import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;

import net.sf.jasperreports.engine.JasperRunManager;
import net.sf.jasperreports.engine.data.JRCsvDataSource;

public class Main {

  public static void main(String[] args) throws Exception {
    Map<String, Object> parameters = new HashMap<>();


    if (!validateArgs(args)) {
      System.out.println("parameter error");
      System.exit(9);
    }

    String jasperPath =  args[0];
    String inputFilePath = args[1];
    String outputFilePath = args[2];

    JRCsvDataSource dataSource = new JRCsvDataSource(new FileInputStream(new File(inputFilePath)));
    dataSource.setUseFirstRowAsHeader(true);

    JasperRunManager.runReportToPdfFile(jasperPath, outputFilePath, parameters, dataSource);

  }

  private static boolean validateArgs(String[] args) {

    if (args.length != 3) {
      System.out.println("parameter length error expected 3 but " + args.length);
      return false;
    }


    for(int i=0; i<args.length; i++){
      System.out.println("execute parameter " + i + ":" + args[i]);

      switch(i) {
      case 0:
        // jasper file path
        String jasperpath = args[i];
        if (!isFileExists(jasperpath)) {
          System.out.println("not found jasper file. path:" + jasperpath);
          return false;
        }
        break;

      case 1:
        // input csv file path
        String inputpath = args[i];
        if (!isFileExists(inputpath)) {
          System.out.println("not found input file. path:" + inputpath);
          return false;
        }
        break;

      case 2:
        // output pdf file path
        break;
      }
    }

    return true;
  }

  private static boolean isFileExists(String filepath) {
    return (new File(filepath)).exists();
  }


}


```

* これをGradleから```fatCapsule```して出来上がったjasperConverter-capsule.jarを実行すればOK

```bash
java -jar jasperConverter-capsule.jar ./trial.jasper ./input.csv ./output.pdf

```


# 帳票に外部イメージファイルを渡す(2016.3.22追記)

* ロゴ等のイメージファイルを帳票上表示させたい
* ファイルは後から置き換えられるように外部リソースにする

## デザイナ側

### Imageを配置

* imageをドラッグアンドドロップで配置

* 画像ファイルの指定ダイアログが出るがとりあえずNo Imageを選択して後で指定させる



![Kobito.Co6ahi.png](https://qiita-image-store.s3.amazonaws.com/0/60056/18e2b33d-a355-664d-d3f4-e3e856c1c96a.png "Kobito.Co6ahi.png")


* 配置したImageのpropertiesから配置やサイズを指定
* propertiesのImageタブにあるExpressionに以下のように記述

![Kobito.SscycJ.png](https://qiita-image-store.s3.amazonaws.com/0/60056/0b0817d6-e0dc-6408-0b52-bbdc08b26911.png "Kobito.SscycJ.png")


* ここで指定したキー名が帳票実行時のパラメタのキー名と対応する


### パラメタの追加

* Outline -> Parameters右クリック -> Create Parameterを選択

* 作成したparameterのpropertiesで以下のように設定

![Kobito.l3alqp.png](https://qiita-image-store.s3.amazonaws.com/0/60056/215ffa42-6b60-a146-37d2-ba46b99d4982.png "Kobito.l3alqp.png")


### Previewで確認

* Previewを出そうとするとパラメータ```logo```を求められるのでここに画像ファイルパスを入力する

![Kobito.IzgW5m.png](https://qiita-image-store.s3.amazonaws.com/0/60056/639739cc-e52f-f3b3-75c7-522b72313af7.png "Kobito.IzgW5m.png")


* これでプレビューに画像イメージが表示される


## Java側

* parameterにキー名とパスをセットするだけ

* 抜粋で記載


```java

Map<String, Object> parameters = new HashMap<>();

parameters.put("logo", "path-to-logo.png");

...

JasperRunManager.runReportToPdfFile(jasperPath, outputFilePath, parameters, dataSource);


```