вторник, 21 августа 2012 г.

Использование шрифтов в JasperReports

Не так давно одной из моих задач было создать модуль отчетности, позволяющий разным клиентским приложениям использовать его для генерации и отдачи сгенерированного контента. При реализации этой задачи я активно работал с библиотекой JasperReports 4.5.1. Одна из первоочередных задач при работе с кирилическими документами - подключение шрифтов. В стандартном варианте подключения JasperRepots не имеет поддержки UTF-8 шрифтов. В нашем случае были необходимы шрифты Arial и Helvetica. Ни того ни другого нет по умолчанию. Дальше я опишу два подхода. Первый был выбран на скорую руку и я впоследствии решил от него отказаться. Второй подход - то как надо было делать сразу и он верный.

Решение 1. - Неправильное(мое оценочное суждение).

  • Скачать файлы ttf, из интернета, либо, если у вас windows, то их можно найти в директории {WIN_INSTALLATION_DIR}\Fonts\
  • Положить эти файлы в директорию проекта, чтобы они были доступны в classpath. Например сюда {project_dir}\src\main\resources\Arial.ttf
  • Явно указать название файла в отчете.
Такой подход привел сразу к проблемам, выяснилось, что выделение жирным не работает, потому что указанный шрифт не содержит жирного варианта. Была выбрана заплатка в таком виде - явно указывать шрифт для элемента. Поскольку сроки поджимали так и было сделано: Конечно, это жутко неудобно не только потому, что так можно делать только для элемента, а внутри элемента разделение на жирный и нежирный шрифт работать не будет, но и как следствие мы лишаемся гибкости в комбинировании элементов и их расположении. Ну и плюс к тому нужно постоянно прописывать явно имя шрифта. Почитав внимательнее документацию по JasperReports был выбран и использован верный способ работы со шрифтами.

Решение 2 - Правильное(рекомендованное документацией и сообществом JasperReports)

Для этого решения используется расширение стандартных шрифтов JasperReports через конфигурационные файлы. Шаги следующие:

  • Скачать/скопировать необходимые шрифты в папку {project_dir}\src\main\resources\fonts
  • Создать файл jasperreports_extension.properties в директории {project_dir}\src\main\resources\. Файл приведен ниже:
  • Создать файл specialfonts.xml в директории {project_dir}\src\main\resources\fonts Файл содержит описание того откуда JasperRepots будет брать файлы шрифтов и какой файл какому(жирному, курсиву и т.д.) стилю соответствует. Ниже пример моего файла:
  • Указать какой шрифт будет использоваться в шаблоне отчета.

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

понедельник, 20 августа 2012 г.

JBOSS 7 and several persistence units.

В течение этого года один из проектов, в котором я участвую, пишется с использованием технологий JEE, EJB3, JPA. Проект интеграционный и зачастую возникает задача использования нескольких баз в рамках одного модуля. Решается это просто: используется несколько persistence-unit в рамках одного persistence.xml. Например вот так: Все бы ничего вот только проблема заключается в том, что при таком подходе при запуске JBOSS жалуется на ошибку инициализации CoreReportAnotherSchemaJPA контекста, он пытается в нем найти связку для класса ReportCategory, который вроде бы даже не определен в этом persistence-unit. Оказывается проблема заключается в следующем. При определении персистеных классов во всех модулях нашего проекта используется аннотация Entity. Ниже пример такого класса: При старте приложения, сервер приложений не обращает внимание на то, что явно указаны классы в persistence-unit он сканирует на предмет наличия аннотации Entity доступный в classpath классы. Отсюда возникает эта коллизия. Решение оказалось довольно простым в спецификации есть тег exclude-unlisted-classes по умолчанию он имеет значение false, поэтому и добавляются не нужные мне классы и происходит коллизия с тем что указано. Включив этот флажок получаем именно то что нам нужно - включаться будут только те классы что указаны руками. Конечно, в обычном приложении без интеграционных замарочек с legacy кодом в разных базах такой проблемы не возникнет. Но кому-то все же этот прием может понадобится. Ниже приведен пример работающего кода с означенным тегом: