JSF является стандартом для реализации каркасов (фреймворков) web-приложений на платформе Java. Существует эталонная реализация стандарта, которая называется Mojarra JSF. Она обеспечивает обработку запросов и предоставляет набор базовых компонентов для разработки пользовательского интерфейса. Фреймворк JSF является компоненто-ориентированным и вносит концепции разработки настольных приложений в разработку web-приложений.

Существует несколько версий JSF:

  • JSF 1.0 (11 марта 2004) – первая реализация спецификации JSF;
  • JSF 1.1 (27 мая 2004) – bugfix-релиз версии 1.0. В эту версию не включены ни какие изменения в спецификации, ни изменения в рендеринге HTML-кода, только исправления ошибок, допущенных в JSF 1.0.
  • JSF 1.2 (11 мая 2006) – следующая версия реализации спецификации JSF со значительными доработками в ядре и API фреймворка.

Все эти версии обьяевлены разработчиками Sun (ныне Oracle) как устаревшие. Текущая актуальная версия JSF – JSF 2.0, вышедшая в свет 28 июня 2009 года. Эта версия намного проще в использовании чем все предыдущие (конфигурация аннотациями и пр. улучшения), значительно расширена функциональность фреймворка, а так же значительно улучшена производительность.

Ниже я буду рассматривать версию JSF 2.0.2. Официальная документация находится в документе The Java EE 6 Tutorial, Volume I. Официальный сайт проекта Mojarra: https://javaserverfaces.dev.java.net/.

JSF 2 предоставляет несколько новых и удобных возможностей, таких как стандартизированный механизм поддержки Ajax, валидация введенных пользователем данных с помощью аннотаций (JSR 303), использование технологии Facelets в качестве стандартного движка рендеринга и еще несколько функций, без которых невозможно представить современное web-приложение.

Стандартная реализация JSF предоставляет только основные функции для работы с HTML-компонентами, однако, одна из главных идей проекта – предоставить разработчикам возможность разрабатывать свои виджеты, например, деревья, сложные таблицы и т.д. Существует ряд сторонних библиотек компонентов. Самые популярные из них: ADF Faces, Trinidad, ICEFaces, PrimeFaces, RichFaces, NetAdvantage, JViews.

Проект Mojarra является Open Source, а версия JSF 2.0.2 распространяется под лицензиями Common Development and
Distribution License (CDDL) + GPLv2.

Тестовое приложение, которое описывается ниже, разработано в среде IntelliJ IDEA 9 (Maia) Ultimate Edition версии IU-95.4. Это не стабильная версия, но в ней есть значительные улучшения поддержки JSF 2 даже по сравнению с последней стабильной 9.0.1. IDEA – это коммерческая IDE. Персональная лицензия стоит $249. Скачать ее можно с сайта JetBrains.

После установки IDEA вы получаете практически полностью готовую для разработки IDE. В нее включены инструменты для работы с Maven (сам Maven должен быть установлен и настроен на вашем компьютере), SVN, Git. Вы можете подключить любой фреймворк, например, Spring или Hibernate, одним щелчком мыши. Нам же из всего этого набора понадобится только Maven, а выбор пал на IDEA из-за отличного редактора xhtml да и в общем, отличной поддержки JSF 2.

Hello World

Для начала необходимо создать проект. Проект у нас будет Maven-модулем. Выполните File -> New Project… Выберите Create project from scratch (создать проект с нуля). Заполните поле имя проекта. У меня проект называется hellojsf. Выберите в разделе Module Settings пункт Maven Module.

Создание web-проекта в IDEA 9

Создание web-проекта в IDEA 9

После того как вы нажмете Next, появится список архетипов (archetype – образец) Maven. Мы создадим обычное web-приложение. Выберите maven-archetype-webapp:RELEASE. GroupId у меня ru.topcode, ArtifactId оставляем по умолчанию, версию тоже. Maven создаст структуру проекта, откроет файл pom.xml и предложит включить авто-импорт. Мы на это предложение согласимся, нажав на Enable Auto-Import в правом верхнем углу. Теперь все зависимости, которые вы прописываете в pom.xml будут автоматически импортироваться в проект, а среда не будет задавать глупых вопросов.

Что требуется

Для разработки тестового приложения нам потребуется установленный и настроенный Maven. Как его установить и настроить читайте на официальном сайте проекта Maven 2.

Для тестирования web-приложения нам понадобится Tomcat 6.x.

Подключение Tomcat 6.x к IntelliJ IDEA 9

Процедура подключения Tomcat к IDEA – проще некуда:

  1. Скачайте Tomcat с официального сайта. Потребуется Binary Distributions Core zip.
  2. Распакуйте архив. У меня получился путь c:\devTools\apache-tomcat-6.0.26.
  3. Перейдите в IDEA, зайдите в меню Run -> Edit Configuration, нажмите на Add New Configuration и выберите Tomcat Server -> Local.
  4. Появится диалоговое окно настройки сервера. Нажмите на Configure… напротив комбобокса Application Server, нажмите в появившемся диалоговом окне Add и укажите путь до Tomcat (c:\devTools\apache-tomcat-6.0.26).
  5. Перейдите на вкладку Deployment и установите флажок на hellojsf:war.
  6. Проверьте как работает сервер. Для этого нажмите Run или Shift + F10. Проект развернется в Tomcat, после чего откроется браузер со страницей http://localhost:8080/ на которой отобразится фраза “Hello World!”.

Часто бывает что порт 8080 занят. Можно изменить его на какой-нибудь менее популярный. Делается это путем редактирования файла server.xml, который лежит в %CATALINA_HOME%\conf\. Откройте его и измените строку

<Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />

на

<Connector port="8282" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />

После этого снова откройте Run Configuration в IDEA и измените порт в строке Startup page.

Подключение библиотек JSF 2 к приложению

Подготовительный этап закончен, теперь нужно подключить библиотеки JSF 2 к нашему приложению. Для этого откройте pom.xml (если еще не открыт) и добавьте туда Maven-репозиторий, в котором лежат эти библиотеки:

<repositories>
  <repository>
    <id>maven2-repository.dev.java.net</id>
    <name>Java.net Repository for Maven</name>
    <url>http://download.java.net/maven/2</url>
  </repository>
</repositories>

После этого в тэг dependencies нужно добавить новые зависимости:

<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-api</artifactId>
    <version>2.0.2</version>
</dependency>
 
<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-impl</artifactId>
    <version>2.0.2</version>
</dependency>
 
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
 
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
</dependency>

На этом подключение библиотек JSF 2 закончено. Посмотрите, появились ли у вас эти библиотеки в навигаторе, в узле External Libraries. В IDEA также есть графический навигатор по pom.xml. Если вы не отказались от поддержки Maven при установки IDEA, то в правой части экрана у вас должна быть кнопка Maven Projects. Нажмите ее и вы увидите жизненный цикл Maven-проекта, состоящий из фаз, каждую из которых можно выполнить двойным щелчком, и список зависимостей. Если вы видите в этом дереве зависимости, которые мы только что добавили в pom.xml и они не подсвечены красной волнистой линией, значит все прошло успешно. Если они там не появились или подсвечиваются красной линией, значит у вас возникли какие-то проблемы, например, вы забыли подключиться к Internet :-)

Замечание по поводу различных контейнеров сервлетов: Tomcat нормально реагирует на то, что вы деплоите библиотеки JSF 2 вместе с web-приложением, однако, например, в поставку GlassFish они уже входят и нет необходимости включать эти библиотеки в свой war-файл. Более того, из-за этого могут возникнуть проблемы.

Если вы используете Jetty для запуска web-приложений, то необходимо положить эти библиотеки в JETTY_HOME/lib/ext/ или создать для них отдельную директорию, например, JETTY_HOME/lib/ext/jsf-2.x/.

При использовании этих контейнеров, складывать библиотеки JSF в WEB-INF/lib web-приложения не нужно, однако для компиляции они все таки нужны. Поэтому в файле pom.xml в описание зависимостей нужно добавить

<scope>compile</scope>

Например,

<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-api</artifactId>
    <version>2.0.2</version>
    <scope>compile</scope>
</dependency>

Изменение web.xml

Класс-сервлет FacesServlet, запускает обработку жизненного цикла JSF-запроса и должен быть определен в web.xml. Тег маппинга сервлета (servlet-mapping) определяет URLы, которые должен обрабатывать FacesServlet. В спецификации JSF обычно используют Шаблон /faces/*, однако можно использовать и любой другой префикс или суффикс. После всех изменений web.xml должен выглядеть следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
            http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 
    <display-name>hellojsf</display-name>
 
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
 
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
</web-app>

Здесь в context-param определен параметр javax.faces.PROJECT_STAGE со значением Development. Это нужно для того, чтобы при возникновении каких-либо исключительных ситуаций, в окно браузера выводился подробный отчет о возникшем исключении. По умолчанию значение этого параметра равно Production. Поэтому, при развертывании приложения на реальном сервере, можно просто удалить блок context-param.

Создание ресурсного файла

Хорошим тоном при разработке любых приложений, будь то настольное или web-приложение, является вынесение всех строковых констант в специальный ресурсный файл. Это позволяет легко интернационализировать приложение.

Сейчас мы имеем следующую структуру приложения:

Структура JSF web-приложения, созданная Maven 2

Структура JSF web-приложения, созданная Maven 2

Создайте директорию java в директории main, затем щелкните правой кнопкой на проекте (модуле) и выберите пункт Module Settings. Откроется диалоговое окно настройки модуля. На странице Sources в правой части в дереве проекта найдите директорию java, которую мы только что создали, выделите ее и нажмите на кнопку Sources, которая находится над деревом проекта. Вы увидите что пиктограмма папки стала синей. Это значит, что в этой директории хранятся исходники приложения. Сейчас у нас две такие директории. В директории java мы будем хранить наши исходные коды. Можете прямо сейчас создать в ней пакеты, например, ru.topcode. Папка resources будет содержать остальные ресурсы приложения, например, наши ресурсные файлы. В конечном итоге, все это окажется в WEB-INF/classes war-файла проекта.

Теперь добавьте в resources пакет messages, а в нем создайте файл messages.properties, в котором мы будем размещать все строковые константы. Получилась следующая структура:

Структура web-проекта после добавления новой директории для ресурсов

Структура web-проекта после добавления новой директории для ресурсов

Добавьте в messages.properties строку hello.world=Hello world. Левая часть этой строки – это ключ, по которому мы будем получать строку, стоящую в правой части.

Мы хотим чтобы ресурсы были доступны из страниц web-приложения, для этого нам необходимо создать конфигурационный файл faces-config.xml в директории WEB-INF и определить в нем наши ресурсы. Как я уже говорил в начале, IDEA полностью поддерживает JSF 2. Щелкните правой кнопкой на WEB-INF и выберите в меню New пункт Faces Config. IDEA создаст xml-документ в который нам нужно добавить описание ресурсов.

Делается это следующим образом:

<?xml version='1.0' encoding='UTF-8'?>
 
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
              version="2.0">
 
    <application>
        <locale-config>
            <default-locale>ru</default-locale>
            <!--<supported-locale>en</supported-locale>-->
        </locale-config>
 
        <resource-bundle>
            <base-name>messages.messages</base-name>
            <var>msgs</var>
        </resource-bundle>
    </application>
 
</faces-config>

В блоке locale-config определяется локаль по умолчанию и поддерживаемые локали. У нас локаль только одна, поэтому я закоментировал тэг supported-locale.

В блоке resource-bundle в тэге base-name прописывается путь до файла с сообщениями, а в тэге var – имя переменной, с помощью которой мы будем обращаться к ресурсному бандлу.

Создание главной страницы

Теперь, чтобы протестировать работу ресурсов, нам нужна jsf-страница. В webapp уже есть файл index.jsp, который и показывал нам строку “Hello World!” когда мы первый раз запускали приложение чтобы проверить работу Tomcat. В спецификации JSF написано что JSP (и даже JSPX) – это устаревшая технология для использования в JSF 2 и рекомендуется использовать xhtml.

Однако, файл index.jsp нам пригодится. Он будет входным файлом в web-приложение и будет выполнять функцию редиректа на greeting.xhtml – главную страницу сайта. Нужно все это потому, что при входе на сайт по URL http://localhost:8080/ страница greeting.xhtml загрузится, но компоненты JSF на ней не обработаются, так как упомянутый выше javax.faces.webapp.FacesServlet обрабатывает только те запросы, в URL которых есть шаблон /faces/*. Поэтому, необходимо сделать входную страницу index.jsp, которая выполнит редирект на http://localhost:8080/faces/greeting.xhtml.

Страница index.jsp выглядит следующим образом:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:forward page="/faces/greeting.xhtml" />

Теперь создайте в webapp файл greeting.xhtml и приведите его к следующему виду:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
        PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
 
<h:head>
    <title></title>
</h:head>
 
<h:body>
    <h:outputText value="#{msgs['hello.world']}" />
</h:body>
</html>

Если в тэге html в определении пространств имен xmlns у вас всё красное, нажмите Alt + Enter и выберите пункт Enable Facelets Support. Теперь IDEA знает что вы работаете с JSF-проектом и больше капризничть не будет.

Чтобы убедиться, что технология ресурсов работает, нужно снова нажать Run. Если Tomcat у вас уже запущен, то IDEA предложит или передеплоить приложение, или перезапустить Tomcat. Нам будет достаточно передеплоить. После того как приложение развернется, главная страница уже не запустится в браузере, т.к. IDEA считает что она у нас уже открыта после первого деплоя. Необходимо перейти в браузер и обновить страницу. Вы должны увидеть тот же “Hello world”, однако, уже более технологичный.

Навигация

В JSF 1.2 навигационные правила явно определялись в faces-config.xml. В JSF 2 у нас есть альтернатива – неявная навигация. Например, если контроллер (управляемый бин, ManagedBean) вернул строку “response”, она автоматически мапится на файл /response.xhtml.

Давайте немного изменим greeting.xhtml, добавив в тело (body) следующий код:

<h:form id="form">
    <h:commandLink action="#{sampleBean.storeMessage}">Go to hello world</h:commandLink>
</h:form>

Здесь мы создали форму с командной ссылкой (есть еще не командная), которая выполняет POST формы, в результате чего выполняется метод storeMessage класса SampleBean. Этот метод получает сообщение из нашего ресурсного бандла и возвращает строку “response”, поэтому JSF рендерит страницу response.xhtml.

Класс SampleBean приведен ниже:

package ru.topcode;
 
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import java.util.ResourceBundle;
 
@ManagedBean
public class SampleBean {
    private String message;
 
    public String storeMessage() {
        FacesContext context = FacesContext.getCurrentInstance();
        ResourceBundle bundle = context.getApplication().getResourceBundle(context, "msgs");
        message = bundle.getString("hello.world");
 
        return "response";
    }
 
    public String getMessage() {
        return message;
    }
}

Страница response.xhtml выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
        PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
 
<h:head>
    <title>Hello JSF Response</title>
</h:head>
 
<h:body>
    Message: #{sampleBean.message}
</h:body>
</html>

Теперь можно выполнить Redeploy и посмотреть как все работает.

Вот и все. Здесь мы научились создавать JSF2-web-приложения, работать с ресурсами и немного изучили технологию навигации.