自从一个月前我学习RESTful Web服务真的很辛苦。 现在,我没有练习语法和我理解的概念,我决定做一个非常简单的企业应用程序,包括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服务的企业应用程序的组织方式?
下面是使用JPA的持久性和JAXB的消息可能看起来像一个会话bean实现的JAX-RS服务的例子。 (注意:一个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<Customer> findCustomersByCity(@PathParam("city") String city) {
Query query = entityManager.createNamedQuery("findCustomersByCity");
query.setParameter("city", city);
return query.getResultList();
}
}
如果你想使用的服务器和客户端相同的域对象。 然后,我将提供通过XML的JPA映射,而不是注解,以避免客户端上的类路径depedency。
欲获得更多信息
- 第1部分-数据模型
- 第2部分- JPA
- 第3部分- JAXB(使用莫西)
- 第4部分- RESTful服务(使用EJB会话bean)
- 第5部分-客户端
UPDATE
META-INF / persistence.xml中
persistence.xml文件是在其中指定链接到包含JPA映射的XML文件:
<persistence-unit name="CustomerService" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>CustomerService</jta-data-source>
<mapping-file>META-INF/orm.xml</mapping-file>
</persistence-unit>
META-INF / orm.xml中
正是在这个文件中,你会添加JPA元数据的XML表示。
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings
version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">
<entity class="org.example.Customer">
<named-query name="findCustomersByCity">
<query>SELECT c FROM Customer c WHERE c.address.city = :city</query>
</named-query>
<attributes>
<id name="id"/>
<basic name="firstName">
<column name="FIRST_NAME"/>
</basic>
<basic name="lastName">
<column name="LAST_NAME"/>
</basic>
<one-to-many name="phoneNumbers" mapped-by="customer">
<cascade>
<cascade-all/>
</cascade>
</one-to-many>
<one-to-one name="address" mapped-by="customer">
<cascade>
<cascade-all/>
</cascade>
</one-to-one>
</attributes>
</entity>
<entity class="org.example.Address">
<attributes>
<id name="id"/>
<one-to-one name="customer">
<primary-key-join-column/>
</one-to-one>
</attributes>
</entity>
<entity class="org.example.PhoneNumber">
<table name="PHONE_NUMBER"/>
<attributes>
<id name="id"/>
<many-to-one name="customer">
<join-column name="ID_CUSTOMER"/>
</many-to-one>
</attributes>
</entity>
</entity-mappings>
欲获得更多信息
- 创建一个RESTful Web服务-第2/5(XML元数据)
这是分离,你是从你的模型域暴露域是一个好主意,所以我会保持这个样子,与实体和生成的类分开。 解决这个ClassCastException异常一个直接的方法是在网络模块中的JAXB类映射到实体来说作为输入,并且反之亦然为输出。 您可以自己动手完成,或有不同的库来解决这个映射。 即推土机(http://dozer.sourceforge.net/)
我认为你错过这里一个额外的组件 - 应用服务。 此外,您CRUDFacade
只是一个CredentialRepository
。
随着我上面提到的成分,有两种可能的解决方案:
- 如果你有一个应用服务明显地分开,你
SampleService
将只是暴露这样的服务给外界的许多可能的方法之一。 你可以有SampleRestResource
, SampleYamlResource
;)或任何其他的选择。 在这种情况下,我建议你创建CredentialDTO
,并标注其字段@XmlRootElement
。 你的应用程序的服务回报这个DTO到外面的世界和SampleRestResource
(原SampleService
)只是将其转发。 - 如果你不想引入额外的积木一样DTO(也许连同汇编)和单独
SampleRestResource
类,你可以在你的应用服务方法添加注释-我不知道是否有可能与所有JAXWS的实现,虽然。
下面我描述的方法,通常我把其余的资源与应用服务以及一个模块中。 EJB模块(目前看起来,我作为一个纯粹的域模块)只是它的一个依赖。
文章来源: How a JEE6 enterprise application that offers REST web services should be organized?