Статьи

Примеры использования плагинов JSperReports JSF — простой список отчетов

Это первая «статья об использовании» серии плагинов JSperReports JSF, и я остановлюсь на простом требовании, а в дальнейшем я углублюсь. Отправной точкой является настройка проекта, которую мы уже выполнили для нашего книжного магазина, и я добавлю к ней список различных книг, зарегистрированных в нашей базе данных, и этот список будет также доступен в виде отчета.

Наше приложение будет предлагать следующие функции при отображении отчетов для пользователя:

  • Пользователь сможет выбрать формат вывода отчета.
  • Представление отчета будет локализуемым и будет выводиться в той же локали, что и пользователь приложения.

Начальная настройка

Чтобы избежать создания всех CRUD функционально, я инициализирую таблицу, которая будет содержать значения, которые будут показаны, используя скрипт SQL для простоты. Всего несколько записей должно быть достаточно для цели этой статьи, и поэтому я буду использовать следующий скрипт для подачи таблицы книги:

01
02
03
04
05
06
07
08
09
10
insert into book(title, author, published_year, genre, price)
    values('The Futurogical Congress', 'Stanislaw Lem', '1978', 'SciFi', 2.5);
insert into book(title, author, published_year, genre, price)
    values('Brave New World', 'H. G. Wells', '1975', 'SciFi', 3.99);
insert into book(title, author, published_year, genre, price)
    values('Treasure Island', 'Robert Lewis Stevenson', '1948', 'Adventures', 4.45);
insert into book(title, author, published_year, genre, price)
    values('The Lord of the Rings', 'J. R. Tolkien', '1945', 'Fantasy', 12.23);
insert into book(title, author, published_year, genre, price)
    values('In Cold Blood', 'Truman Capote', '1966', 'Nonfiction', 9.50);

Я создам пакет ресурсов, который будет содержать локализованные тексты для представления и отчета. Имя файла будет Messages.properties, и я добавлю его в пакет net.sf.jasperreports.jsf.sample.usecases в корневой папке ресурсов. Содержимое файла будет следующим:

1
2
3
4
5
6
7
8
9
report.format.select=Select report format
 
bookList.pageTitle=Browsing Books
bookList.id=Reference ID
bookList.title=Title
bookList.author=Author
bookList.genre=Genre
bookList.year=Year
bookList.price=Price

Я добавил другой файл, похожий на предыдущий, но названный Messages_es.properties и содержащий перевод на испанский язык, вы можете добавить свои дополнительные предпочтительные языки, если вы заинтересованы в поддержке более одного. Предыдущий файл ресурсов должен быть настроен в нашем файлеface-config.xml :

01
02
03
04
05
06
07
08
09
10
11
12
<faces-config ...>
    <application>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>es</supported-locale>
        </locale-config>
        <resource-bundle>
            <var>Messages</var>
            <base-name>net.sf.jasperreports.jsf.sample.usecases.Messages</base-name>
        </resource-bundle>
    </application>
</faces-config>

Поскольку я использую Maven, я настрою папку в структуре моего проекта для хранения файлов отчетов .jrxml и настрою POM для запуска компилятора JasperReports для этой папки. Я выбрал имя папки src / main / jasperreports, а конфигурация POM для подключаемого модуля JasperReports Maven выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>jasperreports-maven-plugin</artifactId>
  <version>1.0-beta-2</version>
  <executions>
    <execution>
      <goals>
        <goal>compile-reports</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <outputDirectory>target/jasperreports/jasper</outputDirectory>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>net.sf.jasperreports</groupId>
      <artifactId>jasperreports</artifactId>
      <version>4.5.1</version>
    </dependency>
  </dependencies>
</plugin>

Я также добавлю некоторую дополнительную конфигурацию в плагин Maven WAR, чтобы он мог собрать все файлы .jasper, сгенерированные компилятором JasperReports, и упаковать их в файл WAR приложения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-war-plugin</artifactId>
  <version>2.2</version>
  <configuration>
    <webResources>
      <resource>
        <directory>src/main/jasperreports</directory>
        <includes>
          <include>**/*.jrxml</include>
        </includes>
        <targetPath>resources/reports/sources</targetPath>
      </resource>
      <resource>
        <directory>target/jasperreports/jasper</directory>
        <includes>
          <include>**/*.jasper</include>
        </includes>
        <targetPath>resources/reports/jasper</targetPath>
      </resource>
    </webResources>
  </configuration>
</plugin>

Как вы можете заметить, я упаковываю файлы JasperReports .jrxml в архив веб-приложения. При использовании плагина мы можем ссылаться либо как ресурс шаблона отчета, механизм плагина достаточно умен, чтобы распознавать тип файла, на который ссылаются, и при использовании ссылки на исходный файл отчета плагин будет компилировать отчет на лету. Однако предпочтительным подходом всегда должно быть использование файла .jasper, поскольку он имеет лучшую производительность, чем другой.  

Разработка шаблона отчета

Как указывалось во введении к этой серии, инструмент визуального дизайна для JasperReports, который я буду использовать, — это iReport. Существует множество руководств по использованию iReport, поэтому я пропущу эту часть. Однако, так как я хочу создать отчет с учетом локали, я должен обратить внимание на образец I18n, представленный на веб-сайте JasperReports.

Итак, мы запускаем iReport и выбираем пустой шаблон отчета. Поскольку в нашем отчете будет использоваться источник данных на основе SQL, как только визуальный конструктор завершит загрузку, мы должны настроить предложение SQL, которое будет извлекать данные из базы данных. Для этого нужно нажать кнопку слева от параметров масштабирования в представлении дизайнера и выбрать вкладку «Запрос отчета»:
JasperReports-JSF-плагин-сценариев использования, простой список-доклад1
SQL-запрос, который я буду использовать для получения данных, является самым простым, который мы можем сделать. После ввода этого SQL-предложения iReport покажет нам все доступные поля в нижней части окна. Если он может загрузить все поля без ошибок, нажмите кнопку ОК, чтобы сохранить их в отчете:

1
select * from book;

Весь текст, который будет выводиться в моем окончательном отчете, будет получен из пакета ресурсов или из самой базы данных. Итак, как показывает пример JasperReports i18n, мы должны использовать текстовые поля везде, где мы хотим вывести некоторый текст. Представление дизайна отчета будет выглядеть примерно так:

JasperReports-JSF-плагин-сценариев использования, простой список-доклад2
XML-представление файла шаблона отчета будет выглядеть примерно так:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
<?xml version="1.0" encoding="UTF-8"?>
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              name="booklist" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20"
              topMargin="20" bottomMargin="20">
    <property name="ireport.zoom" value="1.5"/>
    <property name="ireport.x" value="0"/>
    <property name="ireport.y" value="0"/>
    <queryString>
        <![CDATA[select * from book]]>
    </queryString>
    <field name="BOOK_ID" class="java.lang.Integer"/>
    <field name="TITLE" class="java.lang.String"/>
    <field name="AUTHOR" class="java.lang.String"/>
    <field name="PUBLISHED_YEAR" class="java.lang.String"/>
    <field name="GENRE" class="java.lang.String"/>
    <field name="PRICE" class="java.math.BigDecimal"/>
    <background>
        <band splitType="Stretch"/>
    </background>
    <title>
        <band height="38" splitType="Stretch">
            <textField>
                <reportElement x="0" y="0" width="227" height="29"/>
                <textElement>
                    <font size="18" isBold="true"/>
                </textElement>
                <textFieldExpression><![CDATA[$R{bookList.pageTitle}]]></textFieldExpression>
            </textField>
        </band>
    </title>
    <columnHeader>
        <band height="27" splitType="Stretch">
            <textField>
                <reportElement x="0" y="0" width="100" height="20"/>
                <textElement>
                    <font isBold="true"/>
                </textElement>
                <textFieldExpression><![CDATA[$R{bookList.id}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="113" y="2" width="155" height="20"/>
                <textElement>
                    <font isBold="true"/>
                </textElement>
                <textFieldExpression><![CDATA[$R{bookList.title}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="285" y="2" width="100" height="20"/>
                <textElement>
                    <font isBold="true"/>
                </textElement>
                <textFieldExpression><![CDATA[$R{bookList.author}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="398" y="2" width="100" height="20"/>
                <textElement>
                    <font isBold="true"/>
                </textElement>
                <textFieldExpression><![CDATA[$R{bookList.year}]]></textFieldExpression>
            </textField>
        </band>
    </columnHeader>
    <detail>
        <band height="21" splitType="Stretch">
            <textField>
                <reportElement x="0" y="0" width="100" height="20"/>
                <textElement/>
                <textFieldExpression class="java.lang.Integer"><![CDATA[$F{BOOK_ID}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="113" y="0" width="155" height="20"/>
                <textElement/>
                <textFieldExpression><![CDATA[$F{TITLE}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="285" y="0" width="100" height="20"/>
                <textElement/>
                <textFieldExpression><![CDATA[$F{AUTHOR}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="398" y="0" width="112" height="20"/>
                <textElement/>
                <textFieldExpression><![CDATA[$F{PUBLISHED_YEAR}]]></textFieldExpression>
            </textField>
        </band>
    </detail>
    <columnFooter>
        <band height="45" splitType="Stretch"/>
    </columnFooter>
    <pageFooter>
        <band height="25" splitType="Stretch">
            <textField>
                <reportElement x="227" y="0" width="100" height="20"/>
                <textElement textAlignment="Center"/>
                <textFieldExpression class="java.lang.Integer"><![CDATA[$V{PAGE_NUMBER}]]></textFieldExpression>
            </textField>
        </band>
    </pageFooter>
    <summary>
        <band height="42" splitType="Stretch"/>
    </summary>
</jasperReport>

Сохраните этот файл в созданной ранее папке src / main / jasperreports, и вы готовы к следующему разделу.

Дизайн JSF View

Наш JSF View будет основан на Facelets , поэтому он будет записан в виде файла XHTML, в котором нам необходимо объявить различные пространства имен библиотеки, которые мы будем использовать. Для получения инструкций по настройке Facelets перейдите непосредственно к документации (приложения JSF 2.x поддерживают Facelets без дополнительных настроек).

Следующий фрагмент показывает содержимое шаблона Facelets, который я буду использовать для визуализации пользовательского интерфейса для списка книг. Скопируйте его и сохраните в файле внутри файлов содержимого вашего веб-приложения. Я буду использовать имя файла /book/bookList.xhtml :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?xml version="1.0" encoding="UTF-8"?>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
<head>
    <title>Book List - JasperReports JSF Use Cases</title>
</head>
<body>
<h1><h:outputText value="#{Messages['bookList.pageTitle']}"/></h1>
 
<div>
    <h:form id="bookListForm">
        <jr:source id="bookSource" type="jndi" value="java:comp/env/jdbc/BookStoreDB"/>
 
        <h:panelGrid columns="3">
            <h:outputLabel for="reportFormat" value="#{Messages['report.format.select']}" />
            <h:selectOneMenu id="reportFormat" value="#{bookList.reportFormat}"
                             onchange="document.bookListForm.submit();">
                <f:selectItems value="#{bookList.reportFormats}" />
            </h:selectOneMenu>
            <jr:reportLink id="reportLink" format="#{bookList.reportFormat}"
                           target="blank" source="bookSource"
                           value="/resources/reports/jasper/booklist.jasper"
                           resourceBundle="#{Messages}">
                <h:outputText value="#{Messages['bookList.action.show']}"/>
            </jr:reportLink>
        </h:panelGrid>
 
        <h:dataTable value="#{bookList.allBooks}" var="book">
            <h:column>
                <f:facet name="header">
                    <h:outputText value="#{Messages['bookList.title']}"/>
                </f:facet>
                <h:outputText value="#{book.title}"/>
            </h:column>
            <h:column>
                <f:facet name="header">
                    <h:outputText value="#{Messages['bookList.author']}"/>
                </f:facet>
                <h:outputText value="#{book.author}"/>
            </h:column>
            <h:column>
                <f:facet name="header">
                    <h:outputText value="#{Messages['bookList.year']}"/>
                </f:facet>
                <h:outputText value="#{book.publishedYear}"/>
            </h:column>
            <h:column>
                <f:facet name="header">
                    <h:outputText value="#{Messages['bookList.genre']}"/>
                </f:facet>
                <h:outputText value="#{book.genre}"/>
            </h:column>
        </h:dataTable>
    </h:form>
</div>
</body>
</html>

В выделенных строках мы добавляем компоненты JSF-плагина JasperReports:

  • Прежде всего, в строке 14 мы определяем компонент источника отчета с помощью тега <jr: source> . Этот компонент не будет выводить какие-либо данные в визуализированный HTML-код, но на него могут ссылаться визуальные компоненты библиотеки как способ сообщить им, как получить данные, необходимые для визуализации содержимого отчета.
  • В строке 21–26 мы определяем компонент ссылки на отчет с помощью тега <jr: reportLink> . Этот компонент будет выводить стандартный HTML-элемент, указывающий на специальный URL-адрес, созданный механизмом плагина. При щелчке по нему механизм плагина перехватывает этот URL и заменяет некоторые фазы жизненного цикла JSF для обработки данных отчета и генерации результата. Обратите внимание, что компонент отчета имеет атрибут resourceBundle, указывающий на пакет сообщений, который мы создали в первом разделе.

Примечание . Атрибут resourceBundle сделал доступным в ствольной версии (на момент написания этой строки) JSF-плагин JasperReports, который использует версию 1.3 библиотеки тегов. Для пользователей, которые все еще используют версию 1.2 библиотеки тегов, они могут получить аналогичный результат, добавив параметр в ссылку на отчет:

1
2
3
4
5
6
<jr:reportLink id="reportLink" format="#{bookList.reportFormat}"
               target="blank" source="bookSource"
               value="/resources/reports/jasper/booklist.jasper">
    <f:param name="RESOURCE_BUNDLE" value="#{Messages}" />
    <h:outputText value="#{Messages['bookList.action.show']}"/>
</jr:reportLink>

Помимо выделенных строк, я добавил код для отображения поля со списком со всеми опциями экспорта, поддерживаемыми JSF-плагином JasperReports, и таблицей данных, которая будет размещать различные записи для таблиц книг.

Примечание . Поле со списком содержит атрибут onchange, предназначенный для отправки формы с новым значением для опции экспорта отчета. Я должен сделать это таким образом, чтобы ссылка на отчет работала должным образом в JSF до версии 2.x, поскольку эти версии не поддерживают AJAX.

Представленное выше представление JSF нуждается в управляемом компоненте, чтобы этот компонент передавал значения в пользовательский интерфейс:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class BookListView {
 
    private BookManager bookManager;
 
    private List allBooks;
 
    private String reportFormat = &quot;pdf&quot;;
 
    public void setBookManager(BookManager bookManager) {
        this.bookManager = bookManager;
    }
 
    public List getAllBooks() {
        if (allBooks == null) {
            allBooks = bookManager.getAllBooks();
        }
        return allBooks;
    }
 
    public String getReportFormat() {
        return reportFormat;
    }
 
    public void setReportFormat(String reportFormat) {
        this.reportFormat = reportFormat;
    }
 
    public List getReportFormats() {
        FacesContext context = FacesContext.getCurrentInstance();
        JRFacesContext jrContext = JRFacesContext.getInstance(context);
        List list = new ArrayList();
        for (String format : jrContext.getAvailableExportFormats()) {
            list.add(new SelectItem(format, format));
        }
        return list;
    }
 
}

Поле bookManager является ссылкой на интерфейс, который обеспечит логику для извлечения всех книг из базы данных:

1
2
3
public interface BookManager {
    public List getAllBooks();
}

Как сказано во вступительной статье к этой серии, я не буду вдаваться в подробности о дополнительных классах или интерфейсах, необходимых для реализации варианта использования, поскольку каждый конкретный пользователь должен решить, какая инфраструктура будет предоставлять каркас приложения.  

Тестируем все вместе

Пришло время проверить, что все работает как надо. Итак, давайте запакуем наше веб-приложение, развернем его на нашем сервере Tomcat и введите следующий URL-адрес в предпочитаемом вами браузере: http: // localhost: 8080 / jrjsf-usecases / book / bookList.jsf .

Примечание. Перед выполнением операции развертывания должны быть запущены Derby (база данных) и Tomcat (сервер приложений).

Итак, вот как это должно выглядеть, когда наш браузер выводит содержимое предыдущего упомянутого URL:

JasperReports-JSF-плагин-сценариев использования, простой список-доклада3
Теперь нажмите на ссылку «Показать отчет», чтобы увидеть выходные данные отчета, заполненные строками из нашего пакета ресурсов и данными из базы данных:

JasperReports-JSF-плагин-сценариев использования, простой список-report4
Это пример снимка экрана, взятый из представления отчета в формате PDF. Используйте поле со списком в пользовательском интерфейсе, чтобы изменить формат экспорта отчета.

Вывод

Итак, все готово, это самый простой способ добавить отчет в наше приложение JavaServer Faces. Я начал с простого примера и буду время от времени добавлять к нему более сложные функции. Надеюсь, вам понравилась эта статья и вы вернетесь к будущим публикациям, хорошие вещи еще впереди!

Ссылка: JasperReports Примеры использования плагина JSF — простой список Отчет от нашего партнера JCG Алонсо Домингеса в блоге Code Nibbles .