带有Hibernate OGM的NoSQL –第三部分:在WildFly上构建REST应用程序
歡迎回到我們的教程系列“帶有Hibernate OGM的NoSQL”! 感謝Gunnar Morling( @gunnarmorling )創建了本教程。 在這一部分中,您將學習如何在WildFly服務器上運行的Java EE應用程序中使用Hibernate OGM。 使用本教程前面部分已經知道的實體模型 ,我們將構建一個基于REST的小型應用程序來管理加息。 如果您還沒有閱讀本系列的前兩期,則可以在這里找到它們:
- 帶有Hibernate OGM的NoSQL –第一部分:持久化您的第一個實體
- 帶有Hibernate OGM的NoSQL –第二部分:查詢數據
在下面的內容中,您將學習如何準備WildFly以使其與Hibernate OGM一起使用,配置JPA持久性單元,創建用于訪問數據的存儲庫類以及在這些之上提供REST資源。 在本文中,我們將主要關注與持久性相關的方面,因此使用REST / JAX-RS的一些基本經驗可能會有所幫助。 本教程的完整源代碼托管在GitHub上。
準備WildFly
WildFly服務器運行時基于JBoss Modules系統。 這提供了一個模塊化的類加載環境,其中每個庫(例如Hibernate OGM)都是其自己的模塊,聲明了它依賴的其他模塊的列表,并且僅從那些其他依賴項中“看到”了類。 這種隔離使人們擺脫了可怕的“類路徑地獄”。
SourceForge提供了包含Hibernate OGM所有必需模塊的ZIP文件。 我們昨天發布的 Hibernate OGM 4.2支持WildFly 9,因此請下載hibernate-ogm-modules-wildfly9-4.2.0.Final.zip 。 如果您使用的是WildFly 8,請使用Hibernate OGM 4.1并獲取hibernate-ogm-modules-wildfly8-4.1.3.Final.zip 。
將與您的WildFly版本相對應的歸檔文件解壓縮到應用程序服務器的modules目錄中。 如果您希望原始的WildFly目錄保持不變,則還可以將Hibernate OGM模塊存檔解壓縮到任何其他文件夾,并將其配置為服務器要使用的“模塊路徑”。 為此,請導出以下兩個環境變量,以匹配您的特定環境:
export JBOSS_HOME=/path/to/wildfly export JBOSS_MODULEPATH=$JBOSS_HOME/modules:/path/to/ogm/modules如果您正在使用Maven WildFly插件 (例如在開發期間啟動WildFly),則可以通過在POM文件中使用以下插件配置來實現相同的目的:
... <plugin><groupId>org.wildfly.plugins</groupId><artifactId>wildfly-maven-plugin</artifactId><version>1.1.0.Alpha1</version><configuration><jboss-home>/path/to/wildfly</jboss-home><modules-path>/path/to/ogm/modules</modules-path></configuration> </plugin> ...設置項目
首先使用“ war”包裝類型創建一個新的Maven項目。 將以下內容添加到您的pom.xml中 :
... <dependencyManagement><dependencies><dependency><groupId>org.hibernate.ogm</groupId><artifactId>hibernate-ogm-bom</artifactId><type>pom</type><version>4.2.0.Final</version><scope>import</scope></dependency></dependencies> </dependencyManagement> ...這樣可以確保獲得匹配版本的Hibernate OGM模塊和任何(可選)依賴項。 然后將依賴項添加到Java EE 7 API和Hibernate OGM后端模塊之一,例如Infinispan ,JBoss的高性能,分布式鍵/值數據網格(其他任何諸如hibernate-ogm-mongodb或全新的hibernate -ogm-cassandra模塊也可以工作):
... <dependencies><dependency><groupId>javax</groupId><artifactId>javaee-api</artifactId><version>7.0</version><scope>provided</scope></dependency><dependency><groupId>org.hibernate.ogm</groupId><artifactId>hibernate-ogm-infinispan</artifactId><scope>provided</scope></dependency> </dependencies> ...provided作用域使這些依賴項可用于編譯,但是阻止將它們添加到生成的WAR文件中。 那是因為Java EE API已經是WildFly的一部分,而Hibernate OGM將通過您之前解壓縮的模塊來貢獻。
但是,僅將這些模塊添加到服務器并不會削減它。 還需要將它們注冊為應用程序的模塊依賴項。 為此,添加具有以下內容的文件src / main / webapp / WEB-INF / jboss-web.xml :
<?xml version="1.0" encoding="UTF-8"?> <jboss-deployment-structurexmlns="urn:jboss:deployment-structure:1.2"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><deployment><dependencies><module name="org.hibernate" slot="ogm" services="import" /><module name="org.hibernate.ogm.infinispan" services="import" /><module name="org.hibernate.search.orm" services="import" /></dependencies></deployment> </jboss-deployment-structure>這將使Hibernate OGM核心和Infinispan后端以及Hibernate Search可用于您的應用程序。 后者將很快用于運行JP-QL查詢。
添加實體類和存儲庫
有了基本的項目基礎結構之后,就該添加實體類和存儲庫類以訪問它們了。 實體類型基本上與第1部分中的相同,只是現在使用@Indexed進行注釋,以允許它們通過Hibernate Search和Lucene進行查詢:
@Entity @Indexed public class Person {@Id@GeneratedValue(generator = "uuid")@GenericGenerator(name = "uuid", strategy = "uuid2")private String id;private String firstName;private String lastName;@OneToMany(mappedBy = "organizer",cascade = { CascadeType.PERSIST, CascadeType.MERGE },fetch = FetchType.EAGER)private Set<Hike> organizedHikes = new HashSet<>();// constructors, getters and setters... }@Entity @Indexed public class Hike {@Id@GeneratedValue(generator = "uuid")@GenericGenerator(name = "uuid", strategy = "uuid2")private String id;private String description;private Date date;private BigDecimal difficulty;@ManyToOneprivate Person organizer;@ElementCollection(fetch = FetchType.EAGER)@OrderColumn(name = "sectionNo")private List<HikeSection> sections;// constructors, getters and setters... }@Embeddable public class HikeSection {private String start;private String end;// constructors, getters and setters... }為了使用這些實體,必須定義一個JPA持久性單元。 為此,創建文件src / main / resources / META-INF / persistence.xml :
<?xml version="1.0" encoding="utf-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"version="1.0"><persistence-unit name="hike-PU" transaction-type="JTA"><provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider><class>org.hibernate.ogm.demos.ogm101.part3.model.Person</class><class>org.hibernate.ogm.demos.ogm101.part3.model.Hike</class><properties><property name="hibernate.ogm.datastore.provider" value="INFINISPAN" /><property name="hibernate.ogm.datastore.database" value="hike_db" /><property name="hibernate.ogm.datastore.create_database" value="true" /></properties></persistence-unit> </persistence>在這里,我們定義一個名為“ hike-PU”的持久性單元。 Infinispan是一個完全事務性的數據存儲,使用JTA作為事務類型可以使持久性單元參與容器管理的事務。 將HibernateOgmPersistence指定為提供程序類將啟用Hibernate OGM(而不是Hibernate ORM),它已為設置后端(在這種情況下為INFINISPAN),數據庫名稱等配置了一些屬性。
請注意,實際上,在Java EE容器(例如WildFly)中運行時,實際上不需要在persistence.xml中指定實體類型。 相反,它們應該被自動拾取。 使用Hibernate OGM時,目前很不幸。 這是一個已知的限制(請參閱OGM-828 ),我們希望盡快解決。
下一步是實現用于訪問遠足和組織者數據的存儲庫類。 例如,下面顯示了PersonRepository類:
@ApplicationScoped public class PersonRepository {@PersistenceContextprivate EntityManager entityManager;public Person create(Person person) {entityManager.persist( person );return person;}public Person get(String id) {return entityManager.find( Person.class, id );}public List<Person> getAll() {return entityManager.createQuery( "FROM Person p", Person.class ).getResultList();}public Person save(Person person) {return entityManager.merge( person );}public void remove(Person person) {entityManager.remove( person );for ( Hike hike : person.getOrganizedHikes() ) {hike.setOrganizer( null );}} }實現很簡單; 通過@ApplicationScoped批注,該類被標記為應用程序范圍的CDI bean(即,在應用程序的整個生命周期中都存在該bean的單個實例)。 它通過依賴注入獲得JPA實體管理器,并使用該實體管理器來實現一些簡單的CRUD方法(創建,讀取,更新,刪除)。
請注意, getAll()方法如何使用JP-QL查詢返回所有人員對象。 執行后,此查詢將轉換為等效的Lucene索引查詢,該查詢將通過Hibernate Search運行。
遠足資料庫看起來非常相似,因此為簡潔起見,在此省略。 您可以在GitHub上找到其源代碼 。
公開REST服務
JAX-RS使構建基于REST的Web服務變得輕而易舉。 它定義了一個聲明式編程模型,您可以在其中注釋簡單的舊Java類,以提供HTTP端點的GET,POST,PUT等操作的實現。
深入描述JAX-RS超出了本教程的范圍,例如,如果您想了解更多信息,請參考Java EE 7教程 。 讓我們以資源類中用于管理人員的一些方法為例:
@Path("/persons") @Produces("application/json") @Consumes("application/json") @Stateless public class Persons {@Injectprivate PersonRepository personRepository;@Injectprivate ResourceMapper mapper;@Injectprivate UriMapper uris;@POST@Path("/")public Response createPerson(PersonDocument request) {Person person = personRepository.create( mapper.toPerson( request ) );return Response.created( uris.toUri( person ) ).build();}@GET@Path("/{id}")public Response getPerson(@PathParam("id") String id) {Person person = personRepository.get( id );if ( person == null ) {return Response.status( Status.NOT_FOUND ).build();}else {return Response.ok( mapper.toPersonDocument( person ) ).build();}}@GET@Path("/")public Response listPersons() { … }@PUT@Path("/{id}")public Response updatePerson(PersonDocument request, @PathParam("id") String id) { … }@DELETE@Path("/{id}")public Response deletePerson(@PathParam("id") String id) { … } }的@Path , @Produces和@Consumes注釋由JAX-RS所定義。 它們將資源方法綁定到特定的URL,以期望并創建基于JSON的消息。 @GET , @GET @POST , @GET @PUT和@DELETE配置每個方法負責哪個HTTP動詞。
@Stateless注釋將此POJO定義為無狀態會話Bean。 可以通過基于@Inject的依賴項注入來獲取諸如PersonRepository的依賴項。 實現會話bean可以使您通過容器進行透明的事務管理。 Persons方法的調用將自動包裝在一個事務中,并且Hibernate OGM與數據存儲區的所有交互都將參與其中。 這意味著您對托管實體所做的任何更改(例如,通過PersonRepository#create()持久保存新人員或修改從實體管理器中檢索到的Person對象)都將在方法調用返回后提交到數據存儲中。
映射模型
請注意,我們的REST服務的方法不會返回并接受托管實體類型本身,而是返回特定的傳輸結構,例如PersonDocument :
public class PersonDocument {private String firstName;private String lastName;private Set<URI> organizedHikes;// constructors, getters and setters... }這樣做的理由是以URI的形式表示關聯的元素( Person#organizedHikes , Hike#organizer ),這使客戶端可以根據需要獲取這些鏈接的資源。 例如,對http:// myserver / ogm-demo-part3 / hike-manager / persons / 123的GET調用可能返回如下JSON結構:
{"firstName": "Saundra","lastName": "Johnson","organizedHikes": ["http://myserver/ogm-demo-part3/hike-manager/hikes/456","http://myserver/ogm-demo-part3/hike-manager/hikes/789"] }內部模型(例如,實體Person )和外部模型(例如PersonDocument )之間的映射可能很快成為一項繁瑣而枯燥的任務,因此需要一些基于工具的支持。 存在用于此工作的幾種工具,其中大多數使用反射或運行時字節代碼生成來在不同模型之間傳播狀態。
MapStruct尋求另一種方法,這是我的一個業余項目,并在編譯時(例如,使用Maven或在您的IDE中)通過Java注釋處理器生成bean映射器實現。 它生成的代碼是類型安全的,快速的(它使用簡單的方法調用,沒有反射)并且沒有依賴關系。 您只需要使用所需的源和目標類型的映射方法聲明Java接口,MapStruct就會在編譯過程中生成一個實現:
@Mapper(// allows to obtain the mapper via @InjectcomponentModel = "cdi",// a hand-written mapper class for converting entities to URIs; invoked by the generated// toPersonDocument() implementation for mapping the organizedHikes propertyuses = UriMapper.class ) public interface ResourceMapper {PersonDocument toPersonDocument(Person person);List<PersonDocument> toPersonDocuments(Iterable<Person> persons);@Mapping(target = "date", dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")HikeDocument toHikeDocument(Hike hike);// other mapping methods ... }然后可以在Persons REST資源中使用生成的實現,以從內部模型映射到外部模型,反之亦然。 如果您想了解有關此模型映射方法的更多信息,請查看GitHub上的完整mapper界面或MapStruct參考文檔 。
包起來
在我們的教程系列的這一部分中,您學習了如何將Hibernate OGM添加到WildFly應用程序服務器,并使用它來訪問Infinispan作為小型REST應用程序的數據存儲。
WildFly是使用Hibernate OGM的應用程序的絕佳運行時環境,因為它提供了現成的大多數必需的構建塊(例如JPA / Hibernate ORM,JTA,事務管理等),并且緊密集成并可以使用。 我們的模塊ZIP可以非常輕松地將Hibernate OGM模塊放入組合中,而無需每次在您的應用程序中重新部署它們。 有了WildFly Swarm ,還支持微服務體系結構樣式,但是我們將再留一點時間來展示如何將Hibernate OGM與Wildfly Swarm一起使用(當前,WildFly Swarm仍然缺少JPA支持)。
您可以在GitHub上找到該項目的源代碼。 要構建項目,請運行mvn clean install (它使用Arquillian本身對一個激動人心的主題執行REST服務的集成測試 )。 另外,Maven WildFly插件可用于啟動WildFly實例并通過mvn wildfly:run部署應用程序,這非常適合手動測試,例如通過curl或wget發送HTTP請求。
如果您有任何疑問,請在下面的評論中告訴我們,或給我們發送Tweet到@Hibernate 。 也歡迎您對本教程的后續部分的希望。 敬請關注!
翻譯自: https://www.javacodegeeks.com/2015/06/nosql-with-hibernate-ogm-part-three-building-a-rest-application-on-wildfly.html
總結
以上是生活随笔為你收集整理的带有Hibernate OGM的NoSQL –第三部分:在WildFly上构建REST应用程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DMLC深盟分布式深度机器学习开源平台解
- 下一篇: 教程:如何实现Java OAuth 2.