Business Logic with Service Builder
Once you’ve generated model, persistence, and service code with Service Builder, you can begin adding business logic. Entities generated by Service Builder contain a model implementation and local service implementation class. Your application’s business logic can be implemented in these classes. The generated service later contains default methods that call CRUD operations from the persistence layer. Once you have business logic, you run Service Builder again to propagate your application’s interfaces, which makes your new logic available for invocation.
See the Example Project
Start a new Liferay DXP instance by running
docker run -it -m 8g -p 8080:8080 liferay/dxp:2024.q1.1
Sign in to Liferay at http://localhost:8080 using the email address test@liferay.com and the password test. When prompted, change the password to learn.
Then, follow these steps:
-
Download and unzip Business Logic with Service Builder.
curl https://resources.learn.liferay.com/dxp/latest/en/building-applications/data-frameworks/service-builder/liferay-e4g5.zip -O
unzip liferay-e4g5.zip
-
From the module root, build and deploy.
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
NoteThis command is the same as copying the deployed jars to /opt/liferay/osgi/modules on the Docker container.
-
Confirm the deployment in the Liferay Docker container console.
STARTED com.acme.e4g5.api_1.0.0 [1034] STARTED com.acme.e4g5.service_1.0.0 [1035] STARTED com.acme.e4g5.web_1.0.0 [1036]
-
Verify that the example module is working. Open your browser to
https://localhost:8080
. -
Add the E4G5 Portlet to a page. You can find the example portlet under Sample Widgets.
-
Add an entry by entering a name and description (e.g. e4g5_name1 and e4g5_description1). Click
Add
, and the new entry appears underE4G5 Entries
. Take note of thee4g5EntryId
number. -
Next, update this entry but entering the
e4g5EntryId
from the previous step and a new name and description. (e.g. 41804, e4g5_name2, e4g5_description2). ClickUpdate
, and the entry is now updated. -
Finally, delete the entry by entering the
e4g5EntryId
. ClickDelete
, and the entry is now deleted.
Update the Service Layer
Extend the local service by adding methods that can add, update, and delete E4G5Entry
entries.
Implement the Add Method
- Declare an
add*
method with parameters for creating an entity.
public E4G5Entry addE4G5Entry(String description, String name)
throws PortalException {
E4G5Entry e4g5Entry = e4g5EntryPersistence.create(
counterLocalService.increment());
e4g5Entry.setDescription(description);
e4g5Entry.setName(name);
return e4g5EntryPersistence.update(e4g5Entry);
}
-
The
*Persistence
class associated with your entity has acreate()
method that constructs an entity instance with the given ID. Every*BaseLocalServiceImpl
has acounterLocalService
object for the entity. Invoke the counter service’sincrement()
method to generate a primary key for your entity instance. -
Use the entity’s setter methods to populate your entity’s attributes. The sample sets two attributes:
name
anddescription
. -
Invoke the
*Persistence
class’supdate()
method, passing in the entity object.
Implement the Update Method
- Declare an
update*
method with parameters for updating an entity. The sample receivesname
anddescription
attributes, along withe4g5EntryId
.
public E4G5Entry updateE4G5Entry(
long e4g5EntryId, String description, String name)
throws PortalException {
E4G5Entry e4g5Entry = e4g5EntryPersistence.findByPrimaryKey(
e4g5EntryId);
e4g5Entry.setDescription(description);
e4g5Entry.setName(name);
return e4g5EntryPersistence.update(e4g5Entry);
}
-
Use the
*Persistence
class’sfindByPrimaryKey()
method to retrieve the entity instance by entry ID. -
Use the entity’s setter methods to populate your entity’s attributes.
-
Invoke the
*Persistence
class’supdate()
method, passing in the entity object.
Implement the Delete Method
- Declare a
delete*
method that receives the entity’s entry ID.
public E4G5Entry deleteE4G5Entry(long e4g5EntryId) throws PortalException {
E4G5Entry e4g5Entry = e4g5EntryPersistence.findByPrimaryKey(
e4g5EntryId);
e4g5EntryPersistence.remove(e4g5Entry);
return e4g5Entry;
}
- Invoke the
*Persistence
class’sdelete()
method, passing in the entity object.
After implementing your add*
, update*
, and delete*
methods, run Service Builder to propagate your new service methods to the *LocalService
interface.
Integrate the Backend
Now implement the service methods you created into your web module with portlet actions.
Portlet Actions
You can use an MVC Portlet for your web module. The sample project’s Portlet has entry actions for add
, update
, and delete
.
public void addE4G5Entry(
ActionRequest actionRequest, ActionResponse actionResponse)
throws PortalException {
_e4g5EntryLocalService.addE4G5Entry(
ParamUtil.getString(actionRequest, "description"),
ParamUtil.getString(actionRequest, "name"));
}
public void deleteE4G5Entry(
ActionRequest actionRequest, ActionResponse actionResponse)
throws PortalException {
_e4g5EntryLocalService.deleteE4G5Entry(
ParamUtil.getLong(actionRequest, "e4g5EntryId"));
}
public void updateE4G5Entry(
ActionRequest actionRequest, ActionResponse actionResponse)
throws PortalException {
_e4g5EntryLocalService.updateE4G5Entry(
ParamUtil.getLong(actionRequest, "e4g5EntryId"),
ParamUtil.getString(actionRequest, "description"),
ParamUtil.getString(actionRequest, "name"));
}
Each method takes an ActionRequest
and ActionResponse
parameter. The ActionRequest
receives information from the view layer and the ActionResponse
can be used to pass information back to the view layer.
The addE4G5Entry()
method receives a name and description and calls the service to add the entry. The updateE4G5Entry()
method receives an entry ID, name, and description and calls the service to updated a specific entry. The deleteE4G5Entry()
method receives an entry ID and calls the service to delete the entry.
Map the Actions in the JSP
Now map the action methods you created into your JSP.
<h3>Add a E4G5 Entry</h3>
<portlet:actionURL name="addE4G5Entry" var="addE4G5EntryURL" />
<aui:form action="<%= addE4G5EntryURL %>">
<aui:input name="name" type="text" />
<aui:input name="description" type="text" />
<aui:button type="submit" value="add" />
</aui:form>
<hr />
<h3>Update a E4G5 Entry</h3>
<portlet:actionURL name="updateE4G5Entry" var="updateE4G5EntryURL" />
<aui:form action="<%= updateE4G5EntryURL %>">
<aui:input name="e4g5EntryId" type="text" />
<aui:input name="name" type="text" />
<aui:input name="description" type="text" />
<aui:button type="submit" value="update" />
</aui:form>
<hr />
<h3>Delete a E4G5 Entry</h2>
<portlet:actionURL name="deleteE4G5Entry" var="deleteE4G5EntryURL" />
<aui:form action="<%= deleteE4G5EntryURL %>">
<aui:input name="e4g5EntryId" type="text" />
<aui:button type="submit" value="delete" />
The JSP binds actions to UI components using the tag library’s portlet:actionURL
tag. Note that the portlet:actionURL
’s name
attribute must match each of the action methods created in the portlet. The var
attribute assigns the portlet action URL to an arbitrary variable. The <aui:form>
renders text fields for user input. On submitting the form, its values are passed along with the ActionRequest
to the portlet method.