Java EE 6:如何在应用程序客户端上添加Web模块

Tha*_*ham 7 jsf netbeans ejb jpa java-ee

Technology(Java EE 6 with Glassfish 3.1, Netbeans 7.0)

我有一个通过JPA访问数据库的应用程序客户端.没EJB涉及.现在我需要为此应用程序客户端添加Web界面.所以我会选择使用JSF 2.x.我对这里的设计有些担心,我希望社区能帮助我.因此,感谢BalusC,我可以通过transaction-type=RESOURCE_LOCAL在persistence.xml中指定在独立的客户端应用程序中使用JPA.以下是演示:

编辑以下代码已根据BalusC建议进行了编辑

这是我的App客户端 main

public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("CoreInPU");
    EntityManager em = emf.createEntityManager();
    EntityDAO entityDAOClient = new EntityDAOClient(em);
    Main pgm = new Main();
    try {
        process(entityDAOClient);
    } catch (Exception e) {
        logger.fatal("", e);
    }finally{
        em.close();
        emf.close();
    }
}

public void process(EntityDAO entityDAO){
    validatePDF(List<pdfFiles>);
    processPDF(List<pdfFiles>, entityDAO);
    createPrintJob(List<pdfFiles>, entityDAO);
}

public void processPDF(List<pdfFiles>, EntityDAO entityDAO){
    for(File file : pdfFiles){
        entityDAO.create(file);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是DAO我的App Client中的界面类

public interface EntityDAO {
    public <T> T create(T t);
    public <T> T find(Class<T> type, Object id);
    public List findWithNamedQuery(String queryName);
    public List findWithNamedQuery(String queryName, int resultLimit);

}
Run Code Online (Sandbox Code Playgroud)

这是App Client DAO

public class EntityDAOClient implements EntityDAO {

    private EntityManager em;

    private static Logger logger = Logger.getLogger(EntityDAOClient.class);

    public EntityDAOClient(EntityManager em) {
        this.em = em;
    }

    @Override
    public <T> T create(T t){
        em.getTransaction().begin();
        em.persist(t);
        em.getTransaction().commit();
        return t;
    }

    @Override
    public <T> T find(Class<T> type, Object id){
        em.getTransaction().begin();
        T t = em.find(type, id);
        em.getTransaction().commit();
        return t;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

这是 persistence.xml

<persistence-unit name="CoreInPU" transaction-type="RESOURCE_LOCAL">
   <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
   <class>com.wf.docsys.core.entity.Acknowledgement</class>
   <class>com.wf.docsys.core.entity.PackageLog</class>
   <properties>
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/core"/>
      <property name="javax.persistence.jdbc.password" value="root"/>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
      <property name="javax.persistence.jdbc.user" value="xxxx"/>
      <property name="eclipselink.ddl-generation" value="create-tables"/>
   </properties>
</persistence-unit>
Run Code Online (Sandbox Code Playgroud)

现在我需要在此基础上添加一个Web模块.我知道我需要JTA交易类型,所以我创建一个EAR项目的呼叫foofoo_ejbfoo_war它.所以我的EJB看起来像这样.

@Stateless
@LocalBean
public class CoreEJB implements EntityDAO{

    @PersistenceContext(unitName = "CoreInWeb-ejbPU")
    private EntityManager em;

    //@Override
    public <T> T create(T t) {
        em.persist(t);
        return t;
    }

    //@Override
    public <T> T find(Class<T> type, Object id) {
        return em.find(type, id);
    } 

    ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,这CoreInWeb-ejbPU是具有JTA事务类型的新persistence.xml单元名称.我还将我的app客户端jar文件添加到foo_ejb包中.当我部署时,我得到了这个消息Invalid ejb jar [foo-ejb.jar]: it contains zero ejb.正因为如此@Stateless public class CoreEJB implements EntityDAO.如果我implements EntityDAO拿出它然后是部署,但我需要EJB实现,EntityDAO以便在我的托管bean中我可以做到这一点

@ManagedBean
@RequestScoped
public class Bean {

   @EJB
   private CoreEJB coreEJB;


   public Bean() {

   }

   public void runAppClientMainProcess() { 
       //The web interface can also kick off the same process as the app client
       process(coreEJB);
   }

   // ...
}
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能正确?请帮忙

我知道我可能会在这里问太多,但如果您可以根据我上面的结构,告诉我如何添加一个Web模块,我将非常感激.有些代码会很棒.我还在学习,所以如果我的设计有缺陷,请随意撕开它,如果我说服有更好的方法来实现这一点,我会重新设计一切.底线是,有一组业务逻辑,我想通过访问这两个application clientweb interface.就像glassfishv3有web界面和管理控制台一样

Bal*_*usC 6

你能告诉我在哪里可以使用transaction-type ="JTA"放置/创建另一个persistence.xml吗?在我的web模块中,还是创建一个单独的EJB?

它并没有什么不同.它仍然需要进入/META-INF/persistence.xml文件.如果您的项目代表WAR,请将其放在Web项目中.或者如果它代表EAR,则将其放在EJB项目中.


在JSF中,我使用Managed Bean,我的托管bean如何从EntityUtil调用方法?我问这个问题,因为通常我在某处有一个EJB,所以如果我想让我的Managed bean访问它,我会使用@EJB注释注入EJB.由于EntityUtil未注释为EJB,我如何从Managed Bean访问它?

理论上讲,您可以创建一个新的EJB来组成/委托EntityUtil,然后将这个EJB注入到托管bean中.

@Stateless
public class SomeEJB {

    @PersistenceUnit(unitName="someWebPU")
    private EntityManagerFactory emf;

    @PostConstruct
    public void init() {
        EntityUtil.newInstance(emf);
    }

    public void create(Some some) {
        EntityUtil.create(some);
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

但是......你EntityUtil线程并不安全.你身上的一切EntityUtil都是static.Java EE Web应用程序是一个严重多线程的环境.多个并发用户同时使用相同的代码库.所有公开暴露的静态变量都在所有用户之间共享.当用户呼叫close()您时EntityUtil,它将影响该Webapp的所有当前用户.所以忙于交易的人会得到一个例外.

无论是客户端还是Web应用程序,您都应该EntityManagerFactory在应用程序的启动时创建一次,在整个应用程序的生命周期内重用相同的实例,并仅在应用程序关闭时关闭它.在EntityManager每笔交易或会话中创建的需求只有一次,通过交易或会话的年底前关闭.在具有JTA事务类型的Java EE 6中,事务由容器完全管理.但是在具有资源本地事务类型的客户端应用程序中,您需要自己管理事务.

我建议你重写EntityUtil一个类似DAO的界面,这个界面旨在为客户端应用程序和Web应用程序提供不同的实现.

public interface SomeDAO {

    public void save(Some some);
    // ...
}
Run Code Online (Sandbox Code Playgroud)

以下是如何为客户端应用程序实现它:

public class SomeDAOClient implements SomeDAO {

    private EntityManager em;

    public SomeDAO(EntityManager em) { 
        this.em = em;
    }

    public void save(Some some) {
        em.getTransaction().begin();
        em.persist(some);
        em.getTransaction().commit();
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

并按如下方式使用:

public static void main(String[] args) throws Exception {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("someClientPU");
    EntityManager em = emf.createEntityManager();
    SomeDAO someDAO = new SomeDAOClient(em);

    try {
        Some some = new Some();
        some.setFoo("foo");
        someDAO.save(some);
    } finally {
        em.close();
        emf.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是如何为Web应用程序实现它:

@Stateless
public class SomeDAOEJB implements SomeDAO {

    @PersistenceContext(unitName="someWebPU")
    private EntityManager em;

    public void save(Some some) {
        em.persist(some);
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

并按如下方式使用它

@ManagedBean
@RequestScoped
public class Bean {

    @EJB
    private SomeDAO someDAO;
    private Some some;

    public Bean() {
        some = new Some();
    }

    public void save() {
        someDAO.save(some);
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)


Tha*_*ham 0

我想为我迟到的回复表示歉意。我的另一个项目落后于计划,所以我没有时间写适当的回应BalusCkiran答案。

kiran问我这个:Case 2 - Web Module - You have used(want to use) jsf for presentation , CoreEJB for persistence -- i am not clear where you intend to put business logic, for now ill take is as another ejb class.

回答:嗨 kiran,底线是,我希望在应用程序客户端和 Web 模块端访问相同的逻辑集。就像 glassfish 应用服务器一样。您有访问相同资源的命令行版本和 Web 模块版本。

BalusCRESOURCE_LOCAL如果我只使用应用程序客户端,建议使用工作很棒。然而,一旦我在其上添加了 Web 模块,即使 BalusC 确实尝试与我合作,我也无法再让它工作了。你们可以阅读 BalusC 的回复和我上面的想法的实现(原帖中的代码是我对 BalusC 想法的实现)。如果我将应用程序客户端添加到 Java EE 项目 (EAR) 类路径中,当我尝试从应用程序客户端访问逻辑时,它不会收到编译错误,但当我运行 Web 模块时,它会生成异常,表示它没有看到我尝试从应用程序客户端访问的类/方法。因此,我决定将所有逻辑移植到 EJB 上,并使我的应用程序客户端变得非常精简。逻辑将通过javax.ejb.Remote接口暴露给App Client,并通过接口暴露给Web模块javax.ejb.Local。下面是我对这个想法的总体布局。

这是我的thin应用程序客户端(主)

public class Main {

    @EJB
    private static CoreMainEJBRemote coreEJBRemote;

    private static Logger logger = Logger.getLogger(Main.class);

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
         coreEJBRemote.process(args[0]);
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,在我的 EJB 端,在包含 EJB 和 Web 模块的 Java EE 项目 (EAR) 内的包中,我有

@Stateless
public class CoreMainEJB implements CoreMainEJBRemote, CoreMainEJBLocal {

    @EJB
    private PackageProcessor packageProcessor;

    @Override
    public void process(String configFileName) {
         ...
         //Process config File
         packageProcessor.validatePDF();
         packageProcessor.processPDF();
         ...
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,由于所有逻辑现在都位于 EJB 内部,因此我可以使用JTA由容器管理的事务类型。我比自己管理更喜欢这种方式。

有些人建议通过 RESTful 公开业务逻辑。由于我不太了解 RESTful,所以我现在将继续使用此实现。感谢您的所有帮助BalusCkiran