@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
На странице «Создать список дел» введите строку в поле и нажмите «Отправить».
Вы можете ввести дополнительные строки и нажать «Отправить», чтобы создать список задач с несколькими элементами.
Нажмите Показать элементы.
Откроется страница «Список дел», показывающая метку времени и текст для каждого созданного вами элемента.
Нажмите «Назад», чтобы вернуться на страницу «Создать список дел».
На этой странице можно ввести дополнительные элементы в список.
Назад | Вперёд | Содержание |