Liferay7 BPM门户开发之17: Portlet 生命周期
Portlet 生命周期
init() =〉 render() =〉 processAction() =〉 processEvent() =〉 serveResource() =〉destroy()
- init()
在Liferay容器部署portlet时,启动portlet实例化
init有两个写法:
- public void init() throws PortletException
- public void init(PortletConfig config) throws PortletException
PortletConfig对象用于读取portlet配置(定义在portlet.xml)
- render()
HTML的UI输出,是最常用到的方法了,一个例子
- @Override
- public void render(RenderRequest request, RenderResponse response)
- throws PortletException, IOException {
- _log.info(" 做些你自己定义的事情");
- super.render(request, response);
- }
值得注意的是:
- 在render()的一般最后一行,需要写这句:super.render(request,response),如果不写会不能正常工作,会造成GenericPortlet继承链的断裂(render() 在GenericPortlet中被重写);
- Portlet不能直接访问ServletRequest和ServletResponse;
- RenderRequest和RenderResponse是接口,继承于PortletRequest和PortletResponse;
- 如果一个页面有多个Portlets,当每次页面刷新,所有Portlets实例的render()就会被全部调用一次;
- 有趣的是,Portlet规范并没有一个排序的机制,去安排这些Portlets的render()顺序,这证明了Portlet的独立性,如果要定制开发时序的加载,那必须自己去实现一个GenericPortlet的子类,或者直接扩展MVCPortlet,增加一个加载队列。
- processAction()
action 处理,后面再详细介绍,这里只要知道ActionRequest也是一个接口继承
- processEvent()
监听时间处理
- serveResource()
通过resource URL处理资源
- destroy()
portlet卸载时的处理
Portlet 容器负责的工作
- 装载portlet类
- 创建portlet实例
- 初始化
- 向portlet实例发送用户请求(request)
- 销毁实例(当容器卸载portlet)
Portlet和Servlet的区别
见:
Liferay7 BPM门户开发之15: Liferay开发体系简介
Portlet类的层次
- GenericPortlet实现了Portlet接口;
- LiferayPortlet是GenericPortlet的子类,并且提供了一些额外方法;
- MVCPortlet继承与LiferayPortlet.提供了用于MVC架构的一些方法;
- UserCustomPortlet (用户定义portlet)继承与MVCPorrtlet;
URLs 传递
- Portlet在开发调试时不如servlet中那样方便直接,无法定义静态指定地址url,而是通过以下几种方式:
- Render URL:call render method,用于界面控制
- Action URL:call action method,用于服务调用
- Resource URL:call serve resource method,用于访问资源
Render 处理
首先,介绍Render URL,有四种方式:
方式1、Portlet Tag (portlet:renderURL)
view.jsp
- <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@page import="com.liferay.portal.kernel.portlet.LiferayPortletMode"%>
<%@page import="com.liferay.portal.kernel.portlet.LiferayWindowState"%>
- <portlet:renderURL var="renderUrl"
- windowState="<%=LiferayWindowState.NORMAL.toString() %>" copyCurrentRenderParameters="true" portletMode="<%=LiferayPortletMode.VIEW.toString()%>">
- <portlet:param name="param" value="XXXXXX"/>
- </portlet:renderURL>
- <a href="${renderUrl}">RenderURL Created by Portlet Tag</a>
- render()
- private static final Log _log = LogFactoryUtil.getLog(YourPortlet.class.getName());
- @Override
- public void render(RenderRequest request, RenderResponse response)
- throws PortletException, IOException {
- _log.info(" This is render method");
- String data = request.getParameter("param");
- String data1= ParamUtil.getString(request, "param","");
- super.render(request, response);
- }
最终会实际产生以下URL:
http://localhost:8080/web/portletTest/test?
- p_p_id=renderURLbyportletTag_WAR_renderURLbyportlet
- &p_p_lifecycle=0
- &p_p_state=normal
- &p_p_mode=view
- &p_p_col_id=column-1
- &p_p_col_count=1
- &_renderURLbyportletTag_WAR_renderURLbyportlet_param=XXXXXX
p_p_id 是portlet Id
p_p_lifecycle是生命周期的当前阶段,定义是:0 – render;1 – action;2 – serve resource;
p_p_col_id是多列布局中的当前页第几列;
p_p_col_count是当前页的布局总列数;
最后一个就是用户定自定url参数了,由jsp传递;
方式2、PortletURLFactoryUtil 方式
这种是服务端直接控制,jsp基本不用写什么逻辑,后台控比较喜欢用
- render()
- @Override
- public void render(RenderRequest request, RenderResponse response)
- throws PortletException, IOException {
- _log.info(" This is render method of RenderURLByJavaAPIPortlet");
- String data = request.getParameter("param");
- String data1= ParamUtil.getString(request, "param","");
- ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY);
- PortletURL renderUrl = PortletURLFactoryUtil.create(request, themeDisplay.getPortletDisplay().getId(), themeDisplay.getPlid(), PortletRequest.RENDER_PHASE);
- renderUrl.setWindowState(LiferayWindowState.NORMAL);
- renderUrl.setPortletMode(LiferayPortletMode.VIEW);
- renderUrl.setParameter("param", "This parameter comes from Render URL generated with Java API");
- request.setAttribute("renderUrlByJavaAPI", renderUrl.toString());
- super.render(request, response);
- }
其中,plid 是page layout id
在jsp中,只用一行代码:
<a href="${renderUrlByJavaAPI}">Render Url created by Java API</a>
还有一种灵活方式,即可以由jsp来直接输出
- <%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
- <liferay-theme:defineObjects/>
- <%
- PortletURL renderUrlFromJSP = renderResponse.createRenderURL();
- renderUrlFromJSP.setParameter("param1", "This portletULR is created with API in JSP");
- renderUrlFromJSP.setWindowState(LiferayWindowState.NORMAL);
- renderUrlFromJSP.setPortletMode(LiferayPortletMode.VIEW);
- %>
- <a href="<%=renderUrlFromJSP%>">Render Url created by JSP</a>
方式3:Liferay Tag (liferay-portlet:renderURL)
- view.jsp
- <%@ taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet" %>
- <liferay-portlet:renderURL var="openPortletURL" copyCurrentRenderParameters="true" portletMode="<%=LiferayPortletMode.VIEW.toString() %>"
- windowState="<%=LiferayWindowState.NORMAL.toString()%>">
- <liferay-portlet:param name="param" value="This is from Liferay TAG"/>
- </liferay-portlet:renderURL>
- <a href="${openPortletURL}">Render Url created by Liferay TAG in JSP</a>
render() 同第一种写法(Portlet Tag方式)
方式4:JavaScript (by AUI)
- view.jsp
- <%@page import="com.liferay.portal.kernel.portlet.LiferayWindowState"%>
- <%@page import="com.liferay.portal.kernel.portlet.LiferayPortletMode"%>
- <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
- <%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>
- <%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
- <liferay-theme:defineObjects/>
- <portlet:defineObjects />
- <a id="renderURLWithJS" href=""> This render URL link is created with Javascript</a>
- <aui:script>
- AUI().use('liferay-portlet-url', function(A) {
- var renderUrl1 = Liferay.PortletURL.createRenderURL();
- renderUrl1.setWindowState("<%=LiferayWindowState.NORMAL.toString() %>");
- renderUrl1.setParameter("param","This value comes from Javascript");
- renderUrl1.setPortletMode("<%=LiferayPortletMode.VIEW %>");
- renderUrl1.setPortletId("<%=themeDisplay.getPortletDisplay().getId() %>");
- A.one("#renderURLWithJS").set('href',renderUrl1.toString());
- alert("renderUrl1 is ->"+renderUrl1.toString());
- alert(A.one("#renderURLWithJS").attr("href"));
- });
- </aui:script>
- 这种比较不常用
render() 同第一种写法(Portlet Tag方式)
action 处理
在涉及页面处理业务逻辑,或其他Portlet交互,或者Form提交Action时,就需要我们定义Action方法,actionURL 就是用来传递Action的id
它是和jsp一对一对应的,比如jsp中:
- view.jsp
- <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
- <portlet:defineObjects />
- User Name is : <b> ${userName}</b>
- <portlet:actionURL name="actionMethod1" var="sampleActionMethodURL">
- </portlet:actionURL>
- <form action="${sampleActionMethodURL}" method="post">
- UserName :-<input type="text" name="userName"><br>
- <input type="submit" value="Submit">
- </form>
- <portlet:actionURL name="addName" var="addNameUrl"></portlet:actionURL>
- <a href="${addNameUrl}">Add Name</a>
前提还要定义portlet.xml
- portlet.xml首先要定义
- <portlet-name>custom-liferaymvc</portlet-name>
- <display-name>Custom Liferaymvc</display-name>
- <portlet-class>com.companyname.portlet.CustomMVCPortlet</portlet-class>
- <init-param>
- <name>view-jsp</name>
- <value>/jsp/view.jsp</value>
- </init-param>
编写一个继承MVCPortlet的类
- @ProcessAction(name="addName")
- public void addName(ActionRequest actionRequest,
- ActionResponse actionResponse) throws IOException, PortletException, PortalException, SystemException{
- actionRequest.setAttribute("userName", "Wangxin");
- }
- @ProcessAction(name="actionMethod1")
- public void sampleActionMethod(ActionRequest request, ActionResponse response)
- throws IOException, PortletException, PortalException, SystemException{
- _log.info("This is sampleActionMethod ...");
- String userName = ParamUtil.get(actionRequest, "userName", StringPool.BLANK);
- actionRequest.setAttribute("userName", userName);
- }
如果跟踪一下,会是自动产生以下url:
http://localhost:8080/web/home?p_auth=e6cvA8tX
&p_p_id=testactionmethod_WAR_testactionmethodportlet
&p_p_lifecycle=1
&p_p_state=normal
&p_p_mode=view
&p_p_col_id=column-1
&_testactionmethod_WAR_testactionmethodportlet_javax.portlet.action=actionMethod1
另外PortletURLFactoryUtil 是一种后台产生action url的常用方式
- java code:
- @Override
- public void render(RenderRequest request, RenderResponse response)
- throws PortletException, IOException {
- ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY);
- PortletURL actionUrl = PortletURLFactoryUtil.create(request, themeDisplay.getPortletDisplay().getId(), themeDisplay.getPlid(), PortletRequest.ACTION_PHASE);
- actionUrl.setWindowState(LiferayWindowState.NORMAL);
- actionUrl.setPortletMode(LiferayPortletMode.VIEW);
- actionUrl.setParameter("javax.portlet.action", "actionMethodByJavaApi");
- actionUrl.setParameter("sampleParam", "This parameter comes from Action URL generated with Java API");
- request.setAttribute("actionUrlByJavaAPI", actionUrl.toString());
- super.render(request, response);
- }
- @ProcessAction(name="actionMethodByJavaApi")
- public void actionMethodByJavaApi(ActionRequest request, ActionResponse response)
- throws IOException, PortletException, PortalException, SystemException{
- String sampleParam = ParamUtil.get(request, "sampleParam", "defaultValue");
- _log.info("Sample Param is ::"+sampleParam);
- }
- view.jsp
- <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
- <portlet:defineObjects />
- <a href="${actionUrlByJavaAPI}">Action Url created by Java API in Portlet Class</a>
- <br>
还有两种方式就不介绍了:
liferay-portlet:actionURL 和 JavaScript (AUI module – Liferay.PortletURL)
一个portlet交互的流程图
resource 处理
Render & action是最早被定义的规范,见portlet specification 1.0 (JSR-168).
resource serving 被定义于portlet specification 2.0 (JSR-286)
一句话概括serve resource做的事情:动态产生输出到客户端,负责向客户端发送动态内容
比如:下载文件,发送一个excle报表,发送xml、json文件......,这些在Render 周期是无法实现的
serve resource过程
这里有比较好的介绍:
http://www.oracle.com/technetwork/java/jsr286-2-141964.html
7.0版的Command设计模式
在7.0版,整个一套处理设计为注解方式了,摒弃了满屏混乱的XML配置,更加清晰直观,代码结构更好
有三种命令接口:
- MVCActionCommand
- MVCRenderCommand
- MVCResourceCommand
其中
BaseMVCActionCommand(class)实现=> MVCActionCommand(interface)
定制Portlet类
- @Component(
- immediate = true,
- property = {
- "com.liferay.portlet.css-class-wrapper=portlet-hello-world",
- "com.liferay.portlet.display-category=category.sample",
- "com.liferay.portlet.icon=/icons/hello_world.png",
- "com.liferay.portlet.preferences-owned-by-group=true",
- "com.liferay.portlet.private-request-attributes=false",
- "com.liferay.portlet.private-session-attributes=false",
- "com.liferay.portlet.remoteable=true",
- "com.liferay.portlet.render-weight=50",
- "com.liferay.portlet.use-default-template=true",
- "javax.portlet.display-name=Hello World",
- "javax.portlet.expiration-cache=0",
- "javax.portlet.init-param.always-display-default-configuration-icons=true",
- "javax.portlet.name=" + HelloWorldPortletKeys.HELLO_WORLD,
- "javax.portlet.resource-bundle=content.Language",
- "javax.portlet.security-role-ref=guest,power-user,user",
- "javax.portlet.supports.mime-type=text/html"
- },
- service = Portlet.class
- )
- public class HelloWorldPortlet extends MVCPortlet {
- ......
- }
action command
比如一个action URL用于编辑实体,指向edit_entry.jsp
- <portlet:actionURL name="/blogs/edit_entry" var="editEntryURL" />
action URL被触发后,匹配的action类将会被处理,可以有两种方式实现action command,一是实现接口MVCActionCommand,二是直接继承BaseMVCActionCommand类,liferay官方是推荐第二种,因为已经实现了很多有用的方法。
你的XXXXMVCActionCommand 类必需有@Componet注解,是为了OSGI容器反射得到类,例子:
- @Component(
- immediate = true,
- property = {
- "javax.portlet.name=Your_portlet_name",
- "mvc.command.name=/blogs/edit_entry"
- },
- service = MVCActionCommand.class
- )
- public class YourMVCActionCommand extends BaseMVCActionCommand {
- // your action
- }
比如一个增加实体的方法
- 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 {
- _guestbookService.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");
- }
- }
MVC render command
需要定义三件事情:
- 实现MVCRenderCommand interface;
- 在视图创建portlet render URL;
- Component注解定义MVCRenderCommand service;
一个最简单的render
- @Component(
- immediate = true,
- property = {
- "javax.portlet.name=" + HelloWorldPortletKeys.HELLO_WORLD,
- "javax.portlet.name=" + HelloWorldPortletKeys.HELLO_OTHER_WORLD,
- "mvc.command.name=/hello/edit_entry"
- },
- service = MVCRenderCommand.class
- )
- public class EditEntryMVCRenderCommand implements MVCRenderCommand {
- @Override
- public String render(
- RenderRequest renderRequest, RenderResponse renderResponse)
- throws PortletException {
- try {
- Blog entry = ActionUtil.getEntry(renderRequest);
- }
- catch (Exception e) {
- if (e instanceof NoSuchEntryException ||
- e instanceof PrincipalException) {
- SessionErrors.add(renderRequest, e.getClass());
- return "/hello/error.jsp";
- }
- else {
- throw new PortletException(e);
- }
- }
- return "/hello/edit_entry.jsp";
- }
- }
javax.portlet.name被定义了2个,这代表它可以在2个portlet中使用。
URL:
- <portlet:renderURL var="editEntryURL">
- <portlet:param name="mvcRenderCommandName" value="/hello/edit_entry" />
- <portlet:param name="entryId" value="<%= String.valueOf(entry.getEntryId()) %>" />
- </portlet:renderURL>
一个较详细的例子:
- @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 = _guestbookService
- .getGuestbooks(groupId);
- if (guestbooks.size() == ) {
- Guestbook guestbook = _guestbookService.addGuestbook(
- serviceContext.getUserId(), "Main", serviceContext);
- guestbookId = guestbook.getGuestbookId();
- }
- if (!(guestbookId > )) {
- guestbookId = guestbooks.get().getGuestbookId();
- }
- renderRequest.setAttribute("guestbookId", guestbookId);
- } catch (Exception e) {
- throw new PortletException(e);
- }
- super.render(renderRequest, renderResponse);
- }
MVC serveResource command
- @Component(
- property = {
- "javax.portlet.name=" + LoginPortletKeys.FAST_LOGIN,
- "javax.portlet.name=" + LoginPortletKeys.LOGIN,
- "mvc.command.name=/login/captcha"
- },
- service = MVCResourceCommand.class
- )
- public class CaptchaMVCResourceCommand implements MVCResourceCommand {
- @Override
- public boolean serveResource(
- ResourceRequest resourceRequest, ResourceResponse resourceResponse) {
- try {
- CaptchaUtil.serveImage(resourceRequest, resourceResponse);
- return false;
- }
- catch (Exception e) {
- _log.error(e, e);
- return true;
- }
- }
- private static final Log _log = LogFactoryUtil.getLog(
- CaptchaMVCResourceCommand.class);
- }
目前7.0的文档还太少。
Liferay7 BPM门户开发之17: Portlet 生命周期的更多相关文章
- Liferay7 BPM门户开发之33: Portlet之间通信的3种方式(session、IPC Render Parameter、IPC Event、Cookies)
文章介绍了5种方式,4种是比较常用的: Portlet session IPC Public Render Parameters IPC Event Cookies 参考地址: https://web ...
- Liferay7 BPM门户开发之28: Portlet文件上传,及实体类同步更新上传
抓住核心 . Liferay文件上传的核心就是使用UploadPortletRequest类 继承关系java.lang.Object extended byjavax.servlet.Servlet ...
- Liferay7 BPM门户开发之10: 通用流程实现从Servlet到Portlet(Part1)
开发目的: 实现通用流程自动化处理(即实现不需要hardcode代码的bpm统一处理后台,仅需要写少量前端html form代码和拖拽设计BPM定义) 既可独立运行或可依托于Liferay或依托其它门 ...
- Liferay7 BPM门户开发之37: Liferay7下的OSGi Hook集成开发
hook开发是Liferay客制扩展的一种方式,比插件灵活,即可以扩展liferay门户,也能对原有特性进行更改,Liferay有许多内置的服务,比如用hook甚至可以覆盖Liferay服务. 可作为 ...
- Liferay7 BPM门户开发之36: 使用Portlet filters过滤器做切面AOP
使用Portlet filters过滤器做切面AOP Portlet Filters定义于JSR286 Java Portlet Specification 2.0 Portlet Filters是为 ...
- Liferay7 BPM门户开发之15: Liferay开发体系简介
Liferay SDK 开发体系 主要分6种: Portlet Hook Theme Layout Templates Web Modules Ext Portlet :类似于servlet的web组 ...
- Liferay7 BPM门户开发之12:acitiviti和liferay用户权限体系集成
写到第12章才出现Liferay的内容,希望可以厚积薄发. 我们的目标是不使用不维护Activiti的用户组织架构,只维护Liferay的体系,这样的好处是非常明显的,即不用做组织架构的同步工作. 原 ...
- Liferay7 BPM门户开发之27: MVC Portlet插件工程开发
官网上的教材说实话实在精简不清晰. https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/creating-an-mvc-por ...
- Liferay7 BPM门户开发之44: 集成Activiti展示流程列表
处理依赖关系 集成Activiti之前,必须搞清楚其中的依赖关系,才能在Gradle里进行配置. 依赖关系: 例如,其中activiti-engine依赖于activiti-bpmn-converte ...
随机推荐
- chrome.debugger
官网: https://chromedevtools.github.io/devtools-protocol/ https://developer.chrome.com/extensions/debu ...
- springboot寻找property的顺序
Spring Boot uses a very particular PropertySource order that is designed to allow sensible overridin ...
- c++ 面试题(算法类)
1,从无序的数据流中找到其中位数:(用大根堆和小根堆来实现) float getMidimum(vector<int>& nums) { priority_queue<int ...
- Java17-java语法基础——泛型
Java18-java语法基础——泛型 一.泛型概念和作用 1.泛型概念: 泛型是JavaSE1.5的新特性,泛型的本质是参数化类型,也就是说,所操作的数据类型被指定为一个参数.这种参数类型可以用在类 ...
- 单点登录(SSO)原理与案例
单点登录业务流程 概要 详细流程 单点登录系统一共有三个模块,1.服务端 2.客户端 3.代理模块端 用户发送访问客户端的请求,被客户端的代理模块的拦截器拦截,判断cookie中是否含有token(令 ...
- java 组件开发中的日志记录问题
今天帮别人写封装几个url 请求,打成jar 包,可以以java接口的方式提供给外部访问. 遇到两个问题: 1. 是否把依赖的jar包也 打入 我要生成的jar包中,如果你不打入,别人直接调用接口会报 ...
- MySQL安装及后续配置
rpm -qa | grep mysql 检查已安装的mysql版本 rpm -e --nodeps mysql-libs-5.1.71 卸载 tar -zxvf MySQL.tar.gz 解压 安 ...
- More x64 assembler fun-facts–new assembler directives(转载)
原文地址 The Windows x64 ABI (Application Binary Interface) presents some new challenges for assembly pr ...
- kbmmw中向服务器端传递对象的一种简单方式
运行环境:delphi 10.2+kbmmw 5.6.20 在kbmmw 的老版本中,要向服务器传送一个本地的对象,一般都需要进行一些转换,例如通过序列化的方式. 在新版的kbmmw中这一切都变的很简 ...
- 使用GetAdaptersInfo时,网卡类型的值为71
使用GetAdaptersInfo时,网卡类型的值为71,代表无线网卡.