spring boot ・ doma を使用した際の eclipse (gradle) の環境設定

spring boot で作成した プログラムで、データベースにアクセスする際の O/Rマッパーに doma を選択した際に、依存管理ツールに doma-spring-boot-stater を指定します。

いざ、eclipse で開発しようとした際、doma-n.n.n.jar を使用した環境設定は、公式(※1)を含めて多数存在します。しかし、doma-spring-boot-stater に関しての詳細な設定方法等が見つからなかったので、調査した内容をここに記載します。

■使用環境

windows 10

eclipse 4.15.0
gradle 6.3

doma-spring-boot-starter 1.4.0
doma-processor 2.35.0

■ファクトリーパスの設定

公式ページの説明では、Maven Central Repository より doma を入手し、ファクトリーパスに doma-n.n.n.jar を設定するように記載されています。(※1)

doma-spring-boot-stater の場合、gradle に記載する依存の設定は以下の通りになります。
※必要な箇所のみ抜粋

dependencies {
  implementation "org.seasar.doma.boot:doma-spring-boot-starter:1.4.0"
  annotationProcessor "org.seasar.doma:doma-processor:2.35.0"
}

上記を反映すると、doma-n.n.n.jar が取り込まれません。
代わりに、doma-core-2.35.0.jar が取り込まれます。

gradle の dependencies に設定した doma-processor と共に、doma-core-2.35.0.jar をファクトリーパスに設定する必要があります。
この時、下記画像の通りの順番も関係ありますので、ご注意ください。

※例)[外部jarの追加]より.gradle 配下のファイルを直接指定

■DOMA4019 エラー対応

gradle をデフォルトで使用した際 eclipse 上で[ DOMA4019 ]エラーが発生し、ビルドが失敗します。

javaのビルドパスで、「ソース・フォルダーごとに出力フォルダーの指定を可能にする」にチェックが入っている為です。
こちらのチェックを外すと、エラーが解消されます。

以上、eclipse での躓き箇所と 解決方法でした。

最後に、上記を含めた gradle の設定を公開します。

■gradle の設定

//  doma の gradle設定について、下記を参照してください。
//      https://doma.readthedocs.io/en/2.20.0/build/(日本語訳ページ)

// テンポラリディレクトリのパスを定義する
ext.domaResourcesDir = "${buildDir}/tmp/doma-resources"

  // ---- debug用 -------------------------------------
  //  println "processResources.destinationDir is ${processResources.destinationDir}"
  //  println "ext.domaResourcesDir            is ${ext.domaResourcesDir}"
  //  println "compileJava.destinationDir      is ${compileJava.destinationDir}"

// domaが注釈処理で参照するリソースをテンポラリディレクトリに抽出
task extractDomaResources(type: Copy, dependsOn: processResources)  {
  from processResources.destinationDir
  include 'doma.compile.config'
  include 'META-INF/**/*.sql'
  include 'META-INF/**/*.script'
  into domaResourcesDir
}

// テンポラリディレクトリ内のリソースをcompileJavaタスクの出力先ディレクトリにコピーする
task copyDomaResources(type: Copy, dependsOn: extractDomaResources)  {
  from domaResourcesDir
  into compileJava.destinationDir
}

compileJava {
  // 上述のタスクに依存させる
  dependsOn copyDomaResources
  // テンポラリディレクトリをcompileJavaタスクの入力ディレクトリに設定する
  inputs.dir domaResourcesDir
  options.encoding = 'UTF-8'
}

repositories {
  mavenCentral()
  mavenLocal()
  maven {url 'https://oss.sonatype.org/content/repositories/snapshots/'}
}

dependencies {
  implementation "org.seasar.doma.boot:doma-spring-boot-starter:1.4.0"
  annotationProcessor "org.seasar.doma:doma-processor:2.35.0"
}

eclipse {
  classpath {
    // [DOMA4019] 対応
    //   ソース毎の出力先指定を解除
    file.whenMerged {
      entries.each { entry ->
        if (entry.kind == 'src' && entry.hasProperty('output')) {
          entry.output = null
        }
      }
    }
  }
}

eclipse.jdt.file {
    // [Javaコンパイラー]->[注釈処理] の設定
    def  eclipseAptPrefsFile = '.settings/org.eclipse.jdt.apt.core.prefs'
    file(eclipseAptPrefsFile).write """\
      |eclipse.preferences.version=1
      |org.eclipse.jdt.apt.aptEnabled=true
      |org.eclipse.jdt.apt.genSrcDir=.apt_generated
      |org.eclipse.jdt.apt.genTestSrcDir=.apt_generated_tests
      |org.eclipse.jdt.apt.reconcileEnabled=true
      |""".stripMargin()


    // [Javaコンパイラー]->[注釈処理]->[ファクトリーパス] の設定
    def f = file(".factorypath")
    def w = new FileWriter(f)
    def jar = ""

    def xml = new groovy.xml.MarkupBuilder(w)
    xml.setDoubleQuotes(true)
    xml."factorypath"() {
      // doma-core.jar の読込み
      jar = configurations.annotationProcessor.find { File file -> file.name.matches('doma-core[^//]*') }
      'factorypathentry'(kind: 'EXTJAR', id: jar, enabled: true, runInBatchMode: false)

      // doma-processorjar の読込み
      jar = configurations.annotationProcessor.find { File file -> file.name.matches('doma-processor[^//]*') }
      'factorypathentry'(kind: 'EXTJAR', id: jar, enabled: true, runInBatchMode: false)
    }
    w.close()
}

上記を設定し、gradle eclipse もしくは、eclipse 上で [Gradle] -> [Gradle プロジェクトのリフレッシュ]を実行すると、本記事のファクトリーパスの設定・DOMA4019 を自動対応します。

■参考情報
※1:参考にした、doma 公式の設定ページ。
   https://doma.readthedocs.io/en/2.20.0/build/


ReactNative&ExpoによるPush通知(iOS)の実装

こんにちは。
最近ReactNative&ExpoでPush通知を実装する機会があったので、その内容を記事にさせていただきました。
私個人として、Expoを利用したPush通知機能の開発は

●難易度
  仕組みを理解することで実装自体は比較的簡単
  証明書などの手続きが基本的に不要。

●開発することによる効果
  簡易に通知を実装し、アプリの価値を高めることができる。

という点から、Expoでのアプリ開発をする上では非常にオススメの機能です。

その反面、ExpoでのPush通知の実装においては、

・日本語の記事はいくつかあるものの、サンプルが動かなかった。
・Push通知の仕組みも押さえておきたかったが、実装のコードのみの記事が多かった。
・テスト時の情報があまりなく、push通知のテスト部分で少し苦労した。


そういった経験から今回の記事を作成させていただきました。
私自身、そもそもPush通知の仕組みとは?という知識でしたので、Push通知の仕組みも含めて解説させていただきます。
また、今回はiOSでのテストのみ対象としています。
※基本はandroidでも同様ですが、androidの場合は追加で少し設定が必要です。

対象読者

①Expoを利用してより簡易的にPush通知を実装・テストしたいという方。
②そもそもPush通知とは?という方。

目次

1.環境
2.そもそもPush通知とは
3.Expoの提供するPush通知とは
4.実装①ライブラリインストール
5.実装②Push通知許可と通知用トークンの取得
6.実装③通知を開く・フォアグラウンドでの通知受信時の動作
7.ポイント Expoへのログイン
8.テスト①Expo Goのインストール
9.テスト②Push通知を送る
10.まとめ

1.環境

本記事では下記環境が構築されていることを前提としています。
・Expo(40.0.0)
・その他(上記Expoのバージョンに依存)
・テスト用iPhone (今回はiPhoneSE iOS 14.4を使用)
※本記事はReactNative&Expoの環境構築は省いています。

2.そもそもiOSのPush通知とは

上記の図のように

①端末側でユーザからPush通知の許可を取得。
②APNsからPush通知先の端末を特定するトークンを発行。
③②で発行されたトークン情報をサーバに登録。
④③で登録したトークン情報をキーに通知したい情報をApple社のPush通知用サーバに送信。
⑤Apple社のPush通知用サーバから各ユーザの端末にPush通知を送信。

上記のような仕組みとなり、トークンの発行や通知の送信などはApple社のPush通知用サーバを介する必要があります。
※通常はFirebaseなどのツールを利用することが多いかと思います。
また、iOSのPush通知を利用する場合には証明書の発行などの手続きを行う必要があります。

3.Expo(expo-notifications)を利用したPush通知の仕組み

上記の図のように

①端末側でユーザからPush通知の許可を取得
②Expoを介してApple社のPush通知用サーバから端末を特定するトークンを発行。
③②で発行されたトークン情報をサーバに登録
④③で登録したトークン情報をキーに通知したい情報をExpoのサーバを介してApple社のPush通知用サーバに送信。
⑤Apple社のPush通知用サーバから各ユーザの端末にPush通知を送信

基本的にはやはりApple社のサーバを介す必要があるのですが、そのあたりのやり取り(トークンの取得や通知情報の送信)をExpoが代行して行ってくれるため、
「とりあえずPush通知を実装したい」という場合は非常に簡易的にPush通知を実装することができます。
また、何より証明書発行などの手続きが必要ないということがとても大きなメリットかと思います。

4.実装①ライブラリインストール

今回必要となるライブラリは以下の通りです。

expo-notifications
Push通知を実装するためのコアとなるライブラリ

expo install expo-notifications

expo-constants
Push通知は実機でのみ確認可能となるため、実機かどうかの判定を入れています。

expo install expo-constants

5.実装②Push通知許可と通知用トークンの取得

registerForPushNotificationsAsync
①このアプリからのPush通知の許可を取得
②初回起動時は許可ダイアログを出してユーザからPush通知の許可を取得
③通知用トークンの取得
※今回はサーバなどには送信せず、画面にトークンを表示します。

App.js

import Constants from 'expo-constants';
import * as Notifications from 'expo-notifications';
import React, { useState, useEffect, useRef } from 'react';
import { Text, View, Button } from 'react-native';

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});

export default function App() {
  const [expoPushToken,setExpoPushToken] = useState(null);

  return (
    <View
      style={{
        flex: 1,
        alignItems: 'center',
        justifyContent: 'space-around',
      }}>
      <Text>push通知のトークン: {expoPushToken}</Text>
      <Button
        title="push通知用のトークンを取得"
        onPress={async () => {
          const pushToken = await registerForPushNotificationsAsync()
          setExpoPushToken(pushToken);
        }}
      />
  </View>
  );
}


async function registerForPushNotificationsAsync() {
  let token;
  if (Constants.isDevice) {
    //①このアプリからのPush通知の許可を取得
    const { status: existingStatus } = await Notifications.getPermissionsAsync();
    let finalStatus = existingStatus;
    if (existingStatus !== 'granted') {
       //②初回起動時は許可ダイアログを出してユーザからPush通知の許可を取得
      const { status } = await Notifications.requestPermissionsAsync();
      finalStatus = status;
    }
    if (finalStatus !== 'granted') {
      //許可がない場合
      alert('Failed to get push token for push notification!');
      return;
    }
    //③通知用トークンの取得
    token = (await Notifications.getExpoPushTokenAsync()).data;
    console.log(token);
  } else {
    //実機以外の場合
    alert('Must use physical device for Push Notifications');
  }
  return token;
}

6.実装③通知を開く・フォアグラウンドでの通知受信時の動作

④ユーザが通知をフォアグラウンドで開いた場合のリスナー
今回は「フォアグラウンドで通知を受信しました」と表示することにします。
⑤ユーザが通知を開いた場合のリスナー
今回は「通知を開きました」と表示することにします。

App.js

import Constants from 'expo-constants';
import * as Notifications from 'expo-notifications';
import React, { useState, useEffect, useRef } from 'react';
import { Text, View, Button } from 'react-native';

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});

export default function App() {
  const notificationListener = useRef();
  const responseListener = useRef();
  const [pushState,setPushState] = useState(null);
  const [expoPushToken,setExpoPushToken] = useState(null);

  useEffect(() => {
    // ④ユーザが通知をフォアグラウンドで開いた場合のリスナー
    notificationListener.current = Notifications.addNotificationReceivedListener(notification => {
      setPushState("フォアグラウンドで通知を受信しました。");
    });

    // ⑤ユーザが通知を開いた場合のリスナー
    responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
      setPushState("通知を開きました。")
    });
    // userEffectのreturnに登録する関数は、コンポーネントがunmountされるときに実行される。ここで主にcleanup処理を定義する
    return () => {
      Notifications.removeNotificationSubscription(notificationListener);
      Notifications.removeNotificationSubscription(responseListener);
    };
  }, []);
  return (
    <View
      style={{
        flex: 1,
        alignItems: 'center',
        justifyContent: 'space-around',
      }}>
      <Text>push通知のトークン: {expoPushToken}</Text>
      <View style={{ alignItems: 'center', justifyContent: 'center' }}>
        <Text>push通知受信時の動作: {pushState} </Text>
      </View>
      <Button
        title="push通知用のトークンを取得"
        onPress={async () => {
          const pushToken = await registerForPushNotificationsAsync()
          setExpoPushToken(pushToken);
        }}
      />
  </View>
  );
}


async function registerForPushNotificationsAsync() {
  let token;
  if (Constants.isDevice) {
    ////①このアプリからのPush通知の許可を取得
    const { status: existingStatus } = await Notifications.getPermissionsAsync();
    let finalStatus = existingStatus;
    if (existingStatus !== 'granted') {
      //②初回起動時は許可ダイアログを出してユーザからPush通知の許可を取得
      const { status } = await Notifications.requestPermissionsAsync();
      finalStatus = status;
    }
    if (finalStatus !== 'granted') {
      //許可がない場合
      alert('Failed to get push token for push notification!');
      return;
    }
    //③通知用トークンの取得
    token = (await Notifications.getExpoPushTokenAsync()).data;
    console.log(token);
  } else {
    //実機以外の場合
    alert('Must use physical device for Push Notifications');
  }
  return token;
}

7.ポイント Expoへのログイン

expo-notifiationsの機能を利用してテストをするためには、Expoにログインしておく必要があります。
以下のコマンドでログインしておくことでテストが可能になります。
Expoのユーザはこちらで作成可能です。

expo login

8.テスト①Expo Goのインストール

storeから「Expo Goアプリ」をインストールします。

アプリインストール後、[expo start]を実行した際に表示されるQRコードを実機でスキャンします。
これで画面が表示されるはずです。

9.テスト②Push通知を送る

Push通知を送信するためには、Expoの提供するAPIに必要な情報を送信する必要があります。
下記のようなJSONを「https://exp.host/–/api/v2/push/send」に対してPOST送信します。

[
  {
    "to": "取得したpush通知用のトークン",
    "title":"通知のタイトル部分",
    "body": "通知の内容部分"
  }
]

この際、ヘッダー情報は下記のものを設定します。
host: exp.host
accept: application/json
accept-encoding: gzip, deflate
content-type: application/json

例えば以下のようなPOST送信用のツールから情報を送信した場合

通知受信時(フォアグラウンド)

通知を開いた場合

10.まとめ

今回はできるだけ時間をかけずに早くリリースしたいということから「Expo」と「Expoが提供するPush通知用ライブラリ」の組み合わせでPush通知の実装・テストをより簡易的に行いました。
Push通知と聞くと「何やら難しそう」と思っていましたが、Expoを利用することでとても簡単に実装することができます。
是非皆さんも気軽にPush通知を実装してみてください。

Jaspersoft Studioを使用して帳票作成してみた

こんにちは。ソフトウェア開発をしていると領収証や請求書などの帳票を作成する機会があると思います。
最近、初めて帳票を改修する機会がありました。実装を見れば、ある程度何となくでも行けそうな箇所もありましたが、今回主に以下3点について改修したく、その際に知ったことを中心に改修箇所のポイントとして記事にすることにしました。
① 帳票に新たな項目と値を表示させたい
② 画像の変更をしたい
③ 明細部分の表示の実装を変更したい
※本記事は、帳票作成したことはないが、 既存プロジェクトに帳票がすでに作成されており、その改修作業をする人向けに記載をしております。そのため、実際のソースコードを追えば、 ある程度はできるであろうということを前提としております。

目次

● 環境
● はじめに
● 帳票作成ツール
● ポイント①:データソースの作成・紐づけ
● ポイント②:イメージの追加
● ポイント③:メインレポート内にサブレポートの埋め込み
● javaを使用したコンパイル・レポート出力方法
● Jaspersoft studio を使用したレポート出力方法
● まとめ

環境

本記事では、下記環境を前提に検証を行っております。
・プログラミング言語:Java (jdk1.8.0_77)
・帳票ライブラリ:JasperReports (v6.4.0)
・帳票作成ツール:Jaspersoft Studio (v6.16.0)

はじめに

帳票を作成するためには、「JasperReports」と呼ばれるJavaで動作するオープンソースの帳票出力ライブラリを使用します。
JasperReportsでは、帳票のレイアウト等が記述されたXMLファイルを読み込んで帳票を出力します。

また、作成されたレポートは、PDF、RTF、HTML/XHTML、MS Word(Docx)、MS Excel(XLS)、Open Officeなど様々な形式で出力することができます。出力方法は、Javaを使用した出力方法 または Jaspersoft Studioを使用した出力方法 を参照ください。

※ 拡張子は「.jrxml」です。
※ 「.jrxml」をコンパイルすると、「.jasper」という拡張子ファイルになります。

JasperReportsについて詳しく知りたい方は、こちら を参照ください。

帳票作成ツール

まずは、帳票作成ツールをご紹介します。
帳票を作成する際によく使用されるツールが、「Jaspersoft Studio」です。これは、レポートのレイアウトをマウス操作で設計できるツールです。
テンプレートファイルはXMLファイルの為、手書きすることも可能ですが、こういったデザインツールを使用した方が作業が捗ります。
ダウンロードは、こちら から

※本ページでは、プロジェクトの作成方法および基本的な使用方法の説明は割愛いたします。詳しく知りたい方は、こちら を参照ください。

ポイント①:データソースの作成・紐づけ

データベースからの取得結果やJava側で処理した値などを帳票に出力するには、帳票の項目へのマッピングが必要になります。マッピングさせるうえでの注意点は、以下2点です。

<1点目>
 Javaファイルとjrxmlファイルで項目名を完全一致させること

<2点目>
 Javaファイルとjrxmlファイルで項目の型が同じであること

以下は、JavaファイルJaspersoft studioを使用したデザインイメージそれをjrxmlファイルで見た場合の3つを表しております。
見ていただけると、同じ項目名・型になっていることがお分かりいただけると思います。

Javaソース

        // フィールドの設定値
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
        
        // パラメーターの設定値
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("tel", "090-9999-9999");

Jaspersoft studioを使用したデザインイメージ

jrxmlファイル

jrxmlファイルでは、項目名と型を以下のように<field>または<parameter>を使用して宣言します。
<field name="項目名" class="型"/>
<parameter name="項目名" class="型"/>
このように宣言してあげることで、それ以降、<textField>内などで使用が可能となります。

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.16.0.final using JasperReports Library version 6.16.0-48579d909b7943b64690c65c71e07e0b80981928  -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="MyProj" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" whenResourceMissingType="Error" uuid="3ea3dc26-1bc4-4f32-b3d4-e877955c227d">
	<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
	<property name="net.sf.jasperreports.print.create.bookmarks" value="false"/>
	<import value="java.io.ByteArrayInputStream"/>
	<parameter name="tel" class="java.lang.String"/>
	<field name="name" class="java.lang.String"/>
	<pageHeader>
		<band height="252">
			<textField isBlankWhenNull="true">
				<reportElement key="" x="20" y="10" width="300" height="30" uuid="856ed887-d16d-462c-b786-9d1d44619953">
					<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
					<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
				</reportElement>
				<textElement verticalAlignment="Middle">
					<font fontName="IPA ゴシック" size="24" pdfFontName="HeiseiKakuGo-W5" pdfEncoding="UniJIS-UCS2-HW-H" isPdfEmbedded="false"/>
				</textElement>
				<textFieldExpression><![CDATA["My name is " + $F{name}]]></textFieldExpression>
			</textField>
			<textField isBlankWhenNull="true">
				<reportElement key="" x="20" y="48" width="230" height="32" uuid="1dc9d4a3-e551-4433-b948-544f90d6dbf8">
					<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
					<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
				</reportElement>
				<textElement verticalAlignment="Middle">
					<font fontName="IPA ゴシック" size="24" pdfFontName="HeiseiKakuGo-W5" pdfEncoding="UniJIS-UCS2-HW-H" isPdfEmbedded="false"/>
				</textElement>
				<textFieldExpression><![CDATA["TEL : " + $P{tel}]]></textFieldExpression>
			</textField>
		</band>
	</pageHeader>
</jasperReport>

ポイント②:イメージの追加

イメージの追加方法には、主に以下の2点があります。

【方法①:画像が格納されているパスを記載する方法】
 こちらは一般的に使用されている方法で、プロジェクトにイメージを保存し、そのファイルパスを指定します。

<image>
  <reportElement x="200" y="10" width="210" height="80"/>
  <imageExpression class="Java.lang.String"><![CDATA["./sample.jpg"]]></imageExpression>
</image>

【方法②:Base64を使用する方法】
  Base64とは、64進数を意味する言葉で、すべてのデータをアルファベット(a~zA~z)と数字(0~9)、一部の記号(+,/)の64文字で表すエンコード方式です 。
そのため、方法①:ファイルパスの指定のようにプロジェクトに画像を保存する必要がありません。Base64について詳しく知りたい方は、こちら を参照ください。
手順は以下の通りです。

<手順①:Base64エンコーダーでBase64形式に変換>
  Base64エンコーダーと呼ばれるBase64形式にデータを変換してくれるソフトを使用します。ネットで検索するといくつも出てきますので、それを使用し、Base64形式に変換します。今回は、こちら を使用しました。

<手順②:コードの貼り付け>
 Base64形式のコードを、<parameter> に設定します。

<parameter name="image" class="java.lang.String">
 <defaultValueExpression><![CDATA["iVBORw0KGgoAAAANSUhEUgAABkA(長すぎるため、省略)AAD2EAAA8jWdB7OD"]]></defaultValueExpression>
</parameter>
<image hAlign="Left" vAlign="Bottom">
	<reportElement x="403" y="168" width="125" height="41" uuid="3261ff18-10ac-443e-8ee6-1ec3d3e8a3d9">
		<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
		<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
		<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
		<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
	</reportElement>
	<imageExpression><![CDATA[new java.io.ByteArrayInputStream(javax.xml.bind.DatatypeConverter.parseBase64Binary($P{image}))]]></imageExpression>
</image>

ポイント③:メインレポート内にサブレポートの埋め込み

請求書などを作成していると、商品の明細を出力することがあり、出力するレコードは可変になるパターンがほとんどです。その際に使用するのが、サブレポート機能です。
サブレポート機能とは、メイン帳票の中に複数の別の帳票(サブレポート)を配置することができる機能です。

ポイントとなるのは、以下2点です。

1:サブレポートとなるjrxmlファイルのパスの設定
  <subreportExpression>タグ内に、サブレポートとなるjrxmlファイルのパスを記載します。

2:サブレポートに渡す値の引数の設定
  <dataSourceExpression>タブ内に、「
net.sf.jasperreports.engine.data.JRBeanCollectionDataSource(引数) 」を記載し、サブレポートに渡す値を設定します。

<subreport overflowType="Stretch">
 <reportElement key="" stretchType="RelativeToTallestObject" mode="Transparent" x="-20" y="6" width="595" height="165" isRemoveLineWhenBlank="true" printWhenGroupChanges="Group1" uuid="12fdf542-a1d5-4e85-9ee7-c955f413a668">
  <property name="com.jaspersoft.studio.unit.height" value="pixel"/>
  <property name="com.jaspersoft.studio.unit.y" value="pixel"/>				  
 </reportElement>				 
 <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{lineDataList})]]></dataSourceExpression>				 
 <subreportExpression><![CDATA[$P{SUBREPORT_DIR} + "subreport.jasper"]]></subreportExpression>
</subreport>

Javaを使用したコンパイル・レポート出力方法

実際に java から帳票を生成してみます。今回は、PDFを出力します。
流れは以下の通りです。

① パラメータ・データソースの生成

 帳票に出力したいデータを生成します。

② jrxmlファイルのコンパイル

対象の jrxmlファイルを読み込んで、「JasperCompileManager.compileReportToFile(対象のファイルパス)」を使用し、 jasperファイルへコンパイルします。

③ データバインド

 「 JasperFillManager.fillReport(JasperReport, パラメータ, データソース)」を使用し、対象のjasperファイルへデータをバインドします。

④ PDF出力

exportReportToPdfFile(生成されたレポートオブジェクト, 生成ファイル名)」に生成したいファイル名を引数に指定し、PDFを出力します。なお、
exportReportToPdfFile()」 を変更することで、HTMLやXML等で出力することが可能です。こちら が参考になります。

以下は、実際に作成してみたソースコード例です。

    public static void main(String[] args) throws Exception {

        // フィールド(データソース)の設定
        TestDetailDto testDetailDto = new TestDetailDto();
        testDetailDto.setName("tanaka taro");
        List<?> dataSourceList = Arrays.asList(testDetailDto);
        JRDataSource res = new JRBeanCollectionDataSource(dataSourceList);

        // パラメーターの設定
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("tel", "090-9999-9999");

        try {
            // jrxmlファイルをjasperファイルへコンパイル
            File jrxmlFile = new File("sample.jrxml");
            JasperReport report = JasperCompileManager.compileReport(jrxmlFile.getAbsolutePath());
            // パラメータとデータソースを埋め込む
            JasperPrint jasperPrint = JasperFillManager.fillReport(report, parameters, res);
            // PDF出力
            JasperExportManager.exportReportToPdfFile(jasperPrint, "sample.pdf");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Jaspersoft studio を使用したレポート出力方法

Jaspersoft studioでは、作成したレポートを様々な形式で出力することができます。これは、作成後に[Preview]画面から出力したい形式を選択することで出力することが可能です。

まとめ

今回は、帳票出力する際に使用されるツールとjrxmlファイルのソースコードの書き方をいくつかポイントを絞ってご紹介しました。Jaspersoft studio は、帳票作成にはかかせないツールであり、柔軟な帳票を作成することができます。また、jrxmlファイル内で、コードがどう記載されているかを知るということが重要です。コードがわかるようになると、ある程度のことは Jaspersoft studio を使用せずとも、改修できるようになると思います。 ぜひみなさんもいろいろな帳票を作成してみてください。

WEB業界におけるディレクターとは何か?

こんにちは。SBWorksでディレクターとして働いているWと申します。前職も含めると、かれこれ10年近くWEB業界でディレクターというお仕事をやらせてもらっていますので、これまでの経験にもとづき、

  • WEB業界のディレクターの仕事内容
  • ディレクターに必要なスキル

についてお話しさせていただければと思います。

WEB業界のディレクターの仕事内容は?


身も蓋もない話ですが、正直に言ってしまうと、ひとくちにディレクターと言っても、その仕事内容は働く会社やアサインされるプロジェクトによって異なり、明確に「これだ」と定義するのは難しいと思います。

担保する工程で分けるとすると、
いままでいくつかの現場で見聞きしてきた中でも、

  • パターン1:ビジネス検討およびシステム概要の検討
  • パターン2:ビジネス検討から実装まで
  • パターン3:ビジネス検討とシステム概要の検討+プロマネ

という3つのパターンがありましたので、
現場によりディレクターのカバー範囲となる工程が異なるのが分かっていただけるかと思います。

また経験上、ディレクターは得意とする領域により、下図のように4つの系統に分けることもできるかと思います。

コアスキルを中心として、

  • SEOやWEB広告などが得意なら、マーケティング系ディレクター
  • 開発マネジメントが得意なら、開発系ディレクター
  • UI/UXなどが得意なら、フロント系ディレクター
  • 業務知見が豊富にあり業務運用が得意なら、バックエンド系ディレクター

という感じですね。
※ディレクターのコアスキルに関しては後述いたします。

ただ、どの系統にも共通して概ね、

  1. ビジネスの検討を行うこと(自社サービスであれば自社メンバと、お客様がいるのであればお客様と)
  2. そのビジネスを実現するための要件定義を行う
  3. 必要に応じてプロジェクトのマネジメントや設計・実装・テストを行う

というのがディレクターとしての仕事の流れになります。

なお、SBWorksでは「ビジネス検討とシステム概要の検討+プロマネ」のパターンの「開発系ディレクター」が多く、私もいま現在この役割を担っています。

ディレクターに必要なコアスキルは何か?


どの系統のディレクターにも必要なコアスキルがある、
とお話ししましたが、その中でも代表的なものを4つ、ピックアップします。

・コミュニケーション能力

ディレクターはビジネス検討もしくはそれに近いフェーズを担うため、ビジネスやプロジェクトの意思決定者と会話し、判断いただく機会がかなり多いです。ビジネスやプロジェクトの方針を意思決定者に判断頂く際、なかなかGOが出ないとその分スタートは遅れ、機会損失になってしまいます。そのため、コミュニケーション能力…厳密に言えば「物事を分かりやすく、端的かつロジカルに説明できる能力」は必須能力と言えます。

・ITに対する幅広い知見

自社サービス然り、お客様のビジネス然り、予算は無尽蔵にあるわけでありません。何をどう組み合わせればそのサービス・ビジネスは費用対効果高く実現できるのか、ディレクターはシステム概要の検討時に模索する必要があります。そのため、実際にシステムを構築できなくても構わないので、プログラミング言語の特性や各種インフラ・ミドルウェアの特徴など、幅広い知識を自分の引き出しから出せるようにしておく必要があります。

・関係者調整力

ディレクターは社内外含めて複数のステークホルダーと関わる場面が多いですが、ステークホルダー全員の要望が一致していることは稀です。全員の要望を叶えようとするとプロジェクトは一向に前に進まないため、第三者視点に立ち、各ステークホルダーの要望を取りまとめて1つのプラン・方向性を練り上げる、といった役割がディレクターに求められます。そのため、皆の要望を聞きつつ、その落としどころを探って方々を説得して回り推進する「関係者調整力」がとても重要なスキルになってきます。

・提案力

特にお客様のビジネスをお手伝いする場合ですが、ディレクターに求められるものは、「筋の良い提案」です。現在の状況や様々な事象を思考フレームワークを使いながら分析し、クリティカルな課題を抽出、その課題を解決する方法をメリット・デメリット等とあわせて分かりやすく資料にまとめ、お客様に提案する…といった、筋の良い提案を行うための一通りの力も、ディレクターに欠かせないスキルのひとつです。また、提案を行う際、お客様の目線に立つことも大事ですが、「このサービスを使うユーザはどう思うか?」「自社(開発会社)として最適なソリューションは何か?」といった多角的な視点があると、関わる人皆が幸せになれる提案ができると思います。

まとめ


WEB業界におけるディレクターの役割は幅広く現場によって異なるものの、そのどれにも共通したスキルが必要であることをお話しいたしました。

なお、SBWorksではディレクターを大募集しておりますので、我こそは!という方はぜひ、blogコメントや弊社公式HPの問い合わせフォームからコンタクトいただければと思います。

お読みいただきありがとうございました。