技术(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_ejb
和 foo_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/