Ruby on Rails — это потрясающая среда для создания веб-приложений. Экосистемы Ruby и Rails очень активны и зрелы, со многими библиотеками для решения различных проблем, с которыми сталкиваются разработчики. Но одной конкретной областью, где я чувствую, что у Руби нет вариантов, является отчетность. В Rails существует множество решений для генерации отчетов, большинство из которых полагаются на генерацию HTML и преобразование в PDF. Этот подход имеет свои преимущества, но не подходит для сложных и точных отчетов.
Войдите в JasperReports . JasperReports — это очень популярная библиотека отчетов с открытым исходным кодом, широко используемая в мире Java. Многим из вас может быть интересно узнать, как использовать библиотеку Java в Rails. Есть много подходов, но я предпочитаю использовать JRuby. Это требует от вас преобразования вашего приложения в JRuby, что довольно просто сделать в наши дни. Итак, начнем.
Пример приложения Rails
Мы создадим пример приложения на Rails с моделью контакта и действиями CRUD. Приложение будет использовать JRuby, Rails 4.2 и SQLite в качестве базы данных для простоты. Прежде всего, установите JRuby с помощью RVM или rbenv .
Переключитесь на JRuby и в bundle install
последнюю версию Rails gem. Теперь создайте новое приложение Rails, вот так:
rails new contactbook
После того, как приложение сгенерировано, создайте скаффолд Contact, который выполняет операции с ресурсами amodel и CRUD:
cd contactbook rails g scaffold Contact name:string address:string city:string phone:string email:string
Теперь перенесите базу данных:
rake db:migrate
Давайте проверим, как это работает:
rails s
Направьте ваш любимый браузер на http: // localhost: 3000 / contacts и убедитесь, что все работает правильно. Создайте несколько записей, чтобы мы могли использовать их позже.
Пример JasperReport
Давайте создадим простой отчет, который показывает список контактов. Загрузите JasperSoft Studio, подходящую для вашей платформы, с сайта Jaspersoft Studio . Установите и запустите Jaspersoft Studio. Это полноценная IDE, основанная на Eclipse, специально для разработки JasperReports. Конечно, у него есть кривая обучения, но мы пока не будем вдаваться в эти детали. Вы можете обратиться к Jaspersoft Studio — Ресурсы для получения дополнительной информации.
С помощью Jaspersoft Studio создайте отчет с именами contacts
который должен выглядеть следующим образом:
Скомпилируйте отчет и вставьте файл contacts.jasper в app / reports / нашего приложения Rails.
Интеграция JasperReports
Теперь важная часть — интеграция JasperReports в приложение Rails. Мы будем использовать версию JasperReports 6.1 для этого урока. jasperreports-6.1.0-project.tar.gz
страницу библиотеки JasperReports и загрузите jasperreports-6.1.0-project.tar.gz
. Этот архив содержит JAR-файлы JasperReports в своей папке dist , а также зависимости в папке lib . Скопируйте все файлы из обеих этих папок и поместите их в папку с именем jasperreports в каталоге lib в нашем приложении Rails.
contactbook - app ... - lib - jasperreports - jasperreports-6.1.0.jar ...
У нас есть все необходимые файлы для JasperReports, поэтому давайте создадим класс для интеграции JasperReports. Создайте файл с именем jasper_report.rb в каталоге lib со следующим кодом:
Dir.entries("#{Rails.root}/lib/jasperreports").each do |lib| require "jasperreports/#{lib}" if lib =~ /\.jar$/ end require 'java' java_import Java::net::sf::jasperreports::engine::JasperFillManager java_import Java::net::sf::jasperreports::engine::JasperExportManager java_import Java::net.sf.jasperreports.engine.JRResultSetDataSource class JasperReport DIR = "#{Rails.root}/app/reports" def initialize(report, query, params = nil) @model = report @report_params = params @conn = ActiveRecord::Base.connection.jdbc_connection @query = query end def to_pdf stmt = @conn.create_statement @result = JRResultSetDataSource.new(stmt.execute_query(@query)) report_source = "#{DIR}/#{@model}.jasper" raise ArgumentError, "#@model does not exist." unless File.exist?(report_source) params = {} params.merge!(@report_params) if @report_params.present? fill = JasperFillManager.fill_report(report_source, params, @result) pdf = JasperExportManager.export_report_to_pdf(fill) return String.from_java_bytes(pdf) end end
Давайте посмотрим, что на самом деле делает код. Сначала нам нужны все файлы JasperReports в наш класс, например так:
Dir.entries("#{Rails.root}/lib/jasperreports").each do |lib| require "jasperreports/#{lib}" if lib =~ /\.jar$/ end
Добавьте объявления импорта Java для JasperReports:
require 'java' java_import Java::net::sf::jasperreports::engine::JasperFillManager java_import Java::net::sf::jasperreports::engine::JasperExportManager java_import Java::net.sf.jasperreports.engine.JRResultSetDataSource
Определите место, где будут храниться все отчеты:
DIR = "#{Rails.root}/app/reports"
Добавьте код инициализации в конструктор класса:
def initialize(report, query, params = nil) @model = report @report_params = params @conn = ActiveRecord::Base.connection.jdbc_connection @query = query end
В качестве первого шага мы инициализировали все необходимые переменные:
- Имя файла
report
—report
- SQL-запрос отчета —
query
- Любые необязательные параметры для передачи в отчет —
params
@conn
— это соединение JDBC из пула соединений ActiveRecord, поскольку JasperReports требует соединения JDBC для выполнения запроса.
Наконец, мы добавили метод для заполнения и экспорта отчета в формат PDF:
def to_pdf stmt = @conn.create_statement @result = JRResultSetDataSource.new(stmt.execute_query(@query)) report_source = "#{DIR}/#{@model}.jasper" raise ArgumentError, "#@model does not exist." unless File.exist?(report_source) params = {} params.merge!(@report_params) if @report_params.present? fill = JasperFillManager.fill_report(report_source, params, @result) pdf = JasperExportManager.export_report_to_pdf(fill) return String.from_java_bytes(pdf) end
Первым элементом является оператор JDBC stmt = @conn.create_statement
, который возвращает JDBC ResultSet путем выполнения @result = JRResultSetDataSource.new(stmt.execute_query(@query))
. Файл отчета ( .jasper
), созданный ранее с использованием JasperStudio, имеет значение report_source
. После этого вызовите JasperFillManager.fill_report
чтобы заполнить отчет предоставленными ResultSet и параметрами. Наконец, вызовите JasperExportManager.export_report_to_pdf
чтобы экспортировать отчет в поток PDF, который возвращается с использованием String.from_java_bytes
.
Теперь у нас есть отчет в формате PDF, но у нас пока нет возможности отправить его пользователю. Итак, добавьте небольшой вспомогательный метод в application_controller.rb следующим образом:
def respond_to_report(name, query, filename, download = false, report_params = nil) @report = JasperReport.new(name, query, report_params) disposition = (download.nil? || download == false) ? 'inline' : 'attachment' send_data @report.to_pdf, :filename => filename, :type => :pdf, :disposition => disposition end
Этот вспомогательный метод упрощает вызов отчета и отправляет ответ обратно пользователю. Также добавлены параметры для предоставления имени файла, наряду с возможностью disposition
чтобы открыть файл в браузере или загрузить его как вложение.
Теперь мы добавим действие в ContactsController
который вызывает отчет. Добавьте следующий код в app / controllers / contacts_controller.rb :
def report respond_to_report('contacts', 'select * from contacts', 'contacts.pdf') end
Поскольку у нас нет параметров для передачи и мы хотим открыть отчет в браузере, мы пропустили download
и report_params
из вызова метода.
Обновите route.rb, чтобы добавить новое действие:
resources :contacts do get :report, on: :collection end
Добавьте ссылку на отчет в представлении contacts / index.html.erb :
... <h1>Listing Contacts</h1> <%= link_to 'Download as PDF', report_contacts_path %> ...
Запустите сервер и перейдите по адресу http: // localhost: 3000 / contacts . Нажмите «Скачать в формате PDF». Теперь вы должны увидеть файл PDF со всеми контактами в списке.
Завершение
Это был краткий пример того, как интегрировать JasperReports с Rails для создания отчетов без особых усилий. С помощью JasperReports и Rails можно сделать гораздо больше, например, критерии поиска, сложные отчеты, подотчеты и т. Д. Но это для другого учебника.
Я надеюсь, вам понравился этот пост. Ваши комментарии и идеи всегда приветствуются.