Ruby から JasperReports でPDF帳票を出す(PDF出力処理をサーバ化)

2010年5月14日

Railsをpassengerで動かしている時に、RJBでJavaのライブラリJasperReportsを呼び出そうとすると

うまくいかなかった。

なので、一つの解決法としてJasperReportsの呼び出し部分をRailsとは切り離す仕組みとしてDRubyを採用する。

サンプルは別途リンクを張りますが、ここでは主要なソースのみ書き出します。

まずは、実際にPDFを作成する部分から

gen/WritePdf.java:

package gendosu;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import java.util.List;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRPrintPage;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperRunManager;
import net.sf.jasperreports.engine.util.JRLoader;

public class WritePdf {
  private String _hostName = "localhost";
  private String _databaseName = "jasper_report_on_rails_development";
  private String _userName = "root";
  private String _password = "root";

  public WritePdf(String hostName, String databaseName, String userName, String password) {
    _hostName = hostName;
    _databaseName = databaseName;
    _userName = userName;
    _password = password;
  }

  public void runTest(String jasperName, String jasperName2, String pdfName, HashMap paramMap){
    Connection con = null;
    try {
      con = getConnection();
      List pages = null;

      OutputStream outstream = null;

      // メインになる帳票を取得
      JasperPrint jasperPrint = JasperFillManager.fillReport(jasperName, paramMap, con);

      // 追加する帳票を取得
      JasperPrint jasperPrint2 = JasperFillManager.fillReport(jasperName2, paramMap, con);

      // 追加する帳票をメイン帳票に追加
      pages = jasperPrint2.getPages();
      for(JRPrintPage page : pages ){
        jasperPrint.addPage(page);
      }

      // 帳票をPDFファイルに出力
      JasperExportManager.exportReportToPdfFile(jasperPrint, pdfName);

    } catch (JRException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      closeConnection(con);
    }
  }

  private Connection getConnection(){
    Connection con = null;
    try {
      Class.forName("com.mysql.jdbc.Driver");
      String jdbcValue = String.format("jdbc:mysql://%s/%s", _hostName, _databaseName);
      con = DriverManager.getConnection(jdbcValue, _userName, _password);
    } catch (Exception e) {
      e.printStackTrace();
    }

    return con;
  }

  private void closeConnection(Connection con){
    try {
      con.close();
    } catch (Exception e) {
    }
  }
}

このJavaのメソッド「runTest」をrubyから呼び出します。

つづいて、この「runTest」を呼び出すrubyソース

create_pdf.rb:

require 'rubygems'
require 'drb/drb'
require 'rjb'
require 'erb'
require 'yaml'

CURRENT_PATH = File.dirname(File.expand_path(__FILE__))

classpaths = Dir.glob( File.join(CURRENT_PATH, 'java/lib/*.jar'))
classpaths.concat(Dir.glob(File.join(CURRENT_PATH, 'java/dist/*.jar')))

Rjb::load(classpath = classpaths.join(':'), jvmargs=[])

HashMap = Rjb::import("java.util.HashMap")
FileInputStream = Rjb::import('java.io.FileInputStream')
FileOutputStream = Rjb::import('java.io.FileOutputStream')

WritePdf = Rjb::import('gendosu.WritePdf')

class CreatePdf
  def initialize(stream=$stdout)
    @stream = stream
    @database = YAML::load(ERB.new(IO.read(File.join(CURRENT_PATH, 'config/database.yml'))).result)
  end

  def run_test(pdfName, outputDate, print_record_id)
    jasperName = File.join(CURRENT_PATH, 'java/reports/report1.jasper')
    jasperName2 = File.join(CURRENT_PATH, 'java/reports/report1.jasper')

    @write_pdf = WritePdf.new(@database[@stream]['host'], @database[@stream]['database'], @database[@stream]['username'], @database[@stream]['password'])

    hash_map = HashMap.new
    hash_map.put("OUTPUT_DATE", outputDate);
    hash_map.put("PRINT_RECORD_ID", print_record_id);

    @write_pdf.runTest(jasperName, jasperName2, pdfName, hash_map)
  end
end

@port = YAML::load(ERB.new(IO.read(File.join(CURRENT_PATH, 'config/pdf_server.yml'))).result)
rails_env = ARGV.shift
uri = "druby://localhost:#{@port[rails_env]['port']}"
DRb.start_service(uri, CreatePdf.new(rails_env))
puts DRb.uri
sleep

これで、RubyからRJBを使ってJavaのインスタンスを起動し、JasperReportsでPDF出力することが出来ます。

ここまでの修正で、実行テストは

create_pdf_client.rb:

require 'drb'

pdfName = 'test.pdf'

there = DRbObject.new_with_uri("druby://localhost:8787")

there.run_test(pdfName, "TEST", 1)

とし、このcreate_pdf_client.rbファイルを実行すると、PDFファイルが作成されます。

アンケート