いるもの
- Java
- Rails2.0.2
- SQLite3
- http://www.jasperforge.org/jaspersoft/opensource/business_intelligence/jasperreports/
- http://jasperforge.org/jaspersoft/opensource/business_intelligence/ireport/(帳票のレイアウトを作成するためのツール)
- jasperreport_on_rails.tar.gz(RailsからJasperReportを使うためのJavaクラス、上のWikiにリンクあり)
- iTextAsian.jar(日本語を出力するのに必要なJAR http://sourceforge.net/project/showfiles.php?group_id=15255)
- 試した環境:WindowsXP SP2
テスト用のRailsの環境を作成
> gem install sqlite3-ruby ・・・sqlite3がなかったのでインストール > rails jaspertest > cd jaspertest > ruby script/generate model CustomerType > ruby script/generate model Customer
SQLite3をインストール
SQLite Download Pageから以下の2つのファイルをダウンロード
* sqlite-3_5_8.zip
* sqlitedll-3_5_8.zip
これらのファイルをダウンロードし、解凍したらPATHの通っているところにコピーする。
その後以下のコマンドを実行してRubyからsqlite3を使えるようにする。
> gem install sqlite3-ruby
テーブルを作成
db/migrate/001_create_customer_types.rbを以下のように編集
class CreateCustomerTypes < ActiveRecord::Migration def self.up create_table :customer_types do |t| t.integer :id t.string :code, :limit => 3 t.string :name, :limit => 10 t.timestamps end end def self.down drop_table :customer_types end end
db/migrate/002_create_customers.rbを以下のように編集
class CreateCustomers < ActiveRecord::Migration def self.up create_table :customers do |t| t.integer :id t.string :name, :null => false t.string :address t.integer :customer_type_id t.timestamps end end def self.down drop_table :customers end end
migrateを実行してテーブルを作成
> rake db:migrate
テスト用のデータをフィクスチャのファイルに入力
test/fixtures/customer_types.yml
type1: id: 1 code: '001' name: '支払先' type2: id: 2 code: '002' name: '請求先' type3: id: 3 code: '003' name: '支払・請求'
test/fixtures/customers.yml
custmer_1: id: 1 name: '株式会社 ABC' address: '東京都渋谷区' customer_type_id: 1 custmer_2: id: 2 name: '株式会社 CDE' address: '東京都渋谷区' customer_type_id: 1 custmer_3: id: 3 name: '株式会社 EFG' address: '東京都渋谷区' customer_type_id: 3 custmer_4: id: 4 name: 'XYZ 株式会社' address: '東京都渋谷区' customer_type_id: 2
テーブルにフィクスチャのデータをロードする
> rake db:fixtures:load
CustomerとCustomerTypeの関連を設定
app/models/customer.rbを以下のようにする
class Customer < ActiveRecord::Base belongs_to :customer_type end
顧客一覧XMLを取得するアクションを作成
> ruby script/generate controller Accounting
app/controllers/accounting_controller.rbに以下のメソッドを追加
def customer_list @customers = Customer.find(:all) end
app/views/accounting/customer_list.rxmlを以下のように作成
xml.instruct! xml.customer_list_result do xml.invoice_customers do @customers.each do |customer| xml << customer.to_xml(:dasherize=>false, :skip_instruct=>true, :only=>[:id,:name,:address], :root=>"customer", :include => :customer_type) # belongs_toで指定したリレーションもXMLに end end end
WEBrickサーバを起動し
> ruby script/server
次のようにブラウザに表示されたらOK
このXMLは保存して(customer_list.xmlとしておく)、次のiReportのテンプレートして使う。
最終的にはこのXMLの内容がPDFとして出力される。
<?xml version="1.0" encoding="UTF-8"?> <customer_list_result> <invoice_customers> <customer> <address>東京都渋谷区</address> <id type="integer">1</id> <name>株式会社 ABC</name> <customer_type> <id type="integer">1</id> <name>支払先</name> </customer_type> </customer> <customer> <address>東京都渋谷区</address> <id type="integer">2</id> <name>株式会社 CDE</name> <customer_type> <id type="integer">1</id> <name>支払先</name> </customer_type> </customer> <customer> <address>東京都渋谷区</address> <id type="integer">3</id> <name>株式会社 EFG</name> <customer_type> <id type="integer">3</id> <name>支払・請求</name> </customer_type> </customer> <customer> <address>東京都渋谷区</address> <id type="integer">4</id> <name>XYZ 株式会社</name> <customer_type> <id type="integer">2</id> <name>請求先</name> </customer_type> </customer> </invoice_customers> </customer_list_result>
iReportで帳票のテンプレートを作成する
- iReportをダウンロードし解凍してできたディレクトリ内のiReport.exeを実行
- メニューの[データ]>[接続/データソース]を選択しウィザードを起動
- [新規]>[XLMファイルデータソース]を選択し次へ
- 以下のように設定
- 「保存」を押して完了する
- メニューの[ファイル]>[レポートウィザード]を選択
- 以下のテンプレートを使用してくださいに「なし」、接続データソースに「No connection or datasource」を指定し次へ(ステップ4まで特に設定しないので次へ押していく)
- ステップ4で「テーブルレイアウト」を選択し「gray_landscapeT.xml」を選択し次へ、最後に完了を押して終了。
- [gray_landscape]が作成されてるので、名前をつけて保存で「custrep.jrxml」として保存しておく。
- メニューの[データ]>[レポートクエリ]を選択、「レポートクエリ」タブのクエリ言語に「xpath2」を指定(右側にXMLの構造が表示される)
- 階層を展開していき、「customer」(たくさんあるがどれでもOK)を右クリックし「Set record node(generate xpath)」を選択。左に「/customer_list_result/invoice_customers/customer」と設定される。
- さらに「customer」を展開し、「address, id, name」と項目が見えたらこれを一ずつ下の「フィールド、フィールドタイプ」となっている部分へドラッグ&ドロップしていく(ここではaddress,nameをドラッグ)
- customer_typeのリレーションの「name」だけが必要なので、これ(customer_type以下のname)を同様にドラッグ、ただし、ドラッグしたらname2となってしまい分かりにくいので、ダブルクリックし「name2」を「customer_type_name」に変更しておく。
- レイアウトを整える。日本語のラベルや、テキストボックスはPDF文字エンコーディング、フォントに以下のうちいずれかを選択しておく必要がある。
- フォント
- HeiseiKakuGo-W5
- HeiseiMin-W3
- PDFエンコーディング
- UniJIS-UCS2-H (Japanese)
- UniJIS-UCS2-V (Japanese)
- UniJIS-UCS2-HW-H (Japanese)
- UniJIS-UCS2-HW-V (Japanese)
- フォント
- メニューの「ビルド」>「実行(有効な接続)」を実行し帳票の出力イメージを確認
- このとき、iReport.exeのある場所に「custrep.jasper」ファイルが出力される(このファイルを後で使う)
RailsからJasperReportsを利用するための設定
- jaspertest/app以下に次のディレクトリを作成、ライブラリや作成したファイルを置く
- app/jasper
- app/jasper/bin
- app/jasper/lib
- app/reports
app/jasper/bin
jasperreport_on_rails.tar.gzをダウンロードして解凍して出来るbinディレクトリ内のXmlJasperInterface.classをコピーして設置
app/jasper/lib
iReportを解凍したディレクトリ内のlibディレクトリ内の全てのJARファイルを置く
いるものの所で挙げた「iTextAsian.jar」もこのディレクトリに入れる
app/reports
前の工程で生成された「custrep.jasper」ファイルをを設置
- HowTowに載っているコードを同じように追加
- app/controllers/application.rbの中に以下の内容をコピー&ペースト
class Document include Config def self.generate_report(xml_data, report_design, output_type, select_criteria) report_design << '.jasper' if !report_design.match(/\.jasper$/) interface_classpath=Dir.getwd+"/app/jasper/bin" case CONFIG['host'] when /mswin32/ mode = "w+b" #windows requires binary mode Dir.foreach(Dir.getwd+"/app/jasper/lib") do |file| interface_classpath << ";#{Dir.getwd}/app/jasper/lib/"+file if (file != '.' and file != '..' and file.match(/.jar/)) end else mode = "w+" Dir.foreach(Dir.getwd+"/app/jasper/lib") do |file| interface_classpath << ":#{Dir.getwd}/app/jasper/lib/"+file if (file != '.' and file != '..' and file.match(/.jar/)) end end result=nil IO.popen "java -Djava.awt.headless=true -cp \"#{interface_classpath}\" XmlJasperInterface -o#{output_type} -f#{Dir.getwd}/app/reports/#{report_design} -x#{select_criteria}", mode do |pipe| pipe.write xml_data pipe.close_write result = pipe.read pipe.close end return result end end
このクラスはJavaのプロセスを起動しXmlJasperInterface.classを実行する。
このクラスを実行するときにcustomre_listアクションで生成されたXMLのデータを引き渡し、
PDFへ変換してもらう。
- app/helpersに「send_doc_helper.rb」ファイルを作成し、次の内容をコピー&ペースト
module SendDocHelper protected def cache_hack if request.env['HTTP_USER_AGENT'] =~ /msie/i headers['Pragma'] = '' headers['Cache-Control'] = '' else headers['Pragma'] = 'no-cache' headers['Cache-Control'] = 'no-cache, must-revalidate' end end def send_doc(xml, xml_start_path, report, filename, output_type = 'pdf') case output_type when 'rtf' extension = 'rtf' mime_type = 'application/rtf' jasper_type = 'rtf' else # pdf extension = 'pdf' mime_type = 'application/pdf' jasper_type = 'pdf' end cache_hack send_data Document.generate_report(xml, report, jasper_type, xml_start_path), :filename => "#{filename}.#{extension}", :type => mime_type, :disposition => 'inline' end end
このクラスのsend_docメソッドでは、一つ前に作成したDocumentクラスを呼びだし、
取得したデータ(PDFかRTF形式のデータ)をレスポンスとして返す処理が書かれている。
- app/controllers/accounting_controller.rbに以下の宣言を追加(2009/02/20 追記)
class AccountingController < ApplicationController # ↓この2行を追加 helper :send_doc include SendDocHelper
- app/controllers/accounting_controller.rbに以下のメソッドを追加
def customer_report @customers=Customer.find(:all) send_doc( render_to_string(:template => 'accounting/customer_list', :layout => false), '/customer_list_result/invoice_customers/customer', 'custrep', 'CustomerReport', 'pdf') end
このメソッドで指定している内容
-
- :template => 'accounting/customer_list': app/views/accounting/customer_list.rxml
- /customer_list_result/invoice_customers/customer: iReportで使われるXPath(なんだろ)
- custrep: app/jasper内にある.jasperファイルの名前
- CustomerReport: ダウンロードしたときのファイル名
- pdf: PDFで出力するように指定
以上で設定完了。
実行
http://localhost:3000/accounting/customer_report
にアクセス。こんな感じに出てくる。
大体、下のHowTo(↓)にあるとおりにやると出来る。
http://wiki.rubyonrails.org/rails/pages/howtointegratejasperreports
JasperReportsはJavaで作られた帳票ツール。