Liferay开发实战(2):Service Builder生成持久化层,及开发服务层
本文Liferay适用版本:v6.2.ce-ga6版
Liferay的插件体系是:模型-视图-控制器的portlet MVC框架。
MVC是一个伟大的用于Web应用程序的设计模式,在实际应用中还应处理持久化,它可以用于检索、处理或显示。为此你需要添加更多的层:一个持久层和服务层。
持久层负责保存和检索模型数据。服务层就像你的应用程序和持久层之间的缓冲区:在将来,它会给你自由的自由,即在不修改任何内容的情况下,哪怕是就算将来有一天你替换掉整个持久层。松耦合是良好的应用程序设计,并在Liferay框架中支持。它通过Service Builder(服务生成器)生成。
Service Builder的特性:
- 自动生成模型,持久性和服务层
- 自动生成本地和远程服务
- 自动生成Hibernate和Spring的配置
- 根据帐户的权限生成查找方法的实体和查找方法
- 内置实体缓存(entity caching)支持
- 自定义的SQL查询和动态查询的支持
- 节省开发时间
你只需要生成一个 service.xml 文件,再运行 Service Builder ,这将生成一个新的 service .jar 文件,新文件包括模型层、持久层、服务层等文件。
通过服务生成器生成的远程服务包括SOAP或JSON访问。
另一种节省开发时间的方式是通过Spring和Hibernate的配置你的项目。业务生成器使用Spring的依赖注入使服务实现类可在运行时使用Spring AOP的事务管理。
生成方法。点击当前Liferay项目》 New → Liferay Service Builder
服务生成器的界面
配置文件的格式:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_2_0.dtd"> <service-builder package-path="com.liferay.docs.guestbook"> <author>wangxin</author> <namespace>GB</namespace> <entity name="Guestbook" local-service="true"> <!-- PK fields --> <column name="guestbookId" type="long" primary="true"></column> <!-- Group instance --> <column name="groupId" type="long"></column> <!-- Audit fields --> <column name="companyId" type="long"></column> <column name="userId" type="long"></column> <column name="userName" type="String"></column> <column name="createDate" type="Date"></column> <column name="modifiedDate" type="Date"></column> <column name="name" type="String"></column> </entity> <entity name="Entry"> <!-- PK fields --> <column name="entryId" type="long" primary="true"></column> <!-- Group instance --> <column name="groupId" type="long"></column> <!-- Audit fields --> <column name="companyId" type="long"></column> <column name="userId" type="long"></column> <column name="userName" type="String"></column> <column name="createDate" type="Date"></column> <column name="modifiedDate" type="Date"></column> <column name="name" type="String"></column> <column name="email" type="String"></column> <column name="message" type="String"></column> <column filter-primary="false" name="guestbookId" primary="false" type="long"></column> </entity> <exceptions> <exception>GuestbookName</exception> <exception>EntryName</exception> <exception>EntryMessage</exception> <exception>EntryEmail</exception> </exceptions> </service-builder>
当你写一个系统应用,例如,如果你为两个不同的站点添加一个Wiki,每个wiki的数据是根据每个站点而不同。换句话说,一个网站没有访问另一个网站的数据,但应用程序都相同。这是数据范围的概念。
在Liferay Portal的数据范围有一个层次,在下图描述。
在这里,你可以看到2个门户实例。每一个都是完全独立的门户,不同的用户、网站。在左边的门户实例中描述了2个用户:一个用户是一个独立站点的成员,而另一个用户是一个组织的成员,它本身有一个站点。
默认字段 Company ID,Group ID,User ID 就是提供了数据范围的支持。
然后创建Finders
创建后的代码:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_2_0.dtd"> <service-builder package-path="com.liferay.docs.guestbook"> <author>wangxin</author> <namespace>GB</namespace> <entity name="Guestbook" local-service="true"> <!-- PK fields --> <column name="guestbookId" type="long" primary="true"></column> <!-- Group instance --> <column name="groupId" type="long"></column> <!-- Audit fields --> <column name="companyId" type="long"></column> <column name="userId" type="long"></column> <column name="userName" type="String"></column> <column name="createDate" type="Date"></column> <column name="modifiedDate" type="Date"></column> <column name="name" type="String"></column> <finder name="GroupId" return-type="Collection"> <finder-column name="groupId"></finder-column> </finder> </entity> <entity name="Entry"> <!-- PK fields --> <column name="entryId" type="long" primary="true"></column> <!-- Group instance --> <column name="groupId" type="long"></column> <!-- Audit fields --> <column name="companyId" type="long"></column> <column name="userId" type="long"></column> <column name="userName" type="String"></column> <column name="createDate" type="Date"></column> <column name="modifiedDate" type="Date"></column> <column name="name" type="String"></column> <column name="email" type="String"></column> <column name="message" type="String"></column> <column filter-primary="false" name="guestbookId" primary="false" type="long"></column> <finder name="G_G" return-type="Collection"> <finder-column name="groupId"></finder-column> <finder-column name="guestbookId"></finder-column> </finder> </entity> <exceptions> <exception>GuestbookName</exception> <exception>EntryName</exception> <exception>EntryMessage</exception> <exception>EntryEmail</exception> </exceptions> </service-builder>
并且编译:
Liferay的代码生成器生成了持久化层代码,但控制器、服务层、视图层的具体实现需要开发人员自己做,这样保证了极大的灵活性。
ServiceContext 是Liferay提供上下文访问的核心类,真的是非常强大:
视图层的一些代码,AUI是YUI的扩展。
<%@include file = "/html/init.jsp" %> <portlet:renderURL var="viewURL"> <portlet:param name="mvcPath" value="/html/guestbook/view.jsp"></portlet:param> </portlet:renderURL> <portlet:actionURL name="addGuestbook" var="addGuestbookURL"></portlet:actionURL> <aui:form action="<%= addGuestbookURL %>" name="<portlet:namespace />fm"> <aui:fieldset> <aui:input name="name" /> </aui:fieldset> <aui:button-row> <aui:button type="submit"></aui:button> <aui:button type="cancel" onClick="<%= viewURL %>"></aui:button> </aui:button-row> </aui:form>
前端界面
控制器代码
package com.liferay.docs.guestbook.portlet; import com.liferay.docs.guestbook.model.Entry; import com.liferay.docs.guestbook.model.Guestbook; import com.liferay.docs.guestbook.service.EntryLocalServiceUtil; import com.liferay.docs.guestbook.service.GuestbookLocalServiceUtil; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.exception.SystemException; import com.liferay.portal.kernel.servlet.SessionErrors; import com.liferay.portal.kernel.servlet.SessionMessages; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.portal.service.ServiceContext; import com.liferay.portal.service.ServiceContextFactory; import com.liferay.portal.util.PortalUtil; import com.liferay.util.bridges.mvc.MVCPortlet; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.PortletException; import javax.portlet.PortletPreferences; import javax.portlet.ReadOnlyException; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.ValidatorException; import java.util.logging.Level; import java.util.logging.Logger; /** * Portlet implementation class GuestbookPortlet */ public class GuestbookPortlet extends MVCPortlet { public void addGuestbook(ActionRequest request, ActionResponse response) throws PortalException, SystemException { ServiceContext serviceContext = ServiceContextFactory.getInstance( Guestbook.class.getName(), request); String name = ParamUtil.getString(request, "name"); try { GuestbookLocalServiceUtil.addGuestbook(serviceContext.getUserId(), name, serviceContext); SessionMessages.add(request, "guestbookAdded"); } catch (Exception e) { SessionErrors.add(request, e.getClass().getName()); response.setRenderParameter("mvcPath", "/html/guestbook/edit_guestbook.jsp"); } } public void addEntry(ActionRequest request, ActionResponse response) throws PortalException, SystemException { ServiceContext serviceContext = ServiceContextFactory.getInstance( Entry.class.getName(), request); String userName = ParamUtil.getString(request, "name"); String email = ParamUtil.getString(request, "email"); String message = ParamUtil.getString(request, "message"); long guestbookId = ParamUtil.getLong(request, "guestbookId"); try { EntryLocalServiceUtil.addEntry(serviceContext.getUserId(), guestbookId, userName, email, message, serviceContext); SessionMessages.add(request, "entryAdded"); response.setRenderParameter("guestbookId", Long.toString(guestbookId)); } catch (Exception e) { SessionErrors.add(request, e.getClass().getName()); PortalUtil.copyRequestParameters(request, response); response.setRenderParameter("mvcPath", "/html/guestbook/edit_entry.jsp"); } } @Override public void render(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException { try { ServiceContext serviceContext = ServiceContextFactory.getInstance( Guestbook.class.getName(), renderRequest); long groupId = serviceContext.getScopeGroupId(); long guestbookId = ParamUtil.getLong(renderRequest, "guestbookId"); List<Guestbook> guestbooks = GuestbookLocalServiceUtil .getGuestbooks(groupId); if (guestbooks.size() == 0) { Guestbook guestbook = GuestbookLocalServiceUtil.addGuestbook( serviceContext.getUserId(), "Main", serviceContext); guestbookId = guestbook.getGuestbookId(); } if (!(guestbookId > 0)) { guestbookId = guestbooks.get(0).getGuestbookId(); } renderRequest.setAttribute("guestbookId", guestbookId); } catch (Exception e) { throw new PortletException(e); } super.render(renderRequest, renderResponse); } }
完整代码下载 Source Code
目前维护的开源产品:https://gitee.com/475660