2012-04-05 106 views
4

自從一個月前我真的很難學習寧靜的web服務。 現在我已經練習了語法,並且理解了這些概念,我決定創建一個包含EJB,JPA和REST的非常簡單的企業應用程序。 我正在努力嘗試瞭解組織這種系統的最佳方式。如果有人在該領域有經驗可以給我一些關於什麼是最佳實踐的提示,那麼我很感激,我該如何解決我目前的問題。應該如何組織提供REST Web服務的JEE6企業應用程序?

讓我告訴你這張圖片。對不起,我不能得到更好的分辨率(使用Ctrl +鼠標向上滾動放大):

enter image description here

正如你可以看到這是一個非常簡單的應用程序的企業,有2個模塊。

此應用程序不使用CDI(我要實現我的目標沒有CDI的幫助和)

當某些客戶端(任何可互操作的客戶端)發送一個@GET一些參數的REST服務應該通過這些參數到EJB模塊,它將在數據庫中搜索併發回相應的數據。最後,服務將在JAXB的幫助下自動編組,並將.XML發送回客戶端。

我的問題有以下幾點:

  • 我得到一個ClassCastException,因爲在該實體EJB模塊中不與JAXB類兼容的WebModule(即使它們的變量都相同)
  • 我不知道應該怎麼組織,所以前端可以編組和解組這些實體。
  • 也許實體類可能在前端與JAXB映射相結合?如果那樣的話,EJB模塊將不再需要。但事情是,我想要EJB模塊,因爲我經常在那裏做我的CRUD操作。
  • 如何將EJB公開爲REST Web服務(製作混合)?你認爲這是一個好主意嗎?它如何幫助我?
  • 同樣,如果我在Web模塊中創建JAXRS + EJB的混合,我將必須在前端創建我的JPA實體,這是我以前從未做過的事情。你認爲這是一個好習慣嗎?
  • 你有什麼建議?通常使用REST Web服務的企業應用程序的組織方式是什麼?

回答

5

下面是作爲使用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映射而不是註釋,以避免客戶端上的類路徑依賴。

更多信息


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> 

更多信息

+0

我喜歡這個主意,因爲你使用的是混合方法聽起來很有趣。如果我理解的很好,你說我應該將實體(當前在EJB模塊中)的映射添加到web.xml中,而不是使用註釋,對吧? 但是EJB模塊呢?你能用一個如何做這些映射和在哪個文件中的例子來更新你的問題嗎?我有點困惑。 – sfrj 2012-04-05 18:58:49

+0

@sfrj - JPA元數據將放入從'persistence.xml'文件引用的文件中。 – 2012-04-05 19:13:35

+1

Tnx這個答案是非常有用的。 – sfrj 2012-04-09 09:54:41

0

我想你錯過了一個額外的組件 - 應用程序服務。 此外,您的CRUDFacade只是一個CredentialRepository

用我上面提到的成分,有兩種可能的解決方案:

  1. 如果你有一個應用服務明顯地分開,你SampleService將只是暴露這樣的服務對外部世界的許多可能的方法之一。您可以有SampleRestResourceSampleYamlResource;)或您選擇的任何其他選項。在這種情況下,我建議創建CredentialDTO並用@XmlRootElement註釋其字段。您的應用服務將此DTO返回給外部世界,並且SampleRestResource(原名稱爲SampleService)只是將其轉發給您。
  2. 如果你不想引入額外的積木一樣DTO(也許連同彙編)和單獨SampleRestResource類,你可以在你的應用服務方法添加註釋 - 我不知道是否有可能與所有JAXWS的實現,但是。

以下描述的方法通常會將其餘資源和應用程序服務一起放在一個模塊中。您的EJB模塊(目前將我看作純粹的域模塊)只是它的一個依賴項。

0

這是分離,你是從你的模型域暴露域是一個好主意,所以我會保持這個樣子,與實體和生成的類分開。解決這個ClassCastException的直接方法是將web模塊中的jaxb類映射到實體作爲輸入,反之作爲輸出。您可以手動完成,或者有不同的庫來解決這個映射問題。即推土機(http://dozer.sourceforge.net/)

相關問題