Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Пример producerfields: использование полей-производителей для создания ресурсов

Пример providerfields, позволяющий создавать список дел, показывает, как использовать поле-производитель для генерации объектов, которыми затем может управлять контейнер. В этом примере создаётся объект EntityManager, но ресурсы, такие как соединения JDBC и источники данных, также могут быть сгенерированы таким образом.

Пример providerfields — самый простой пример сущности. Он также содержит квалификатор и класс, который генерирует EntityManager. Он также содержит один объект, сессионный компонент с состоянием, страницу Facelets и Managed-бин.

Исходные файлы находятся в каталоге tut-install/examples/cdi/providerfields/src/main/java/javaeetutorial/providerfields/.

Здесь рассматриваются следующие темы:

Пример поля-производителя для producerfields

Наиболее важным компонентом примера providerfields является самый маленький класс db.UserDatabaseEntityManager, который изолирует генерацию объекта EntityManager, чтобы он мог легко использоваться другими компонентами в приложении. Класс использует поле источника, чтобы инъецировать EntityManager с аннотацией @UserDatabase, также определённой в пакете db:

@Singleton
public class UserDatabaseEntityManager {

    @Produces
    @PersistenceContext
    @UserDatabase
    private EntityManager em;
    ...
}

Класс не создаёт поле юнит персистентности явным образом, но в приложении есть файл persistence.xml, в котором описан юнит персистентности. Класс аннотирован javax.inject.Singleton, чтобы указать контейнеру, что объект этого класса должен быть инстанцирован только один раз.

Класс db.UserDatabaseEntityManager также содержит закомментированный код, который использует методы create и close для генерации и удаления поля источника:

 /* @PersistenceContext
    private EntityManager em;

    @Produces
    @UserDatabase
    public EntityManager create() {
        return em;
    } */

    public void close(@Disposes @UserDatabase EntityManager em) {
        em.close();
    }

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

Преимущество создания EntityManager в отдельном классе, а не просто встраивание его в Enterprise-бин, состоит в том, что пользовать объект повторно можно легко и типобезопасно (typesafe). Кроме того, более сложное приложение может создавать несколько EntityManager-ов с использованием нескольких юнитов персистентности, и этот механизм изолирует этот код для простоты обслуживания, как в следующем примере:

@Singleton
public class JPAResourceProducer {
    @Produces
    @PersistenceUnit(unitName="pu3")
    @TestDatabase
    EntityManagerFactory customerDatabasePersistenceUnit;

    @Produces
    @PersistenceContext(unitName="pu3")
    @TestDatabase
    EntityManager customerDatabasePersistenceContext;

    @Produces
    @PersistenceUnit(unitName="pu4")
    @Documents
    EntityManagerFactory customerDatabasePersistenceUnit;

    @Produces
    @PersistenceContext(unitName="pu4")
    @Documents
    EntityManager docDatabaseEntityManager;"
}

Объявления EntityManagerFactory также позволяют использовать EntityManager, управляемый приложением.

Сущность и сессионный бин примера producerfields

Пример providerfields содержит простой класс сущности entity.ToDo и сессионный компонент с состоянием ejb.RequestBean, который его использует.

Класс сущности содержит три поля: автогенерируемое поле id, строку, задающую задачу, и метку времени. Поле метки времени timeCreated помечено аннотацией @Temporal, которая необходима для полей Date.

@Entity
public class ToDo implements Serializable {

    ...
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    protected String taskText;
    @Temporal(TIMESTAMP)
    protected Date timeCreated;

    public ToDo() {
    }

    public ToDo(Long id, String taskText, Date timeCreated) {
        this.id = id;
        this.taskText = taskText;
        this.timeCreated = timeCreated;
    }
    ...

Остальная часть класса ToDo содержит обычные методы получения, установки и другие методы сущностей.

Класс RequestBean инъецирует EntityManager, созданный методом-производителем, с аннотацией @UserDatabase:

@ConversationScoped
@Stateful
public class RequestBean {

    @Inject
    @UserDatabase
    EntityManager em;

Затем он определяет два метода, один из которых создаёт и сохраняет один элемент списка ToDo, а другой — получает все элементы ToDo, созданные на данный момент, путём создания запроса:

    public ToDo createToDo(String inputString) {
        ToDo toDo = null;
        Date currentTime = Calendar.getInstance().getTime();

        try {
            toDo = new ToDo();
            toDo.setTaskText(inputString);
            toDo.setTimeCreated(currentTime);
            em.persist(toDo);
            return toDo;
        } catch (Exception e) {
            throw new EJBException(e.getMessage());
        }
    }

    public List<ToDo> getToDos() {
        try {
             List<ToDo> toDos =
                    (List<ToDo>) em.createQuery(
                    "SELECT t FROM ToDo t ORDER BY t.timeCreated")
                    .getResultList();
            return toDos;
        } catch (Exception e) {
            throw new EJBException(e.getMessage());
        }
    }
}

producerfields — страницы Facelets и Managed-бин

В примере providerfields есть две страницы Facelets, index.xhtml и todolist.xhtml. Простая форма на странице index.xhtml запрашивает у пользователя только задачу. Когда пользователь кликает кнопку «Submit», вызывается метод listBean.createTask. Когда пользователь кликает кнопку «Show Items», действие указывает, что должен отображаться файл todolist.xhtml:

    <h:body>
        <h2>To Do List</h2>
        <p>Enter a task to be completed.</p>
        <h:form id="todolist">
            <p><h:outputLabel value="Enter a string: " for="inputString"/>
                <h:inputText id="inputString"
                             value="#{listBean.inputString}"/></p>
            <p><h:commandButton value="Submit"
                                action="#{listBean.createTask()}"/></p>
            <p><h:commandButton value="Show Items"
                                action="todolist"/></p>
        </h:form>
        ...
    </h:body>

Managed-бин web.ListBean инъецирует сессионный бин ejb.RequestBean. Он объявляет сущность entity.ToDo и список сущностей вместе со входной строкой, которую он передаёт в сессионный компонент. inputString аннотируется ограничением @NotNull Bean Validation, поэтому попытка отправить пустую строку приведёт к ошибке.

@Named
@ConversationScoped
public class ListBean implements Serializable {

    ...
    @EJB
    private RequestBean request;
    @NotNull
    private String inputString;
    private ToDo toDo;
    private List<ToDo> toDos;

Метод createTask, обработчик нажатия кнопки Submit, вызывает метод createToDo RequestBean:

    public void createTask() {
        this.toDo = request.createToDo(inputString);
    }

Метод getToDos, который вызывается страницей todolist.xhtml, в свою очередь вызывает метод getToDos RequestBean:

public List<ToDo> getToDos() {
        return request.getToDos();
    }

Чтобы заставить страницу Facelets распознавать пустую строку как нулевое значение и возвращать ошибку, файл web.xml устанавливает контекстный параметр javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL в true:

<context-param>
  <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
  <param-value>true</param-value>
</context-param>

Страница todolist.xhtml немного сложнее, чем страница index.html. Она содержит элемент dataTable, который отображает содержимое списка ToDo. Тело страницы выглядит так:

    <body>
        <h2>To Do List</h2>
        <h:form id="showlist">
            <h:dataTable var="toDo"
                         value="#{listBean.toDos}"
                         rules="all"
                         border="1"
                         cellpadding="5">
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Time Stamp" />
                    </f:facet>
                    <h:outputText value="#{toDo.timeCreated}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Task" />
                    </f:facet>
                    <h:outputText value="#{toDo.taskText}" />
                </h:column>
            </h:dataTable>
            <p><h:commandButton id="back" value="Back" action="index" /></p>
        </h:form>
    </body>

Значением dataTable является listBean.toDos — список, возвращаемый методом getToDos Managed-бина, который в свою очередь вызывает метод сессионного компонента getToDos. В каждой строке таблицы отображаются поля timeCreated и taskText отдельной задачи. Наконец, кнопка «Back» возвращает пользователя на страницу index.xhtml.

Запуск producerfields

Вы можете использовать IDE NetBeans или Maven для сборки, упаковки, развёртывания и запуска приложения providerfields.

Здесь рассматриваются следующие темы:

Сборка, упаковка и развёртывание producerfields с использованием IDE NetBeans

  1. Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).

  2. Если сервер базы данных ещё не запущен, запустите его, следуя инструкциям в Запуск и остановка Apache Derby.

  3. В меню «Файл» выберите «Открыть проект».

  4. В диалоговом окне «Открыть проект» перейдите к:

    tut-install/examples/cdi
  5. Выберите каталог providerfields.

  6. Нажмите Открыть проект.

  7. На вкладке «Проекты» кликните правой кнопкой мыши проект providerfields и выберите «Сборка».

    Эта команда собирает и упаковывает приложение в WAR-файл providerfields.war, расположенный в каталоге target, а затем развёртывает его на сервере GlassFish.

Сборка, упаковка и развёртывание producerfields с использованием Maven

  1. Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).

  2. Если сервер базы данных ещё не запущен, запустите его, следуя инструкциям в Запуск и остановка Apache Derby.

  3. В окне терминала перейдите в:

    tut-install/examples/cdi/producerfields/
  4. Введите следующую команду для развёртывания приложения:

    mvn install

    Эта команда собирает и упаковывает приложение в WAR-файл providerfields.war, расположенный в каталоге target, а затем развёртывает его на сервере GlassFish.

Запуск producerfields

  1. В веб-браузере введите следующий URL:

    http://localhost:8080/producerfields
  2. На странице «Создать список дел» введите строку в поле и нажмите «Отправить».

    Вы можете ввести дополнительные строки и нажать «Отправить», чтобы создать список задач с несколькими элементами.

  3. Нажмите Показать элементы.

    Откроется страница «Список дел», показывающая метку времени и текст для каждого созданного вами элемента.

  4. Нажмите «Назад», чтобы вернуться на страницу «Создать список дел».

    На этой странице можно ввести дополнительные элементы в список.


Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)