持久层保存并检索模型数据。服务层是应用程序层和持久层之间的隔离区:可以替换不同的持久层实现,而不用修改除服务层调用之外的任何其他层。
为了建模留言簿和条目,将创建留言簿和条目模型类。但是不会直接用Java来做这件事。相反,应在Service Builder中定义,它将生成对象模型,并映射到Liferay Portal支持的所有SQL数据库。
应用程序的设计可创建多个留言簿,每个留言簿都包含不同的条目集。所有有权访问应用程序的用户都可以添加条目,但只有管理员可以添加留言簿。
首先创建实Guestbook体:
- In your
guestbook-service
project, open service.xml
. - When Liferay IDE generated your project, it filled this file with dummy entities, which you’ll replace. First replace the file’s opening contents (below the
DOCTYPE
) with the following code:<service-builder auto-namespace-tables="true" package-path="com.liferay.docs.guestbook">
<author>liferay</author>
<namespace>GB</namespace>
<entity name="Guestbook" local-service="true" uuid="true">
This defines the author, namespace, and the entity name. The namespace keeps the database field names from conflicting. The last tag is the opening tag for the Guestbook
entity definition. In this tag, you enable local services for the entity, define its name, and specify that it should have a universally unique identifier (UUID).
- Next, replace the PK fields section:
<column name="guestbookId" primary="true" type="long" />
This defines guestbookId
as the entity’s primary key, of the type long
.
- The group instance can be left alone.
<column name="groupId" type="long" />
This defines the ID of the site in Liferay Portal that the entity instance belongs to (more on this in a moment).
- Leave the Audit Fields section alone. Add status fields:
<!-- Status fields -->
<column name="status" type="int" />
<column name="statusByUserId" type="long" />
<column name="statusByUserName" type="String" />
<column name="statusDate" type="Date" />
The Audit section defines Liferay Portal metadata. The companyId
is the primary key of a portal instance. The userId
is the primary key of a user. The createDate
and modifiedDate
store the respective dates on which the entity instance is created and modified. The Status section is used later to implement workflow.
- In the Other fields section, remove all the generated fields and put this one in their place:
<column name="name" type="String" />
- Next, remove everything else from the Guestbook entity. Before the closing
</entity>
tag, add this finder definition: <finder name="GroupId" return-type="Collection">
<finder-column name="groupId" />
</finder>
This defines a finder that generates a get
method you’ll use to retrieve Guestbook entities. The fields used by the finder define the scope of the data retrieved. This finder gets all Guestbooks by their groupId
, which corresponds to the site the application is on. This lets administrators put Guestbooks on multiple sites, and each Guestbook
has its own data scoped to its site.
该Guestbook
实体现在完成。接下来,创建Entry
实体:
- Add the opening entity tag:
<entity name="Entry" local-service="true" uuid="true">
As with the Guestbook
entity, you enable local services, define the entity’s name, and specify that it should have a UUID.
- Add the tag to define the primary key and the
groupId
:<column name="entryId" primary="true" type="long" />
<column name="groupId" type="long" />
- Add the audit fields as you did with the
Guestbook
entity:<column name="companyId" type="long" />
<column name="userId" type="long" />
<column name="userName" type="String" />
<column name="createDate" type="Date" />
<column name="modifiedDate" type="Date" />
- Add status fields like you did for the guestbook:
<!-- Status fields -->
<column name="status" type="int" />
<column name="statusByUserId" type="long" />
<column name="statusByUserName" type="String" />
<column name="statusDate" type="Date" />
- Add the fields that define an
Entry
:<column name="name" type="String" />
<column name="email" type="String" />
<column name="message" type="String" />
<column name="guestbookId" type="long" />
The name
, email
, and message
fields comprise an Entry
. These fields define the name of the person creating the entry, their email address, and the Guestbook message, respectively. The guestbookId
is assigned automatically by code you’ll write, and is a Guestbook
foreign key. This ties the Entry
to a specific Guestbook
.
- Add your finder and closing entity tag:
<finder name="G_G" return-type="Collection">
<finder-column name="groupId" />
<finder-column name="guestbookId" />
</finder>
</entity>
Here, you define a finder that gets guestbook entries by groupId
and guestbookId
. As before, the groupId
corresponds to the site the application is on. The guestbookId
defines the guestbook the entries come from. This finder returns a Collection
of entries.
- Define your exception types outside the
<entity>
tags, just before the closing </service-builder>
tag:<exceptions>
<exception>EntryEmail</exception>
<exception>EntryMessage</exception>
<exception>EntryName</exception>
<exception>GuestbookName</exception>
</exceptions>
These generate exception classes you’ll use later in try/catch statements.
- Save your
service.xml
file.
现在您已准备好运行Service Builder来生成模型,服务和持久层!
- In the Gradle Tasks pane on the right side of IDE, open
guestbook-service
→ build
. - Run
buildService
by right-clicking it and selecting Run Gradle Tasks. Make sure you’re connected to the Internet, as Gradle downloads dependencies the first time you run it. - In the Project Explorer, right-click the
guestbook-service
module and select Refresh. Repeat this step for the guestbook-api
module. This ensures that the new classes and interfaces generated by Service Builder show up in IDE. - In the Project Explorer, right-click the
guestbook-service
module and select Gradle → Refresh Gradle Project. Repeat this step for the guestbook-api
module. This ensures that your modules’ Gradle dependencies are up to date.
Service Builder基于松散耦合的设计理念。它会生成三层应用程序:模型,服务和持久层。松耦合意味着您可以在模型层和服务层几乎不做任何更改的情况下更换持久层。该模型位于-api
模块中,服务层和持久层位于-service
模块中。
图1:模型,服务和持久层。
每一层都使用Java接口和这些接口的实现类来实现。Service Builder 生成一个代表您的模型的Entry类,而是生成系列类,包括一个Guestbook接口、一个Service Builder 管理的GuestbookBaseImpl抽象类,以及一个可以自定义的GuestbookImpl类。
接下来,您将创建服务实现。