@Singleton
public class UserDatabaseEntityManager {
@Produces
@PersistenceContext
@UserDatabase
private EntityManager em;
...
}
|
Java Platform, Enterprise Edition (Java EE) 8 Учебник по Java EE |
| Назад | Вперёд | Содержание |
Пример providerfields, позволяющий создавать список дел, показывает, как использовать поле-производитель для генерации объектов, которыми затем может управлять контейнер. В этом примере создаётся объект EntityManager, но ресурсы, такие как соединения JDBC и источники данных, также могут быть сгенерированы таким образом.
Пример providerfields — самый простой пример сущности. Он также содержит квалификатор и класс, который генерирует EntityManager. Он также содержит один объект, сессионный компонент с состоянием, страницу Facelets и Managed-бин.
Исходные файлы находятся в каталоге tut-install/examples/cdi/providerfields/src/main/java/javaeetutorial/providerfields/.
Здесь рассматриваются следующие темы:
Наиболее важным компонентом примера 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, управляемый приложением.
Пример 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());
}
}
}
В примере 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.
Вы можете использовать IDE NetBeans или Maven для сборки, упаковки, развёртывания и запуска приложения providerfields.
Здесь рассматриваются следующие темы:
Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).
Если сервер базы данных ещё не запущен, запустите его, следуя инструкциям в Запуск и остановка Apache Derby.
В меню «Файл» выберите «Открыть проект».
В диалоговом окне «Открыть проект» перейдите к:
tut-install/examples/cdi
Выберите каталог providerfields.
Нажмите Открыть проект.
На вкладке «Проекты» кликните правой кнопкой мыши проект providerfields и выберите «Сборка».
Эта команда собирает и упаковывает приложение в WAR-файл providerfields.war, расположенный в каталоге target, а затем развёртывает его на сервере GlassFish.
Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).
Если сервер базы данных ещё не запущен, запустите его, следуя инструкциям в Запуск и остановка Apache Derby.
В окне терминала перейдите в:
tut-install/examples/cdi/producerfields/
Введите следующую команду для развёртывания приложения:
mvn install
Эта команда собирает и упаковывает приложение в WAR-файл providerfields.war, расположенный в каталоге target, а затем развёртывает его на сервере GlassFish.
В веб-браузере введите следующий URL:
http://localhost:8080/producerfields
На странице «Создать список дел» введите строку в поле и нажмите «Отправить».
Вы можете ввести дополнительные строки и нажать «Отправить», чтобы создать список задач с несколькими элементами.
Нажмите Показать элементы.
Откроется страница «Список дел», показывающая метку времени и текст для каждого созданного вами элемента.
Нажмите «Назад», чтобы вернуться на страницу «Создать список дел».
На этой странице можно ввести дополнительные элементы в список.
| Назад | Вперёд | Содержание |
Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены.
Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)