Я в основном новичок, начинающий работу над новым веб-приложением. Веб-приложение — это в основном ваши основные операции CRUD. Для этого я решил использовать JPA с Hibernate в качестве поставщика Persistence и буду разрабатывать на Apache Derby для целей разработки и тестирования. Я использую GlassFish v2 в качестве сервера приложений для развертывания своих компонентов EJB3. Для внешнего интерфейса я использую JSF (Visual JSF с темой Woodstock, которая поставляется в комплекте с NeatBeans v6.5)
Вот так я и поступал до сих пор. Я использую мастера NetBeans 6.5 по большей части для создания своих классов сущностей и сеансовых компонентов ejb. Что я делаю, так это создаю новую таблицу в Apache Derby, скажем, XXX. Затем я использую «Классы сущностей из базы данных» для создания класса сущностей XXX, который содержит все необходимые аннотации и методы получения и установки.
Затем я запускаю мастер «Класс контроллера JPA из классов сущностей», чтобы сгенерировать код класса контроллера, XXXJpaController, который содержит в основном следующее:
@Resource private UserTransaction utx = null;
@PersistenceUnit(unitName = "TestEnterpriseApplication-ejbPU") private EntityManagerFactory emf = null;
1. EntityManager getEntityManager() { return emf.createEntityManager() }
2. void create(XXX xxx) throws PreexistingEntityException, RollbackFailureException, Exception{}
3. void edit(XXX xxx) throws NonexistentEntityException, RollbackFailureException, Exception{}
4. void destroy(Long id) throws NonexistentEntityException, RollbackFailureException, Exception {}
5. List<XXX> findXXXEntities(){}
6. List<XXX> findXXXEntities(int maxResults, int firstResult) {}
7. List<XXX> findXXXEntities(boolean all, int maxResults, int firstResult){}
8. XXX findXXX(Long id){}
9. int getXXXCount(){}
Затем я запускаю мастер «Session Beans for Entity Classes», чтобы сгенерировать локальные/удаленные сеансовые компоненты EntityFacade, которые при необходимости могут быть вызваны внешним интерфейсом следующим образом:
@PersistenceContext private EntityManager em;
1. void create(XXX xxx) { em.persist(xxx); }
2. void edit(XXX xxx) { em.merge(xxx); }
3. void remove(XXX xxx) { em.remove(em.merge(xxx)); }
4. List<XXX> findAll() { return em.createQuery("select object(o) from XXX as o").getResultList(); }
Поскольку у меня уже есть сгенерированные классы Controller, которые реализуют эти методы с лучшей поддержкой try, catch и транзакций, я решил вызвать их в XXXFacade.java, как показано ниже:
XXXJpaController XXXController = new XXXJpaController();
1. public void create(XXX xxx) throws PreexistingEntityException, RollbackFailureException, Exception {
XXXController.create(xxx); }
2. public void edit(XXX xxx) throws NonexistentEntityException, RollbackFailureException, Exception{
XXXController.edit(xxx); }
3. public void remove(XXX xxx) throws NonexistentEntityException, RollbackFailureException, Exception{
XXXController.destroy(xxx.getId()); }
4. public XXX find(Object id) {
return XXXController.findXXX((Long)id); }
5. public List<XXX> findAll() {
return XXXController.findXXXEntities(); }
Итак, вот мой первый вопрос. Это правильный способ делать что-то в мире JEE или есть лучший способ сделать это? Я ввожу здесь какую-то избыточность? Это шаблон, которому я в значительной степени следовал для всех классов Entity: создать класс сущности -> создать класс контроллера -> создать класс entityfacade -> изменить класс entityfacade для вызова методов класса контроллера.
PS: я использую JTA
Это, в свою очередь, привело меня к другой проблеме. Все сгенерированные классы контроллеров имеют свои собственные методы getEntityManager(). Поэтому, чтобы избавиться от этой избыточности, я решил использовать вспомогательный класс по аналогии с HibernateUtil.java, который обычно встречается в руководствах по Hibernate (который действует как синглтон для sessionfactory). Поэтому я создал PersistenceUtil.java с методами getEntityManager() и getUserTransaction(), которые должны возвращать экземпляры EntityManager и UserTransaction для использования классами контроллера.
Вот где проблема. Я использую @PersistenceContext ((name="jpa/EntityManager") и @Resource (name="jta/UserTransaction") в классах XXXFacade. Таким образом, я могу получить доступ к записям JNDI для em и utx как из класса XXXFacade ( если мне нужно, хотя в моем случае я этого не делаю) и в вспомогательном классе XXXJpaController (через поиск jndi). Прочитав в Интернете, вот что я узнал. Вспомогательные классы должны использовать поиск JNDI в среде компонента bean ( java:comp/env), так как инъекция выполняется только для управляемых контейнером bean-компонентов, а не для неуправляемых вспомогательных классов. Это отлично работает для класса Controller, экземпляр которого создается в классе XXXFacade, как показано в приведенном выше коде. Однако я не могу использовать PersistenceUtil для поиска либо EntityManager, либо UserTransaction, поскольку я предполагаю, что это вспомогательный класс помощника. Что я могу сделать, чтобы обойти это и получить доступ к управляемому контейнером entitymanager и usertransaction в вспомогательном классе PersistenceUtil? Один из вариантов, который приходит мне на ум, также создать экземпляр класса Persistence в каждом классе XXXFacade (мне не нравится, как это звучит).
Единственный другой вариант, который я могу придумать, — это избавиться от класса Controller и переместить весь этот код в класс XXXFacade. Таким образом, мне даже не понадобится вспомогательный класс PersistenceUtil, поскольку я смогу напрямую внедрить его в сессионный компонент, верно?
Как я уже говорил в начале, я новичок. Я хочу услышать от всех вас, опытных и опытных ветеранов java/jee, совета по этому вопросу. Есть ли какой-то конкретный шаблон, который я могу использовать здесь?
Мне жаль, если что-то из этого не имеет для вас смысла. Пожалуйста, не стесняйтесь обращаться ко мне за любыми разъяснениями, и я буду более чем счастлив сделать это.