«1. Обзор

В этой статье мы рассмотрим рецепт доступа к bean-компонентам, определенным в Spring, из управляемого bean-компонента JSF и страницы JSF с целью делегирования выполнения бизнес-логики bean-компонентам Spring.

В этой статье предполагается, что читатель имеет предварительное представление о JSF и Spring по отдельности. Статья основана на реализации JSF в Mojarra.

2. В Spring

Пусть следующий bean-компонент определен в Spring. Компонент UserManagementDAO добавляет имя пользователя в хранилище в памяти и определяется следующим интерфейсом:

public interface UserManagementDAO {
    boolean createUser(String newUserData);
}

Реализация компонента настраивается с использованием следующей конфигурации Java:

public class SpringCoreConfig {
    @Bean
    public UserManagementDAO userManagementDAO() {
        return new UserManagementDAOImpl();
    }
}

Или с помощью следующего Конфигурация XML:

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean class="com.baeldung.dao.UserManagementDAOImpl" id="userManagementDAO"/>

Мы определяем bean-компонент в XML и регистрируем CommonAnnotationBeanPostProcessor, чтобы гарантировать получение аннотации @PostConstruct.

3. Конфигурация

В следующих разделах объясняются элементы конфигурации, обеспечивающие интеграцию контекстов Spring и JSF.

3.1. Конфигурация Java Без web.xml

Реализуя WebApplicationInitializer, мы можем программно настроить ServletContext. Ниже приведена реализация onStartup() внутри класса MainWebAppInitializer:

public void onStartup(ServletContext sc) throws ServletException {
    AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
    root.register(SpringCoreConfig.class);
    sc.addListener(new ContextLoaderListener(root));
}

AnnotationConfigWebApplicationContext загружает контекст Spring’g и добавляет компоненты путем регистрации класса SpringCoreConfig.

Точно так же в реализации Mojarra есть класс FacesInitializer, который настраивает FacesServlet. Для использования этой конфигурации достаточно расширить FacesInitializer. Полная реализация MainWebAppInitializer теперь выглядит следующим образом:

public class MainWebAppInitializer extends FacesInitializer implements WebApplicationInitializer {
    public void onStartup(ServletContext sc) throws ServletException {
        AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
        root.register(SpringCoreConfig.class);
        sc.addListener(new ContextLoaderListener(root));
    }
}

3.2. С web.xml

Мы начнем с настройки ContextLoaderListener в файле web.xml приложения:

<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

Этот прослушиватель отвечает за запуск контекста приложения Spring при запуске веб-приложения. Этот слушатель будет искать файл конфигурации spring с именем applicationContext.xml по умолчанию.

3.3. Faces-config.xml

Теперь мы настроим SpringBeanFacesELResolver в файле face-config.xml:

<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>

Преобразователь EL — это подключаемый компонент, поддерживаемый инфраструктурой JSF, что позволяет нам настраивать поведение JSF. время выполнения при оценке выражений языка выражений (EL). Этот преобразователь EL позволит среде выполнения JSF получать доступ к компонентам Spring через выражения EL, определенные в JSF.

4. Доступ к Spring Bean-компонентам в JSF

На этом этапе наше веб-приложение JSF подготовлено для доступа к Spring-бину либо из вспомогательного JSF-бина, либо со страницы JSF.

4.1. Из резервного компонента JSF 2.0

Доступ к компоненту Spring теперь можно получить из резервного компонента JSF. В зависимости от версии JSF, которую вы используете, есть два возможных метода. В JSF 2.0 вы используете аннотацию @ManagedProperty для управляемого компонента JSF.

@ManagedBean(name = "registration")
@RequestScoped
public class RegistrationBean implements Serializable {
    @ManagedProperty(value = "#{userManagementDAO}")
    transient private IUserManagementDAO theUserDao;

    private String userName;
    // getters and setters
}

public void createNewUser() {
    FacesContext context = FacesContext.getCurrentInstance();
    boolean operationStatus = userDao.createUser(userName);
    context.isValidationFailed();
    if (operationStatus) {
        operationMessage = "User " + userName + " created";
    }
}

Обратите внимание, что геттер и сеттер являются обязательными при использовании @ManagedProperty. Теперь, чтобы подтвердить доступность bean-компонента Spring из управляемого bean-компонента, мы добавим метод createNewUser():

Суть метода заключается в использовании bean-компонента Spring userDao и доступе к его функциям.

4.2. Из резервного компонента в JSF 2.2

Другой подход, допустимый только в JSF2.2 и выше, заключается в использовании аннотации CDI @Inject. Это применимо к управляемым компонентам JSF (с аннотацией @ManagedBean) и компонентам, управляемым CDI (с аннотацией @Named).

@Named( "registration")
@RequestScoped
public class RegistrationBean implements Serializable {
    @Inject
    UserManagementDAO theUserDao;
}

Действительно, с аннотацией CDI это единственный допустимый метод внедрения бина:

При таком подходе геттер и сеттер не нужны. Также обратите внимание, что выражение EL отсутствует.

4.3. Из представления JSF

<h:form>
    <h:panelGrid id="theGrid" columns="3">
        <h:outputText value="Username"/>
        <h:inputText id="firstName" binding="#{userName}" required="true"
          requiredMessage="#{msg['message.valueRequired']}" value="#{registration.userName}"/>
        <h:message for="firstName" style="color:red;"/>
        <h:commandButton value="#{msg['label.saveButton']}" action="#{registration.createNewUser}"
          process="@this"/>
        <h:outputText value="#{registration.operationMessage}" style="color:green;"/>
    </h:panelGrid>
</h:form>

Метод createNewUser() будет запущен со следующей страницы JSF:

http://localhost:8080/jsf/index.jsf

Чтобы отобразить страницу, запустите сервер и перейдите к:

<h:commandButton value="Save"
  action="#{registration.userDao.createUser(userName.value)}"/>

Мы также можем использовать EL в представлении JSF для доступа к компоненту Spring. Для проверки достаточно изменить строку номер 7 из введенной ранее JSF-страницы на:

«

«Здесь мы вызываем метод createUser непосредственно в Spring DAO, передавая значение привязки userName методу со страницы JSF, полностью обходя управляемый компонент.

5. Заключение

Мы рассмотрели базовую интеграцию между контекстами Spring и JSF, где мы можем получить доступ к bean-компоненту Spring в bean-компоненте JSF и странице.

Стоит отметить, что, хотя среда выполнения JSF предоставляет подключаемую архитектуру, которая позволяет платформе Spring предоставлять компоненты интеграции, аннотации из среды Spring нельзя использовать в контексте JSF и наоборот.