Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Jakarta Faces

Jakarta Faces (раньше JSF) — технология серверных HTML-страниц из компонентов. Страница описывается в XHTML-файле, данные и действия берутся из бина, а сервер сам собирает HTML, принимает формы и проверяет поля. Новые интерфейсы сегодня чаще делают на JavaScript поверх REST API, но на Faces написано множество корпоративных систем, и поддерживать их приходится до сих пор. Этот урок — знакомство с основами.

Включение Faces

Faces включается аннотацией @FacesConfig на любом бине приложения:

// src/main/java/com/example/blog/FacesActivator.java
package com.example.blog;
 
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.faces.annotation.FacesConfig;
 
@FacesConfig
@ApplicationScoped
public class FacesActivator {
}

Бин страницы

Странице нужен объект, из которого она берёт данные. Аннотация @Named делает бин доступным на странице по имени postsPage — имени класса с маленькой буквы:

// src/main/java/com/example/blog/PostsPage.java
package com.example.blog;
 
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import java.util.List;
 
@Named
@RequestScoped
public class PostsPage {
 
    @Inject
    PostRepository repository;
 
    @Inject
    PostService service;
 
    private String title;
    private String body;
 
    public List<Post> getPosts() {
        return repository.findAll();
    }
 
    public String publish() {
        service.publish(new NewPost(title, body));
        return "posts?faces-redirect=true";
    }
 
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public String getBody() { return body; }
    public void setBody(String body) { this.body = body; }
}

Поля формы связываются с парой геттер–сеттер. Метод publish вызывается кнопкой и возвращает, куда перейти: faces-redirect=true просит браузер заново загрузить страницу, чтобы обновление не отправило форму второй раз.

Страница

Создайте файл src/main/webapp/posts.xhtml:

<!-- src/main/webapp/posts.xhtml -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="jakarta.faces.html"
      xmlns:ui="jakarta.faces.facelets">
<h:head>
    <title>Записи блога</title>
</h:head>
<h:body>
    <h1>Записи блога</h1>
 
    <ul>
        <ui:repeat value="#{postsPage.posts}" var="post">
            <li>#{post.title} (#{post.createdAt})</li>
        </ui:repeat>
    </ul>
 
    <h2>Новая запись</h2>
    <h:form id="postForm">
        <h:outputLabel for="title" value="Заголовок" />
        <h:inputText id="title" value="#{postsPage.title}" required="true" />
 
        <h:outputLabel for="body" value="Текст" />
        <h:inputTextarea id="body" value="#{postsPage.body}" />
 
        <h:commandButton value="Опубликовать" action="#{postsPage.publish}" />
        <h:messages />
    </h:form>
</h:body>
</html>

Выражения #{...} — язык выражений (Expression Language): #{postsPage.posts} вызывает getPosts(), #{postsPage.publish} — метод publish. Префиксы h: и ui: подключают библиотеки компонентов.

Результат

Откройте http://localhost:8080/blog/posts.xhtml. Сервер отдаст обычный HTML — список и форму:

<ul>
        <li>Привет, Jakarta EE (2026-10-01)</li>
        <li>Сервлеты и фильтры (2026-10-02)</li>
</ul>
<h2>Новая запись</h2><form id="postForm" name="postForm" method="post" action="/blog/posts.xhtml" ...>

Заполните форму и нажмите «Опубликовать» — запись сохранится через тот же PostService, что и в REST API, и появится в списке. Если оставить заголовок пустым, required="true" не пропустит форму, а h:messages покажет сообщение об ошибке. На сервере с английской локалью оно выглядит так: postForm:title: Validation Error: Value is required.

Основные компоненты

КомпонентЧто выводит
h:formФорма
h:inputText, h:inputTextareaПоле ввода и многострочное поле
h:commandButtonКнопка, которая вызывает метод бина
h:outputTextТекст с экранированием HTML
h:dataTableТаблица по списку
h:messagesСообщения об ошибках
ui:repeatПовторение разметки для каждого элемента

Частая ошибка

Создать .xhtml-страницу, но не включить Faces. Без @FacesConfig (или файла WEB-INF/faces-config.xml) сервер отдаёт файл как есть, и браузер получает исходный текст с тегами h:body и выражениями #{postsPage.posts} вместо списка записей.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.