jsf - Java EE 6 : How to add web module on top of application client

标签 jsf jpa netbeans jakarta-ee ejb

技术(Java EE 6 与 Glassfish 3.1、Netbeans 7.0)

我有一个通过 JPA 访问数据库的应用程序客户端。不涉及EJB。现在我需要为此应用程序客户端添加一个 Web 界面。所以我会选择使用JSF 2.x。我对这里的设计有一些担忧,我希望社区能够帮助我。 So thanks to BalusC, I am able to use JPA in a stand alone client application通过在 persistence.xml 中指定 transaction-type=RESOURCE_LOCAL 。下面是演示:

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

这是我的应用程序客户端 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);
    }
}

这是我的App Client中的DAO接口(interface)类

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);

}

这是应用程序客户端 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;
    }
    ...
}

这是 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>

现在我需要在此基础上添加一个网络模块。我知道我需要 JTA 事务类型,因此我创建了一个 EAR 项目调用 foo,其中包含 foo_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);
    } 

    ...
}

请注意,CoreInWeb-ejbPU 是具有 JTA 事务类型的新 persistence.xml 单元名称。我还将我的应用程序客户端 jar 文件添加到 foo_ejb 包中。 当我部署时,我收到此消息无效的ejb jar [foo-ejb.jar]:它包含零ejb。这是因为这个@Stateless公共(public)类CoreEJB实现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);
   }

   // ...
}

我怎样才能正确地做到这一点?请帮忙

我知道我在这里可能要求太多,但如果您能根据我上面的结构,向我展示如何添加网络模块,我将不胜感激。有些代码会很棒。 我仍在学习,所以如果我的设计有缺陷,请随意撕掉它,如果我确信有更好的方法来实现这一点,我将重新设计一切。底线是,有一组业务逻辑,我想通过应用程序客户端Web界面访问这些逻辑。就像 glassfishv3 如何拥有 Web 界面和管理控制台

最佳答案

Can you guys tell me where should I put/create another persistence.xml with transaction-type="JTA"? Inside my web module, or create a separate EJB?

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

<小时/>

In JSF, I use Managed Bean, how would my managed bean invoke method from EntityUtil? I ask this question because usually I have a EJB somewhere, so if I want my Managed bean to access it, I inject EJB using @EJB annotation. Since EntityUtil is not annotated to be EJB, how I can access it from Managed Bean?

理论中,您可以创建一个新的 EJB,它组成/委托(delegate) EntityUtil,然后将此 EJB 注入(inject)到托管 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);
    }

    // ...
}

但是...您的EntityUtil不是线程安全的EntityUtil 中的所有内容都是静态。 Java EE Web 应用程序是一个高度多线程的环境。多个并发用户同时使用相同的代码库。所有公开暴露的静态变量都在所有用户之间共享。当用户在 EntityUtil 上调用 close() 时,它将影响该 Web 应用程序的所有当前用户。因此那些忙于交易的人会得到一个异常(exception)。

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

我建议将您的 EntityUtil 重写为类似 DAO 的接口(interface),该接口(interface)旨在为客户端应用程序和 Web 应用程序提供不同的实现。

public interface SomeDAO {

    public void save(Some some);
    // ...
}

以下是为客户端应用程序实现它的方法:

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();
    }

    // ...
}

并按如下方式使用它:

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();
    }
}

以下是如何在网络应用程序中实现它:

@Stateless
public class SomeDAOEJB implements SomeDAO {

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

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

    // ...
}

并按如下方式使用

@ManagedBean
@RequestScoped
public class Bean {

    @EJB
    private SomeDAO someDAO;
    private Some some;

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

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

    // ...
}

关于jsf - Java EE 6 : How to add web module on top of application client,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6387475/

相关文章:

css - 如何在 JSF 中使用第三方 CSS 库,例如 Font Awesome?浏览器找不到 CSS 文件中引用的字体文件

jsf - javax.faces.FacesException 无法找到 CDI BeanManager

java - 从支持 bean 中关闭 JSP 弹出窗口?

java - 基于列值的 JPA 目标实体类型

java - Netbeans scala 插件 - 无文档

jsf - f :validateWholeBean in JSF 2. 3

java - 是否有更好的解决方案将大量字段实体映射到两个表中?

java - Hibernate JPA,连接多个表

java - Netbeans 中使用 JSTL 的代码提示

java - 新的 jre、jdk 更新后,无法在 Netbeans 中生成 jar