EclipseLink , эталонная реализация JPA, имеет поддержку JPA для баз данных NoSQL (MongoDB и Oracle NoSQL) начиная с версии 2.4. В этом руководстве мы обсудим использование базы данных MongoDB с поддержкой JPA EclipseLink. Транзакция, ранее выполненная с использованием консоли и собственного драйвера java, будет выполнена в веб-приложении с помощью EclipseLink.
Инструменты и технологии, используемые в примере приложения, следующие:
- MongoDB версия 2.4.1
- MongoDB Java Driver версия 2.11.1
- JSF версия 2.2
- PrimeFaces версия 3.5
- EclipseLink версия 2.4
- Jetty 7.x Maven Плагин
- JDK версия 1.7
- Maven 3.0.4
Зависимости проекта
<dependency> <groupId>org.glassfish</groupId> <artifactId>javax.faces</artifactId> <version>2.2.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>3.5</version> </dependency> <dependency> <groupId>org.primefaces.themes</groupId> <artifactId>bootstrap</artifactId> <version>1.0.10</version> </dependency> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.jpa</artifactId> <version>2.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.nosql</artifactId> <version>2.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>jboss</groupId> <artifactId>jboss-j2ee</artifactId> <version>4.2.2.GA</version> </dependency> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>2.11.1</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3</version> </dependency>
Класс сущности
@Entity @NoSql(dataFormat=DataFormatType.MAPPED) public class Article implements Serializable { public Article() { } @Id @GeneratedValue @Field(name="_id") private String id; @ElementCollection private List<Categories> categoryLists = new ArrayList<Categories>(); @Basic private String title; @Basic private String content; @Basic @Temporal(javax.persistence.TemporalType.DATE) private Date date; @Basic private String author; @ElementCollection private List<Tags> tagLists = new ArrayList<Tags>();
Нотация @NoSQL устанавливает формат и тип данных и отображает данные NoSQL. Из-за использования MongoDB в нашем примере приложения и документов в MongoDB, хранящихся в
формате BSON ,
MAP используется в качестве типа данных.
Нотация @ElementCollection отображает встроенную коллекцию в родительский документ. Так как в нашем примере приложения было бы более одной категории и тега, связанных со статьей, мы отображаем их как коллекцию элементов.
Встроенные объекты
@Embeddable @NoSql(dataFormat=DataFormatType.MAPPED) public class Categories implements Serializable { @Basic private String category;
@Embeddable @NoSql(dataFormat=DataFormatType.MAPPED) public class Tags implements Serializable { @Basic private String tag;
Мы видим
нотацию @Embeddable вверху класса
Categories и
Tags в отличие от
класса сущности Article . Документы, хранящиеся в родительском документе, отображаются в этой записи.
Обратите внимание, что встроенные объекты не нуждаются в уникальном поле.
persistence.xml
<?xml version="1.0" encoding="UTF-8" ?> <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_2_0.xsd" version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="kodcuMongo" transaction-type="RESOURCE_LOCAL"> <class>com.kodcu.entity.Article</class> <class>com.com.kodcu.entity.Categories</class> <class>com.kodcu.entity.Tags</class> <properties> <property name="eclipselink.target-database" value="org.eclipse.persistence.nosql.adapters.mongo.MongoPlatform"/> <property name="eclipselink.nosql.connection-spec" value="org.eclipse.persistence.nosql.adapters.mongo.MongoConnectionSpec"/> <property name="eclipselink.nosql.property.mongo.port" value="27017"/> <property name="eclipselink.nosql.property.mongo.host" value="localhost"/> <property name="eclipselink.nosql.property.mongo.db" value="kodcu"/> <property name="eclipselink.logging.level" value="FINEST"/> </properties> </persistence-unit> </persistence>
CRUD Операции
<h:form id="articleForm"> <p:growl id="growl"/> <h:panelGrid columns="2" cellpadding="2" cellspacing="2"> <p:panel styleClass="registrationForm" header="Registration Form"> <h:panelGrid id="registrationPanelGrid" columns="2" cellpadding="2" cellspacing="2"> <h:outputLabel value="Category"/> <p:inputText value="#{myBean.categories}" styleClass="inputTextWidth"/> <h:outputLabel value="Title"/> <p:inputText value="#{myBean.article.title}" required="#{param['saveArticle']=='true'}" requiredMessage="The title field is required." styleClass="inputTextWidth"/> <h:outputLabel value="Content"/> <p:inputTextarea value="#{myBean.article.content}" required="#{param['saveArticle']=='true'}" requiredMessage="The content field is required." styleClass="inputTextAreaWidthHeight"/> <h:outputLabel value="Author"/> <p:inputText value="#{myBean.article.author}" required="#{param['saveArticle']=='true'}" requiredMessage="The author field is required." styleClass="inputTextWidth"/> <h:outputLabel value="Tags"/> <p:inputText value="#{myBean.tags}" styleClass="inputTextWidth" /> </h:panelGrid> </p:panel> <p:panel header="Article Directory" styleClass="articleDirectory"> <p:dataTable id="articleTable" var="article" value="#{myBean.articleList}" selectionMode="single" selection="#{myBean.selectArticle}" paginator="true" paginatorPosition="bottom" rows="5" rowKey="#{article.id}"> <p:ajax event="rowSelect" listener="#{myBean.articleSelect}" update=":articleForm:registrationPanelGrid :articleForm:removeArticle"/> <p:column width="200"> <f:facet name="header"> <h:outputLabel value="Title"/> </f:facet> <h:outputLabel value="#{article.title}"/> </p:column> <p:column width="350"> <f:facet name="header"> <h:outputLabel value="Content"/> </f:facet> <h:outputLabel value="#{article.content}"/> </p:column> <p:column width="200"> <f:facet name="header"> <h:outputLabel value="Author"/> </f:facet> <h:outputLabel value="#{article.author}"/> </p:column> <p:column width="40"> <f:facet name="header"> <h:outputLabel value="Date"/> </f:facet> <h:outputLabel value="#{article.date}"> <f:convertDateTime pattern="dd/MM/yyyy"/> </h:outputLabel> </p:column> </p:dataTable> </p:panel> <h:panelGroup> <p:commandButton id="newArticle" action="#{myBean.initArticle}" value="New" update="registrationPanelGrid articleTable removeArticle"/> <p:commandButton id="saveArticle" action="#{myBean.saveArticle}" value="Save" update="registrationPanelGrid articleTable growl"> <f:param name="saveArticle" value="true"/> </p:commandButton> <p:commandButton id="removeArticle" disabled="#{null == myBean.selectArticle}" action="#{myBean.removeArticle}" value="Remove" update="registrationPanelGrid articleTable @this"/> </h:panelGroup> </h:panelGrid> </h:form>
MyBean.java
public void saveArticle() { em.getTransaction().begin(); if(null == article.getId()) em.persist(article); else em.merge(article); em.getTransaction().commit(); } public void removeArticle() { em.getTransaction().begin(); em.remove(selectArticle); em.getTransaction().commit(); }
6. Демо-приложение
Реальный контент выше и демонстрационное приложение, могут быть доступны в
NoSQL с JPA