如何组织提供REST Web服务的JEE6企业应用程序?

从一个月前开始,我正在努力学习宁静的网络服务。 现在我练习了语法并理解了概念,我决定创建一个包含EJB,JPA和REST的非常简单的企业应用程序。 我正在努力尝试了解组织这种系统的最佳方法。 如果有经验的人可以给我一些关于什么是最佳实践的技巧,我会非常感激,以及如何解决我当前的问题。

我来告诉你这个形象吧。 抱歉,我无法获得更好的分辨率(使用Ctrl +鼠标向上滚动缩放):

在此处输入图像描述

如您所见,这是一个非常简单的企业应用程序,它有2个模块。

此应用程序不使用CDI(我希望在没有CDI帮助的情况下实现我的目标)

当某个客户端(任何可互操作的客户端)发送带有某些参数的@GET时,REST服务应将这些参数传递给EJB模块,该模块将在数据库中搜索并发回适当的数据。 最后,服务将在JAXB的帮助下自动编组,并将.XML发送回客户端。

我的问题如下:

  • 我得到一个ClassCastException,因为它在EJB模块中的实体与WebModule中的JAXB类不兼容(即使它们的变量是相同的)
  • 我不知道应该如何组织事情,所以前端可以整理和解组这些实体。
  • 应该是实体类在前端与JAXB映射相结合吗? 如果那时,就不会真正需要EJB模块。 但问题是,我想要EJB模块,因为我经常在那里进行CRUD操作。
  • 将EJB暴露为REST Web服务(制作混合)怎么样? 你认为这是个好主意吗? 它怎么能帮到我?
  • 再次,如果我在Web模块中创建JAXRS + EJB的混合,我必须在前端创建我的JPA实体,这是我以前从未做过的事情。 你认为这是一个好习惯吗?
  • 你有什么建议? 使用REST Web服务的企业应用程序的组织方式通常是什么?

下面是一个JAX-RS服务的示例,该服务作为会话bean实现,使用JPA进行持久化,而JAXB用于消息传递。 (注意一个EntityManager被注入会话bean,你为什么要避免这种行为?):

 package org.example; import java.util.List; import javax.ejb.*; import javax.persistence.*; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; @Stateless @LocalBean @Path("/customers") public class CustomerService { @PersistenceContext(unitName="CustomerService", type=PersistenceContextType.TRANSACTION) EntityManager entityManager; @POST @Consumes(MediaType.APPLICATION_XML) public void create(Customer customer) { entityManager.persist(customer); } @GET @Produces(MediaType.APPLICATION_XML) @Path("{id}") public Customer read(@PathParam("id") long id) { return entityManager.find(Customer.class, id); } @PUT @Consumes(MediaType.APPLICATION_XML) public void update(Customer customer) { entityManager.merge(customer); } @DELETE @Path("{id}") public void delete(@PathParam("id") long id) { Customer customer = read(id); if(null != customer) { entityManager.remove(customer); } } @GET @Produces(MediaType.APPLICATION_XML) @Path("findCustomersByCity/{city}") public List findCustomersByCity(@PathParam("city") String city) { Query query = entityManager.createNamedQuery("findCustomersByCity"); query.setParameter("city", city); return query.getResultList(); } } 

如果要在服务器和客户端使用相同的域对象。 然后我将通过XML而不是注释提供JPA映射,以避免客户端上的类路径依赖。

了解更多信息

  • 第1部分 – 数据模型
  • 第2部分 – JPA
  • 第3部分 – JAXB(使用MOXy)
  • 第4部分 – RESTful服务(使用EJB会话bean)
  • 第5部分 – 客户

UPDATE

META-INF / persistence.xml中

您可以在persistence.xml文件中指定包含JPA映射的XML文件的链接:

  org.eclipse.persistence.jpa.PersistenceProvider CustomerService META-INF/orm.xml  

META-INF / orm.xml中

您将在此文件中添加JPA元数据的XML表示forms。

     SELECT c FROM Customer c WHERE c.address.city = :city                               

了解更多信息

  • 创建RESTful Web服务 – 第2/5部分(XML元数据)

将您公开的域与模型域分开是个好主意,所以我会保持这样,实体和生成的类分开。 解决此ClassCastException的一种简单方法是在Web模块中将jaxb类映射到实体作为输入,反之亦然作为输出。 您可以手动完成,也可以使用不同的库来解决此映射问题。 推土机(http://dozer.sourceforge.net/)

我认为你错过了一个额外的组件 – 应用程序服务。 此外,您的CRUDFacade只是一个CredentialRepository

使用上面提到的组件,有两种可能的解决方案:

  1. 如果您的应用程序服务明显分开,那么您的SampleService只是将此类服务暴露给外部世界的众多可能方法之一。 您可以拥有SampleRestResourceSampleYamlResource ;)或您选择的任何其他。 在这种情况下,我建议创建CredentialDTO并使用@XmlRootElement注释其字段。 您的应用程序服务将此DTO返回给外部世界, SampleRestResource (以前称为SampleService )只是转发它。
  2. 如果您不想引入其他构建块(如DTO(可能还有汇编程序))和单独的SampleRestResource类,您可以在应用程序服务方法上添加注释 – 但我不确定是否可以使用所有JAXWS实现。

按照我描述的方法,通常我将rest资源和应用程序服务放在一个模块中。 您的EJB模块(当前将其视为纯域模块)只是其依赖项之一。