В моей предыдущей статье я изложил способ, которым мы, по крайней мере частично, интегрировали BIRT в процесс сборки Maven для недавнего проекта. Моя следующая задача в проекте состояла в том, как интегрировать Birt в структуру Wicket ? Мы использовали Wicket в некоторых наших предыдущих проектах, но в прошлом у нас не было необходимости углубляться в API Wicket, чтобы понять процесс его жизненного цикла, для создания пользовательских сессий, заполнения компонентов wicket из необработанного HTML-запроса. параметры и обработка запроса. Это является свидетельством прекрасной архитектуры Wicket, поскольку мы смогли писать нетривиальные приложения, не вдаваясь в абстракцию компонентов, предоставляемую платформой; однако это должно было измениться с BIRT.
Как интегрировать BIRT в ваше приложение
Существуют два основных способа интеграции BIRT (Business Intelligence и Reporting Tools) в ваше приложение:
- Используя приложение Birt Viewer,
- Использование API механизма отчетов
Из документации BIRT eclipse проще всего интегрировать BIRT в ваше веб-приложение, используя приложение BIRT Viewer. Когда я прочитал документацию, мне стало ясно, что этот метод будет чрезвычайно утомительным для использования с Wicket. Для интеграции со средством просмотра необходимо либо использовать теги JSP, что не является опцией в Wicket, либо предоставить URL-ссылки, которые проходят через соответствующие параметры отчета в строке запроса, что возможно в Wicket.
Для обоих этих методов требуется установить отдельный военный файл или веб-приложение для BIRT Viewer. Несмотря на то, что BIRT Viewer предоставляет отличные функциональные возможности, такие как возможность экспорта в различные форматы, автоматическое создание диалоговых окон параметров и многое другое, мне не понравилась эта модель развертывания. Это означало, что каждый раз, когда я развертывал наше веб-приложение, мне нужно было также развертывать приложение BIRT Viewer. Я решил использовать API нижнего уровня для интеграции BIRT. Более подробную информацию о том, как интегрировать BIRT Viewer, можно найти на сайте Eclipse.
Интеграция BIRT с использованием API механизма отчетов с Wicket
Я решил, что лучшим подходом является использование API механизма отчетов. Этот механизм отчетов API позволяет генерировать отчет с помощью вызовов API во время выполнения BIRT, а затем нужно будет самостоятельно обрабатывать поток вывода отчета в браузер клиента. Если бы я использовал API сервлета напрямую, было бы просто записать поток вывода в объект ответа в методе get или post сервлета, но в Wicket API сервлета скрыт от прямого доступа под слоями платформы.
Я не рассматриваю BIRT Reporting API в деталях, так как его довольно просто использовать. Фрагмент кода в конце статьи показывает, как я использовал API для генерации отчета, но полезную информацию о том, как использовать BIRT API, можно найти на сайте Eclipse BIRT.
Жизненный цикл запроса калитки
Чтобы понять, как можно получить доступ к выходному потоку ответа в Wicket, требуется понимание потока жизненного цикла запроса Wicket. К сожалению, в интернете мало документации о том, как идет платформа Wicket, от необработанного html-запроса до структуры, вызывающей ваш код Wicket. Некоторая информация может быть найдена здесь, но она скрывает детали самого объекта RequestCycle, оставляя один почесывая голову относительно того, где вы можете взять выходной поток.
После некоторого исследования приведенная ниже диаграмма отражает мое текущее понимание процессов жизненного цикла запроса калитки.
Жизненный цикл начинается, когда WicketFilter, как на диаграмме, или WicketServlet, в зависимости от настроек web.xml, получает необработанный HTML-запрос. Затем фильтр оборачивает объекты HTMLServlerRequest и HTMLServletResponse в объекты Wicket WebRequest и WebResponse и создает или получает объект RequestCycle . Класс RequestCycle является абстрактным, поэтому возвращаемый объект на самом деле является объектом WebRequestCycle, но большая часть интересной работы выполняется в абстрактном объекте RequestCycle.
Затем вызывается метод «request» объекта RequestCycle для обработки оставшейся части обработки. Для объекта RequestCycle требуется объект IRequestCycleProcessor, который фактически выполняет всю работу. Наш фактический объект является экземпляром класса WebRequestCycleProcessor, который расширяет класс AbstractRequestCycleProcessor , где, опять же, большая часть интересной работы выполнена. Объект WebRequestCycle вызывает методы в WebRequestCycleProcessor в инверсии шаблона управления во время обработки метода request.
Программный поток веб-запроса
Объект WebRequestCycleProcessor вызывает методы объекта WebRequest в три этапа в следующем порядке:
- Resolve — этот метод разрешает URL-адрес целевого компонента IRequestTarget, который был вызван. Это будет включать создание компонента с нуля или извлечение его из сеанса пользователя,
- ProcessEvents — это вызывает любые события, которые применимы для компонента. На приведенной выше диаграмме вызывается событие onSubmit () кнопки формы. Во время этой обработки RequestTarget может быть изменен с помощью вызова метода setRequesTarget RequestCycle. Это сбросит трехэтапный процесс, чтобы начать с «ProcessEvents» для нового requestTarget. (Объект RequestCycle хранит стек RequestTargets для обеспечения правильного запуска и очистки всех событий). В случае BIRT мы используем метод «onSubmit», чтобы изменить IRequestTarget (см. Ниже) на вывод PDF механизма отчетов. Таким образом, когда метод «ответить» вызывается на следующем этапе процессов, он вызывается для нашего пользовательского объекта, а не для исходного целевого объекта.
- Respond — это то место, где вызывается метод render из целевого компонента.
Таким образом, мы должны установить наш отчет в формате PDF, сгенерированный BIRT и API механизма отчетов, как RequestTarget после нажатия кнопки или ссылки. Wicket использует интерфейс IResourceStream для связи с потоками ресурсов. Большинство классов, реализующих этот интерфейс, ожидают получить объект входного потока, из которого можно прочитать поток для окончательного вывода в ответ. В тех случаях, когда вам нужно напрямую записывать в выходной поток динамически создаваемый контент, например отчеты в формате PDF, вам необходимо создать объект, реализующий интерфейс IResourceStreamWriter . Удобный класс AbstractResourceStreamWriter предназначен для легкого расширения и переопределения метода write.
Таким образом, после этого довольно сложного объяснения код для фактического отображения вашего BIRT pdf очень прост.
public void onSubmit() {
HashMap map = new HashMap();
....(process parameters from Wicket for the report and place in the map object)
ReportParameterPage.this.generateReport(map,((WebApplication)ReportParameterPage.this.getApplication()).getServletContext().getRealPath(reportName.toString()));
}
protected void generateReport(final Map map,final String strReport){
AbstractResourceStreamWriter writer = new AbstractResourceStreamWriter (){
public void write(OutputStream os) {
EngineConfig config = new EngineConfig();
String path = ((WebApplication)ReportParameterPage.this.getApplication()).getServletContext().getRealPath("WEB-INF/birt");
config.setEngineHome(path);
path = ((WebApplication)ReportParameterPage.this.getApplication()).getServletContext().getRealPath("WEB-INF/log");
config.setLogConfig(path,Level.FINE);
try {
Platform.startup(config);
IReportEngineFactory factory =(IReportEngineFactory) Platform.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
IReportEngine engine = factory.createReportEngine(config);
IReportRunnable report = engine.openReportDesign(strReport);
IRunAndRenderTask task = engine.createRunAndRenderTask(report);
task.setParameterValues(map);
PDFRenderOption options = new PDFRenderOption();
options.setOutputFormat("pdf");
options.setOutputStream(os);
task.setRenderOption(options);
task.run();
task.close();
} catch (BirtException e) {
logger.error(e.getLocalizedMessage());
}
}
public String getContentType() {
return "application/pdf";
}
};
this.getRequestCycle().setRequestTarget(new ResourceStreamRequestTarget(writer));
}
Вывод
Wicket — это отличный фреймворк, а BIRT — отличный инструмент для составления отчетов. Я надеюсь, что эта статья поможет другим использовать эти две технологии вместе. Я также надеюсь, что мы увидим больше статей, объясняющих внутреннюю работу калитки, так как я уверен, что это поможет в разработке новых сторонних компонентов.