2015-04-14 99 views
6

我們正在使用AngularJS,Rest,JPA開發Web應用程序。我已閱讀了一些關於域實體不應該通過服務暴露的文章。 我知道這是緊密的耦合,可以有循環引用,關注點分離,這似乎對我有效。 但是後來我看到有關將jpa和jaxb映射應用於相同模型的文章,eclipseLink moxy就是一個例子。通過服務暴露JPA實體

然後是春季數據REST它通過REST API公開JPA實體。(可以是彈簧數據REST是用來解決手邊有一個不同的問題)

所以我感到有點困惑。以下兩個問題和場景的答案,其中一個比另一個更有幫助。

  1. 將jaxb和JPA註釋應用於同一個域模型有什麼優勢?這是否僅僅是爲了避免DTO在 層之間?

  2. Spring數據REST是否應該僅在您開發需要公開CRUD操作的應用程序時使用,並且實際上沒有涉及其他業務功能?

回答

1

使用DTO需要一定的開銷:必須創建DTO類;實體類必須在序列化之前映射到DTO。

只要他們似乎違背了「不要重複自己」的原則,DTO也會「感覺不對」。看到一個實體和一個DTO並看到它們本質上是相同的,這是令人沮喪的。

因此,直接暴露您的JPA實體會減少代碼並減少處理代碼時的精神開銷。您的控制器,服務和存儲庫都處理相同的類。

有問題,但是:要公開給API用戶的內部表示與接口之間

  • 不匹配。

    真實世界的例子:根文檔是article和子文檔是sections的分層文檔。在內部,每個文檔都與可能爲空的父文檔有關係。

    直接通過REST接口公開此實體將要求客戶端發送id(或HATEOAS中的url)作爲其提交實體的一部分,以正確地將文檔鏈接在一起。

    更好的辦法是在創建子部分時將api用戶POST設置爲/articles/{id}/sections/

  • 公開內部數據。

    您的實體可能包含標識符,磁盤上的路徑等,這些標識符並非真正用於公共消費。在序列化時,你將不得不@JsonIgnore這些。當反序列化時,您也可以手動填寫實體。

  • 表現。

    與上述相似;也許你的實體包含一個大型數據對象。您希望用戶能夠POST或PUT這些,但不應要求他們下載對象只是爲了讀取實體的其他字段。

  • 潛在的序列化問題。

    延遲加載的集合是這裏經典的失敗案例。

  • 比需要更復雜的序列化表示。

    真實世界的例子:word實體集合synonyms;同義詞依賴於這個詞。直接序列化的實體將導致:

    { "id":12, 
        "word": "cat", 
        "synonyms": [ 
        { "id": 23, 
         "synonym": "kitty" 
        }, 
        { "id": 34, 
         "synonym": "pussycat" 
        } 
        ] 
    } 
    

    更好的模式是:在同一類可降低清晰度

    { "word": "cat", 
        "synonyms": [ 
        "kitty", 
        "pussycat" 
        ] 
    } 
    
  • 大量的註釋。

    根據您的實體的複雜性,你可能有JPA的註解(@Entity@Id@GeneratedValue@Column@ManyToMany@MappedBy等),XML註釋(@XmlRootElement@XmlType@XmlElement,等等),JSON註解(@JsonInclude@JsonIgnore@JsonProperty等)和驗證註釋(@NotNull,@Null等)都在同一個類上。

由於所有這些問題,我通常使用DTO。我手工將這個實體做成DTO映射,但有一些項目試圖使這更容易,如Dozer

我可以想象使用spring-data-rest或直接暴露我的實體,只是在我有非常簡單的實體,沒有太多關係,以及實體模型和我希望的模型之間高度一致的情況下暴露給用戶。

+0

您的至少一些問題至少沒有解決https://spring.io/blog/2014/05/21/what-s-new-in-spring-data-dijkstra#projections-in-spring-數據休息 –