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

时间: 2024-10-01 07:47:40

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.liferay.com/zh/community/wiki/-/wiki/Main/Portlet%E9%97%B4%E7%9A%84%E9%80%9A%E4%BF%A1 方式1:Session portlet session作用域: APPLICATION_SCOPE  :全局 PORTLET_

Liferay7 BPM门户开发之28: Portlet文件上传,及实体类同步更新上传

抓住核心 -- 王昕 Liferay文件上传的核心就是使用UploadPortletRequest类 继承关系java.lang.Object extended byjavax.servlet.ServletRequestWrapper extended byjavax.servlet.http.HttpServletRequestWrapper extended bycom.liferay.util.servlet.UploadPortletRequest 实现关系:Implemented I

Liferay7 BPM门户开发之37: Liferay7下的OSGi Hook集成开发

hook开发是Liferay客制扩展的一种方式,比插件灵活,即可以扩展liferay门户,也能对原有特性进行更改,Liferay有许多内置的服务,比如用hook甚至可以覆盖Liferay服务. 可作为系统服务挂钩(Liferay Service Hook),还有其他类型的hook... Liferay6.2 时的hook开发比较有限,而在Liferay7则大为不同,OSGi services的彻底改进至Liferay的底层模型框架,使得Liferay可以支持更多的定制扩展!OSGi plugin

Liferay7 BPM门户开发之36: 使用Portlet filters过滤器做切面AOP

使用Portlet filters过滤器做切面AOP Portlet Filters定义于JSR286 Java Portlet Specification 2.0 Portlet Filters是为了在4个生命周期的过程中,提供外部的AOP支持,这非常不显眼,但也很有用,比如可以用在Liferay的Hook开发中.JSR286 Java Portlet Specification 2.0 的更多介绍:http://www.ibm.com/developerworks/websphere/lib

Liferay7 BPM门户开发之32: 实现自定义认证登陆(定制Authentication Hook)

优秀的平台必然松耦合.易扩展  -- 王昕 第一步:修改liferay-hook.xml <?xml version="1.0"?> <!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.2.0//EN" "http://www.liferay.com/dtd/liferay-hook_6_2_0.dtd"> <hook> <portal-properties>

Liferay7 BPM门户开发之14: Liferay开发体系简介

Liferay SDK 开发体系 主要分6种: Portlet Hook Theme Layout Templates Web Modules Ext Portlet :类似于servlet的web组件,编译后是war包,是页面的组成元素,可以把它理解为一个web APP 详细介绍:https://web.liferay.com/zh/products/what-is-a-portal/web-platform Hook:钩子插件,用来覆盖门户的JSP文件和配置文件,适用于仅需要少量(jsp)代

Liferay7 BPM门户开发之39: Form表单提交的ProcessAction处理

在v6.2开始后,需要设置<requires-namespaced-parameters>false</requires-namespaced-parameters>  来避免在jsp中写<portlet:namespace/>的input前缀 在v7.0发现,注解方式是不灵的! 即  "javax.portlet.requires-namespaced-parameters=false", 无效果, 真是汗... 但我们是有办法在7.0中解决的,直

Liferay7 BPM门户开发之41: Expando API入门

Expando 是liferay的一种自定义表格扩展的方式,从5.0就已存在 , 可以在运行时新建表格\字段\行\值. 这是一种Service Builder之外的轻量级替代扩展方式,不必像Service Builder那么繁琐, 实现的具体技术实际上是列转行,其中ExpandoValue有点像Activiti的act_ru_variable 主要有4种接口,分别是表\行\列\值 ExpandoTableLocalServiceUtil ExpandoRowLocalServiceUtil Ex

Liferay7 BPM门户开发之8: Activiti实用问题集合

1.如何实现审核的上级获取(任务逐级审批) 这个是必备功能,通过Spring的注入+Activiti表达式可以很容易解决. 可参考: http://blog.csdn.net/sunxing007/article/details/8491552 http://linhongyu.blog.51cto.com/6373370/1656596 2.如何设置流程发起人,并动态在其他任务中使用 通过变量,在启动的时候设置. activiti里设置流程发起人的功能很绕. activiti 指定发起人,并作