精华内容
下载资源
问答
  • Portlet

    2017-11-29 18:52:00
    在一个 Portal 页面中,通常都包含了多个 Portlet ,在一个时刻用户只能与一个 Portlet 交互,当用户向一个 Portlet 发出请求(例如点击了“ submit ”按钮),整个 Portlet 页面将会重新构成。在这个过程中,是否...
    1、Portlet Request & URL 

          在一个 Portal 页面中,通常都包含了多个 Portlet ,在一个时刻用户只能与一个 Portlet 交互,当用户向一个 Portlet 发出请求(例如点击了“ submit ”按钮),整个 Portlet 页面将会重新构成。在这个过程中,是否有与用户交互的 Portlet 处理方式显然是不同的,而且用户没有与之交互的 Portlet 显然不应该接收到用户的请求参数。
      因此 JSR168 规范中将对 Portlet 的请求分为 Action 和 Render 两种。 Portlet 在收到 Action 请求,获取用户所提交的信息,进行相应的处理;受到 Render 请求后,则生成页面代码。当用户向一个 Portlet 发出请求,该请求被 Portlet 容器接受, Portlet 容器再调用相应 Portlet 的 processAction() 方法;等到 processAction() 方法执行完毕后, Portlet 容器再调用所有 Portlet 的 render() 方法,并将这些方法所返回的内容组合形成一个页面返回给客户端。在上述过程中,所有 Portlet 的 render() 方法的调用次序在规范中没有规定,既可能是有顺序的串行调用,也可能是多线程的同步调用,依赖于厂商的具体实现。

           为了接受用户请求,一个 Portlet 需要有一个指向其自身的 URL ,例如用在 HTTP FORM 的 ACTION 字段。但是与 Servlet 不同的是, Portlet 不是一个完整的页面而只是页面的一部分,一个 Portlet 可以出现在多个页面中,所以 Portlet 无法绑定具体的 URL 。在 JSR168 规范中定义了 PortletURL 接口,通过该接口可以得到指向 Portlet 自身的 URL ,对应两种用户请求有两种产生 URL 的方法: q?4k2@*v_rk*l
    一、for render(): 
    PortletURL url = response.createRenderURL(); www.portalfan.com&S        A(`L v(s
    url.setParameter(“customer”,”foo.com”); 
    url.setParameter(“show”,”summary”); !g{f#vk^
    writer.print(“<A HREF=\””+url.toString()+”\”>Summary</A>”); 

    4x_kUS/^![
    二、for processAction(): 

    `kTi3O

    PortletURL url = response.createActionURL(); 
    url.setParameter(“paymentMethod”,”creditCardInProfile”); 
    url.setWindowState(WindowState.MAXIMIZED); www.portalfan.com1x"p VfH
    writer.print(“<FORM METHOD=\”POST\” ACTION=\””+ url.toString()+”\”>”); 
    (r/aI iI(v/i
    上面的代码我们可以看到,除了得到 URL 外,还可以在其中加入参数。另外由于 Portal 服务器厂商通常都会利用 URL 增加一些产品相关的参数,因此强烈建议在 Portlet 中提交用户请求采用 POST 方式。 

    2、 Portlet Modes & Window States
    在 Portal 应用中,用户通常需要设置、调整 Portlet 的显示方式,对此 JSR168 同样做出了规定。分别有 Portlet Modes 和 Window States 。
    Portlet Modes 说明 Portlet 目前所执行的功能模式,规范要求 Portal 服务器必须支持以下三种模式: www.portalfan.com\        k6k7cWk
    )e-[_lj rq&sI
    q

    VIEW ——内容显示,通常为缺省模式 
    EDIT ——编辑相关的设置 
    HELP ——显示帮助信息 
    除此之外可以Portal服务器可以实现自定义的模式。portal爱好者0XLqXP5iv J

    每个 Portlet 在 Portal 页面中就是一个“窗口”,类似于 MS Windows 、 XWindo 等窗口系统 Portlet 也有自己的窗口状态( Window States ),规范要求 Portal 服务器必须支持以下三种窗口状态 : 
    NORMAL ——普通 portlet 窗口,在这个状态下通常是与其它 Portlet 共享 Portal 页面; portal爱好者t8u/O/F;F
    MAXIMIZED ——最大化 portlet 窗口,独占 Portal 页面; 

    J&?'X$az9u_eJ

    MINMIZED ——最小化 portlet 窗口 #la|M@!YP?2N g
    除此之外可以Portal服务器可以实现自定义的窗口状态         
    在规范中对这些特性进行定义,使得 Portlet 开发者无需关心这方面实现细节,另外在 processAction() 和 render() 方法中开发者都可以通过 getPortletMode() 和 getWindowState() 等方法获得当前 Portlet 的情况从而决定相关操作。 

    3、Preferences & User Information say?d
    Portal 应用一个重要功能就是“个性化”,一方面 Portal 服务器需要根据用户的不同显示不同的 Portlet ,另一方面同一个 Portlet 也会根据用户的偏好显示不同的内容。这就要求 Portlet 需要保存一些用户的相关信息,例如一个股票实时信息的 Portlet 会根据用户所关注的股票显示相应的信息。
    每个 Portlet 都可能有自己相应的个性化信息, JSR168 规范提供了 PortletPreferences 接口来操纵这些信息。   
    PortletPreferences 接口提供读取、设置属性的方法,如下:
    PortletPreferences prefs = req.getPreferences(); 
    String[] symbols = prefs.getValues(”preferredStockSymbols”, l&Fnew String[]{”ACME”,”FOO”}); www.portalfan.com*J4WF2WI qg
    #f_,[$j({6M

    d,NG1r(`*NUp

      在 JSR168 规范中 PortletPreferences 是用户相关的,也就是通过 getPreferences() 获得的对象是与当前登录用户绑定的, PortletPreferences 不会在用户之间共享属性。 lg4a {^a2zb q        ]
            PortletPreferences 提供了一个基本的读取、设置个性化属性的途径,使得 Portlet 无需依赖具体的数据储存环境(例如数据库联接、表结构等等)就可以实现个性化并能够在不同的 Portal 服务器之间移植。但是不应该使用 PortletPreferences 来替代一般的数据库功能。
           在实现个性化功能中经常需要获取各种用户信息,例如用户姓名、地址等等。因此 JSR168 也提供了一个获取用户信息的途径,如下:
    SK2B7KK
    ~}
    n%R3I

    Map userInfo = (Map) request.getAttribute(PortletRequest.USER_INFO); 
    String givenName = (userInfo!=null) ? (String) userInfo.get(“user.name.given”) : “”; 
    String lastName = (userInfo!=null) ? (String) userInfo.get(“user.name.family”) : “”; 
    所获得的 Map 对象是一个只读对象,不能更改。但是用户信息应该包含什么内容不在 JSR168 规范的范围,事实上目前还没有关于访问用户信息的 Java 标准, JSR168 提到在以后形成访问用户信息的 Java 标准时,当前的机制就会被取代。

    4、Sessions 
    K5u{g|)Q
    w

    portal爱好者SS"uu+~`
    作为一个 Web 应用组件, Portlet 同样有 Session 这个机制用于跟踪用户操作,而与一般的 Web 应用所不同的是 Portlet 的 Session 属性有两种作用域:fi
    PORTLET_SCOPE:属性只能被设置它的Portlet访问
    APPLICATION_SCOPE:属性可以被同一个Portal应用中的所有Portlet访问 
    4VgU\;F

    PortletSession session = request.getSession(true); 
    URL url = new URL(“
    http://www.foo.com ”); 
    session.setAttribute(“home.url”,url,PortletSession.APPLICATION_SCOPE); 
    session.setAttribute(“bkg.color”,”RED”,PortletSession.PORTLET_SCOPE);  

    5、Request Dispatch & Portlet Tag 
    在实现 Portlet 应用时,开发者往往会利用 Servlet 、 JSP 等资源,起码会有两个目的会这样做: 为了利用现有的资源,简单地将已经写好的 Servlet 、 JSP 应用转换成 Portlet ;  方便 Portlet 的表现层开发。 Portlet 规范类似于 Servlet 规范,在表现层开发上远远不如 JSP ,因此需要利用 JSP 来开发界面。
    JSR168  提供了类似 Servlet RequestDispatcher 的接口来实现利用 Servlet 、 JSP 等资源的功能。
    例子如下: 
    portal爱好者.c
    oJ#m|7SJ,M2vh

    String path = "/raisons.jsp?orderno=5"; portal爱好者'J0q|lh:Vu&[']
    PortletRequestDispatcher rd = context.getRequestDispatcher(path); rd.include(renderRequest, renderResponse);  
    当一个 JSP 页面需要作为 Portlet 应用的一部分, JSP 开发者需要获得相关的 Portlet 信息,为此 JSR168 提供了相应的 JSP Tag 来实现相关的功能。通过相应的 Portlet Tag , JSP 开发者可以获得相应的 Portlet Request/Response 对象,产生 ActionURL 或者 RenderURL 等等。

    5、缓存qB&gWN(N_
    www.portalfan.com/yza"x1g-PB1C
    在前面中我们知道,用户每次向Portal 应用发送一个请求,该页面中所有的 Portlet 都会被 Portlet 容器调用 render() 方法来产生相应内容。但是只有一个 Portlet 才会处理用户请求,其它不处理用户请求的 Portlet 可能每次的显示内容都是不变的。 
    因此 JSR168 定义了缓存机制来提供 Portal 应用的效率。在 portlet.xml 中可以定义缓存的失效时间,如下:
    portal爱好者)y2C$\7m.E
    <portlet> R`Xh M5co i
    ...
    <expiration-cache>300</expiration-cache> 
    ... 
    </portlet> 
    这样 Portlet 容器在调用 Portlet 的 render() 方法之前就会检查有缓存是否已经有效,如果有效的话就直接使用缓存内容。 Portlet 缓存是跟客户端相关的,不同的客户端访问同一个 Portlet 分别有自己的缓存而不会混淆。JSR168 对缓存机制的实现不是强制性的, Portal 服务器厂商可以自行决定是否实现这个特性。 

    6、CSS Style Definition 
    在一个 Portlet 应用中,所有 Portlet 应该具有显示上的一致性,例如使用相同的字体等等。为了到达这一点, JSR168 定义了一套 CSS 元素名称, Portlet 开发者都应该采用这套 CSS 来产生显示内容。这套 CSS 定义主要包含了 Fonts 、 Message (例如告警、通知等等)、 Sections 、 Forms 。

    7、Portlet VS Servlet
    Portlet 和 Servlet 是十分类似的,只是由于 Servlet 无法达到 Portal 应用的要求 JCP 才定义了新的 Portlet 规范,为了尽可能与现有的 Servlet 结合达到重复使用的目的, portlet 的规范利用了 Servlet 的规范,许多观念都很相似的。在讲述了 Portlet 的特性后,我们再来看看他们直接的异同。相似之处:]3b        AC|Z2g
    Portlet 也是 Java 技术的 web 组件 z&MBh[]        T6sEy
    Portlet 也是有特定的 container 在管理 
    Portlet 可以动态产生各种内容 &X3Z$r0]W9J)_
    Portlet 的生命周期由 container 所管理 bf;YKx
    Portlet 和客户端的互动是通过 request/response 的机制
    wZ

    不同之处: 
    portal爱好者 D(e9g$MA2W{L
    Portlet 只产生 markup 信息片段,不是完整的网页文件
    Portlet 不会和 URL 有直接的关系
    客户端必须通过 Portal 系统才能和 Portlet 互动
    Portlet 有一些定义好的 request 处理, action request 以及 render request
    Portlet 默认定义 portlet modes 及窗口状态
    Portlet 可以在同一个 portal 网页之中存在多个

    Portlet有的功能而Servlet没有:
    Portlet 能够存取及储存永久配置文件及定制资料
    Portlet 可以存取使用者数据
    Portlet 具有 URL 的重写功能够在它的内容中动态建立连结
    Portlet Session 的属性拥有两个不同的范围: application-scope 及 portlet-scope

    Portlet不具备而Servlet提供的功能
    Servlet 具有设置输出的文字编码 ( character set encoding) 方式
    Servlet 可以设置 HTTP 输出的 header
    Servlet 才能够接收客户对 portal 发出的 URL 请求

     

     

     

    这里所说的网络资源是指图片、js、css等文件资源,对于资源的获取,在servlet2.4规范下的服务器中,我们喜欢的方式为(例如获取图片资源images/a.gif): 
    <img src="${pageContext.request.contextPath}/images/a.gif"/>

    但是在不支持servlet2.4的服务器中,就需要采用其它方式了,一种最为基本的方式如下: 
    <img src="<%=request.getContextPath()%>/images/a.gif"/>

    另外,我们还可以借助jstl来实现: 
    <img src="<c:url value='/images/a.gif'/>" />

    另外,也可以使用portlet的相关标签,例如: 
    <portletAPI:encodeURI path='/images/a.gif' />

    此外,还可以使用PortletResponse的encodeURL方法: 
    <%=portletResponse.encodeURL('/images/a.gif')%>

    这里所说的网络资源是指图片、js、css等文件资源,对于资源的获取,在servlet2.4规范下的服务器中,我们喜欢的方式为(例如获取图片资源images/a.gif): 
    <img src="${pageContext.request.contextPath}/images/a.gif"/>
    但是在不支持servlet2.4的服务器中,就需要采用其它方式了,一种最为基本的方式如下: 
    <img src="<%=request.getContextPath()%>/images/a.gif"/>
    另外,我们还可以借助jstl来实现: 
    <img src="<c:url value='/images/a.gif'/>" />
    另外,也可以使用portlet的相关标签,例如: 
    <portletAPI:encodeURI path='/images/a.gif' />
     这里所说的网络资源是指图片、js、css等文件资源,对于资源的获取,在servlet2.4规范下的服务器中,我们喜欢的方式为(例如获取图片资源images/a.gif): 
    <img src="${pageContext.request.contextPath}/images/a.gif"/>
    但是在不支持servlet2.4的服务器中,就需要采用其它方式了,一种最为基本的方式如下: 
    <img src="<%=request.getContextPath()%>/images/a.gif"/>
    另外,我们还可以借助jstl来实现: 
    <img src="<c:url value='/images/a.gif'/>" />
    另外,也可以使用portlet的相关标签,例如: 
    <portletAPI:encodeURI path='/images/a.gif' />
    此外,还可以使用PortletResponse的encodeURL方法: 
    <%=portletResponse.encodeURL('/images/a.gif')%>
    此外,还可以使用PortletResponse的encodeURL方法: 

    <%=portletResponse.encodeURL('/images/a.gif')%>

    本文转自kenty博客园博客,原文链接http://www.cnblogs.com/kentyshang/archive/2008/04/22/1165474.html如需转载请自行联系原作者


    kenty

    展开全文
  • portlet

    2012-11-27 22:57:49
    portlet portlet portlet
    portlet portlet portlet
    展开全文
  • portlet_Portlet教程

    2020-07-17 15:24:52
    portletWe’ve introduced all of these concepts that would be used while you’re dealing with the Portlet development. Portlet and Portlet container had used several objects that make obligation ...

    portlet

    We’ve introduced all of these concepts that would be used while you’re dealing with the Portlet development. Portlet and Portlet container had used several objects that make obligation between both of them to get their functionality achieved.

    我们介绍了在处理Portlet开发时将使用的所有这些概念。 Portlet和Portlet容器使用了多个对象,这两个对象之间都承担了义务,以实现其功能。

    However, no one of these tutorials have provided you a full detailed explanation for these fine-grained objects. To get into real development, you should be aware of these objects as well as you must have to know what these objects are closely,  how can they are used and when their usage should be to get the most benefit.

    但是,这些教程都没有一个为您提供这些细粒度对象的完整详细说明。 要进行真正的开发,您应该了解这些对象,还必须知道这些对象紧密相关,如何使用它们以及何时应使用它们才能获得最大收益。

    Portlet教程 (Portlet Tutorial)

    This tutorial intended to help you getting these information in an organised manner as it’s also will make you use all of them willingly. Following below core concepts that you would pass through:

    本教程旨在帮助您以有组织的方式获取这些信息,因为它也会使您乐于使用所有这些信息。 遵循以下核心概念:

    Portlet请求 (Portlet Requests)

    As we’ve stated earlier, the PortletRequest interface represents the common functionality that’s lying in RenderRequest interface and ActionRequest interface as both of them have extended the PortletRequest interface.

    如前所述,PortletRequest接口代表了RenderRequest接口和ActionRequest接口中的常用功能,因为它们都扩展了PortletRequest接口。

    PortletRequest interface provides methods for accessing various types of needed information. These information would be:

    PortletRequest接口提供了用于访问各种类型的所需信息的方法。 这些信息将是:

    Request Attributes:  request attributes used mainly to pass Java objects between Portlets, Servlets and JSP pages. These attributes are formed as name/value pairs, in that the String will form the name of the attribute while Java Object is the value.

    请求属性 :请求属性主要用于在Portlet,Servlet和JSP页面之间传递Java对象。 这些属性形成为名称/值对,因为String将形成属性的名称,而Java Object是值。

    As soon as the Portlet receives a new action request, the attributes that were sent previously are no longer available and they will be replaced by new ones. The Portlet may set, update, delete and read attributes during action processing and render processing by invoking request.getAttribute(), request.setAttribute() and request.getAttributeNames().

    Portlet收到新的操作请求后,先前发送的属性将不再可用,并且将被新的替换。 Portlet可以通过调用request.getAttribute()request.setAttribute()request.getAttributeNames()在操作处理和呈现处理期间设置,更新,删除和读取属性。

    Basically, any attributes you’ve set against request while executing of processAction() phase won’t be available by the request object while executing of render() phase. Even Java Portlet Specification 2.0 has  provided the PLT.10.4.4 Runtime Option javax.portlet.actionScopedRequestAttributes that will make your processAction() attributes available while executing of render() phase but unfortunately this feature isn’t implemented in Apache Pluto 2.0.3 as you can refer for Apache Pluto’s JIRA.

    基本上,您在执行processAction()阶段时针对请求设置的任何属性在执行render()阶段时都不能由请求对象使用。 甚至Java Portlet Specification 2.0也提供了PLT.10.4.4运行时选项javax.portlet.actionScopedRequestAttributes ,这些属性将使您的processAction()属性在执行render()阶段时可用,但是不幸的是,该功能未在Apache Pluto 2.0.3中实现。您可以参考Apache Pluto的JIRA

    A more detailed sample would be discussed, especially when it comes to use the JSF bridge that already facilitate sending objects through using of request attributes.

    我们将讨论一个更详细的示例,尤其是在使用JSF桥时,该桥已经通过使用请求属性方便了发送对象。

    Request Parameters:  Request parameters aren’t so differ from discussed request attributes, they’re pairs of name/value where both of them are a String object. The most important issue here are the sources that request parameter come from. Typically, request parameters are those appended onto Portlet URL (e.g ActionURL, RenderURL), submitted by the form or set during execution of action request.

    请求参数:   请求参数与讨论的请求属性没有太大区别,它们是一对名称/值,其中它们都是String对象。 这里最重要的问题是请求参数的来源。 通常,请求参数是那些附加到Portlet URL上的参数(例如ActionURLRenderURL ),由表单提交或在执行操作请求期间设置。

    The parameters sent to the Portlet from an action request are valid only while the action request is processed. Meanwhile, the render parameters are valid until the Portlet has received a new request. According to Java Portlet Specification 2.0, all these requests that are responsible for change the Portlet’s window state or mode from the user interface elements on the Portal page shouldn’t reset the render parameters for the Portlet.

    从动作请求发送到Portlet的参数仅在处理动作请求时才有效。 同时,渲染参数在Portlet收到新请求之前一直有效。 根据Java Portlet Specification 2.0,负责从门户网站页面上的用户界面元素更改Portlet窗口状态或模式的所有这些请求均不应重置Portlet的呈现参数。

    Both of processAction() and render are read the request parameters using the same methods; getParamaterMap(), getParameter(), getParameterNames() and getParamaterValues() are used for this purpose. Following sample shows you how can we develop simple Login form where you must enter journaldev as a username and password to get logged into.

    使用相同的方法读取processAction()和render的请求参数。 为此使用了getParamaterMap()getParameter()getParameterNames()getParamaterValues() 。 以下示例向您展示了如何开发简单的Login表单,您必须在其中输入journaldev作为用户名和密码才能登录。

    package com.journaldev.portlet;
    
    import java.io.IOException;
    
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.GenericPortlet;
    import javax.portlet.PortletException;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    
    public class RequestParameters extends GenericPortlet{
    	
    	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
    		// Check if the loggedIn is null for initial state
    		if(request.getParameter("loggedIn") == null){
    			response.getWriter().println("<form action="+response.createActionURL()+">"
    					+ "Enter Username : <input type='text' id='username' name='username'/>"
    					+ "Enter Password : <input type='password' id='password' name='password'/>"
    					+ "<input type='submit' value='Login'/>"
    					+ "</form>");	
    		}
    		else {
    			// Get loggedIn value from the request parameter
    			boolean loggedIn = Boolean.parseBoolean(request.getParameter("loggedIn"));
    			if(loggedIn){
    				response.getWriter().println("<form action="+response.createActionURL()+">"
    						+ "<p>You're logged in</p>"
    						+ "</form>");
    			}
    			else {
    				response.getWriter().println("<form action="+response.createActionURL()+">"
    						+ "<span style='color:red'>Try another</span><br/>"
    						+ "Enter Username : <input type='text' id='username' name='username'/>"
    						+ "Enter Password : <input type='password' id='password' name='password'/>"
    						+ "<input type='submit' value='Login'/>"
    						+ "</form>");			
    			}	
    		}	
    	}
    	
    	public void processAction(ActionRequest request, ActionResponse response) throws PortletException {
    		// Fetch username and password from the request parameters of action
    		String username = request.getParameter("username");
    		String password = request.getParameter("password");
    		
    		// Do some checking procedure
    		if(username != null && username.equals("journaldev") &&
    				password != null && password.equals("journaldev")){
    			// Use render parameters to pass the result
    			response.setRenderParameter("loggedIn", "true");
    		}
    		else {
    			// Use render parameters to pass the result
    			response.setRenderParameter("loggedIn", "false");
    		}
    	}
    }

    portlet.xml

    portlet.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <portlet-app xmlns="https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
    	version="2.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
    
    	<portlet>
    		<display-name>Request Attributes</display-name>
    		<portlet-name>requestAttributes</portlet-name>
    		<portlet-class>com.journaldev.portlet.RequestParameters</portlet-class>
    		<description>Print out all attributes located at the PortletRequest</description>
    		<portlet-info>
    			<title>Request Attributes</title>
    			<keywords>request, attributes</keywords>
    			<short-title>Request Attributes</short-title>
    		</portlet-info>
    	</portlet>
    
    </portlet-app>
    <project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>com.journaldev</groupId>
    	<artifactId>PortletConcepts</artifactId>
    	<packaging>war</packaging>
    	<version>0.0.1-SNAPSHOT</version>
    	<name>PortletConcepts</name>
    	<url>https://maven.apache.org</url>
    	<properties>
    		<deployFolder>D:/Apache Pluto/pluto-2.0.3/webapps</deployFolder>
    	</properties>
    	<dependencies>
    		<!-- Java Portlet Specification V2.0 -->
    		<dependency>
    			<groupId>org.apache.portals</groupId>
    			<artifactId>portlet-api_2.0_spec</artifactId>
    			<version>1.0</version>
    			<scope>provided</scope>
    		</dependency>
    	</dependencies>
    	<build>
    		<finalName>${project.artifactId}</finalName>
    		<plugins>
    			<!-- bind 'pluto2:assemble' goal to 'process-resources' lifecycle -->
    			<!-- This plugin will read your portlet.xml and web.xml and injects required 
    				lines -->
    			<plugin>
    				<groupId>org.apache.portals.pluto</groupId>
    				<artifactId>maven-pluto-plugin</artifactId>
    				<version>2.1.0-M3</version>
    				<executions>
    					<execution>
    						<phase>generate-resources</phase>
    						<goals>
    							<goal>assemble</goal>
    						</goals>
    					</execution>
    				</executions>
    			</plugin>
    			<!-- configure maven-war-plugin to use updated web.xml -->
    			<!-- This plugin will make sure your WAR will contain the updated web.xml -->
    			<plugin>
    				<artifactId>maven-war-plugin</artifactId>
    				<version>2.1.1</version>
    				<configuration>
    					<webXml>${project.build.directory}/pluto-resources/web.xml</webXml>
    				</configuration>
    			</plugin>
    			<plugin>
    				<artifactId>maven-antrun-plugin</artifactId>
    				<executions>
    					<execution>
    						<id>copy</id>
    						<phase>integration-test</phase>
    						<configuration>
    							<tasks>
    								<copy file="target/${project.artifactId}.war" tofile="${deployFolder}/${project.artifactId}.war" />
    							</tasks>
    						</configuration>
    						<goals>
    							<goal>run</goal>
    						</goals>
    					</execution>
    					<execution>
    						<id>delete</id>
    						<phase>clean</phase>
    						<configuration>
    							<tasks>
    								<delete file="${deployFolder}/${pom.build.finalName}.war" />
    								<delete dir="${deployFolder}/${pom.build.finalName}" />
    							</tasks>
    							<detail>true</detail>
    						</configuration>
    						<goals>
    							<goal>run</goal>
    						</goals>						
    					</execution>					
    				</executions>
    			</plugin>	
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-compiler-plugin</artifactId>
    				<version>3.1</version>
    				<configuration>
    					<source>1.7</source>
    					<target>1.7</target>
    				</configuration>
    			</plugin>
    		</plugins>
    	</build>
    </project>

    Here’s detailed explanation for the code listed above:

    这是上面列出的代码的详细说明:

    • You can use RenderResponse to create actionURL or renderURL.

      您可以使用RenderResponse创建actionURLrenderURL
    • It’s possible to pass the parameters as appended name/value into both of action request and render request.

      可以将参数作为附加的名称/值传递到动作请求和渲染请求中。
    • Action request has the ability to add any new parameters for render request.

      动作请求可以为渲染请求添加任何新参数。
    • If you’ve tried to get username and password parameters by using render request, you will get null for both of them.

      如果尝试使用渲染请求获取用户名和密码参数,则这两个参数都将为null。

    Context Path: The Portlet’s context path is that part of URL corresponds to the Portlet’s context. Acquiring of context path is very helpful especially when a reference to a web resources is required. You may redirect your request into other web resources like Servlet by adding the context path into resource name.

    上下文路径 :Portlet的上下文路径是URL的一部分与Portlet的上下文相对应。 获取上下文路径非常有帮助,尤其是在需要引用Web资源的情况下。 您可以通过将上下文路径添加到资源名称中来将请求重定向到其他Web资源(如Servlet)。

    Context path can be specified by using either of action or render requests.

    可以使用动作请求或渲染请求来指定上下文路径。

    Preferred Locales & Internationalization: It’s also possible for you to query the current locale that will be used for rendering the content. You may invoke the getLocale() or getLocales() for getting the current locale used and the list of locales for which the Portlet could provide the content for the Portal.

    首选语言环境和国际化 :您还可以查询将用于呈现内容的当前语言环境。 您可以调用getLocale()getLocales()来获取当前使用的语言环境以及Portlet可以为其提供门户内容的语言环境列表。

    Retrieving The Schema, Server Name and Port: Similar for HttpServletRequest, PortletRequest provides you the needed methods for inquiring the schema of the URL used for the request (e.g http, https, ftp, etc), the server’s name and the port number that the application is listening for.

    检索模式,服务器名称和端口 :与HttpServletRequest类似, PortletRequest为您提供查询用于请求的URL的模式(例如http,https,ftp等),服务器名称和端口号的必要方法。应用程序正在监听。

    Even you’re probably won’t get used these methods as you don’t need to create the needed URLs by yourself. Methods like createActionURL() and createRenderURL() will be used alternatively.

    甚至您可能也不会使用这些方法,因为您不需要自己创建所需的URL。 诸如createActionURL()createRenderURL()将被替代使用。

    渲染请求 (Render Request)

    As we’ve seen previously, render() method takes a RenderRequest as one of the arguments. RenderRequest is used to represent the request for the render phase.

    如前所述,render()方法将RenderRequest作为参数之一。 RenderRequest用于表示渲染阶段的请求。

    动作请求和文件上传 (Action Request & File Uploading)

    At the same time, the request that’s passed for processAction() method is of type ActionRequest and it represents the request for the action phase.

    同时,为processAction()方法传递的请求的类型为ActionRequest,它表示操作阶段的请求。

    ActionReqeust provides you two different methods that will help you read the content of the request body, getReader() and getPortletInputStream() are used for this purpose. Mainly, if your form posted data its MIME type is application/x-www-form-urlencoded, the Portlet container will read the request body on behalf of you and you will get the form’s data as a request parameters.

    ActionReqeust为您提供了两种不同的方法来帮助您读取请求正文的内容,为此目的使用了getReader()和getPortletInputStream()。 主要是,如果您的表单发布数据的MIME类型是application / x-www-form-urlencoded,则Portlet容器将代表您读取请求正文,您将获得表单数据作为请求参数。

    As soon as you’ve called a getReader() or getPortletInputStream() while reading the request body from a form’s its MIME type is application/x-www-form-urlencoded, you’ve surly got an IllegalStateException that print out the message says User request HTTP POST data is of type application/x-www-form-urlencoded. This data has been already processed by the portlet-container and is available as request parameters.

    从表单的MIME类型为application / x-www-form-urlencoded的表单中读取请求正文时,调用getReader()或getPortletInputStream()时,您肯定会收到一个IllegalStateException,该异常会打印出消息说用户请求HTTP POST数据的类型为application / x-www-form-urlencoded。 此数据已由Portlet容器处理,可以用作请求参数。

    You’re able of getting read the form’s data that MIME value is multipart/form-data. But be careful as you can open one reader at the same time. As soon as the getReader() has been used, using of getPortletInputStream() will throw an IllegalStateException and the same case when opposite is happened. Following sample shows you how can we submit two different forms, one of them is aimed to upload the file.

    您可以读取MIME值为multipart / form-data的表单数据 。 但是要小心,因为您可以同时打开一个阅读器。 一旦使用了getReader(),使用getPortletInputStream()就会抛出IllegalStateException和发生相反情况的相同情况。 以下示例向您展示了我们如何提交两种不同的表单,其中一种旨在上传文件。

    package com.journaldev.portlet;
    
    import java.io.IOException;
    import java.util.List;
    
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.GenericPortlet;
    import javax.portlet.PortletException;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.FileItemFactory;
    import org.apache.commons.fileupload.FileUploadException;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.portlet.PortletFileUpload;
    
    public class ActionRequestReader extends GenericPortlet{
    	
    	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
    		response.getWriter().println("<form action="+response.createActionURL()+" method='POST' enctype='application/x-www-form-urlencoded'>"
    				+ "Enter message : <input type='text' id='message' name='message'/>"
    				+ "<input type='submit' value='Submit Form Message'/><br/>"
    				+ "</form>"
    				+ "<form action="+response.createActionURL()+" method='POST' enctype='multipart/form-data'>"
    				+ "Upload Your File: <input type='file' name='fileUpload'/>"
    				+ "<input type='submit' value='Upload File'/>"
    				+ "</form>");
    
    	}
    	
    	public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
    		// Handle default MIME type request
    		if(request.getContentType().equals("application/x-www-form-urlencoded")){
    			String message = request.getParameter("message");
    			System.out.println(message);
    		}
    		// Handle multipart request
    		else if(request.getContentType().contains("multipart/form-data")){
    			// Create FileItemFactory
    			FileItemFactory factory = new DiskFileItemFactory();
    			// Create PortletFileUpload instance
    			PortletFileUpload fileUpload = new PortletFileUpload(factory);
    			try {
    				// Instead of parsing the request ourselves, let Apache PortletFileUpload do that
    				List<FileItem> files = fileUpload.parseRequest(request);
    				// Iterate over files
    				for(FileItem item : files){
    					// Print out some of information
    					System.out.println("File Uploaded Name Is : "+item.getName()+" , Its Size Is :: "+item.getSize());
    				}
    			} catch (FileUploadException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }

    Here’s detailed explanation for the code listed above:

    这是上面列出的代码的详细说明:

    • GetContentType is used for determining which type of request we’ve handled.

      GetContentType用于确定我们处理的请求类型。
    • URL-encoded request cannot be read as the Portlet container will do that. So you can find your form’s parameters through using of request.getParameters().

      无法读取URL编码的请求,因为Portlet容器会这样做。 因此,您可以使用request.getParameters()查找表单的参数。
    • Multipart request can be read using getReader() or getPortletInputstream(). But one can be used per request.

      可以使用getReader()或getPortletInputstream()读取多部分请求。 但是每个请求可以使用一个。
    • Instead of processing the request manually to get the file uploaded, we used Apache commons upload file library. This library is very smart one as it can handle normal file upload request or Portlet file upload request. See required libraries provided within the pom.xml.

      我们没有使用手动处理请求来上传文件,而是使用了Apache commons上传文件库。 这个库非常聪明,因为它可以处理正常的文件上传请求或Portlet文件上传请求。 请参阅pom.xml中提供的必需库。
    • Although, we handle the uploaded file using the very trivial way (Just Print out some of file information), but you can use ImageIO api for getting image saved onto your disk space.

      虽然,我们使用非常简单的方式来处理上传的文件(只需打印出一些文件信息),但是您可以使用ImageIO api将图像保存到磁盘空间中。
    • To get ActionRequestReader Portlet deployed, don’t forget to list it inside portlet.xml file.

      要部署ActionRequestReader Portlet,请不要忘记在portlet.xml文件中列出它。

    Portlet响应 (Portlet Response)

    The Portlet sends the response object back to the Portal after every request. The response object contains the Portlet fragment that will be drawn into Portal page. Fragments collective mission is a Portal job.

    每个请求之后,Portlet都会将响应对象发送回Portal。 响应对象包含将被绘制到门户页面的Portlet片段。 碎片集体任务是Portal的工作。

    PortletResponse provides you a three methods only, setProperty(), getProperty() and encodeURL(). These methods that are relevant for properties will be discussed while introducing the Portlet cache concept. Using of encodeURL() is mandatory for some of Portlet container implementations, in that some resources (e.g Servlet, JSP, etc) within the Portlet application need to be referenced using some additional data like SessionID and may others.

    PortletResponse仅为您提供三种方法, setProperty()getProperty()encodeURL() 。 在介绍Portlet高速缓存概念时,将讨论与属性相关的这些方法。 对于某些Portlet容器实现,必须使用encodeURL() ,因为需要使用某些附加数据(如SessionID以及其他一些数据)来引用Portlet应用程序内的某些资源(例如Servlet,JSP等)。

    According to Java Portlet Specification, if encoding isn’t needed, the Portlet container will return the URL unchanged.

    根据Java Portlet规范,如果不需要编码,则Portlet容器将返回不变的URL。

    渲染响应 (Render Response)

    Mainly, we’ve used RenderResponse object for writing content fragment into Portal page. RenderResponse object has provided two methods for getting content drawn, getWriter() and getPortletOutputStream() are available for that purpose.

    主要是,我们使用RenderResponse对象将内容片段写入Portal页面。 RenderResponse对象提供了两种获取内容绘制的方法,为此目的可使用getWriter()和getPortletOutputStream()。

    But as soon as you’ve used getWriter(), you cannot able of using the getPortletOutputStream() and the opposition is valid. In case you’ve used both of them to handle the content draw, you will get an IllegalStateException.

    但是,一旦使用了getWriter(),就无法使用getPortletOutputStream(),并且对立有效。 如果您同时使用它们来处理内容绘制,则将收到IllegalStateException。

    The major facility has provided by the RenderResponse object is the getNamespace() method that’s used in a JavaScript code for variable naming identification. Following sample shows you two Portlets have referenced the same Portlet class and they’re provided the same JavaScript method. Let’s look at the scenario before getting getNamespace() used.

    RenderResponse对象提供的主要功能是getNamespace()方法,该方法在JavaScript代码中用于变量命名标识。 以下示例显示两个Portlet引用了相同的Portlet类,并且为它们提供了相同JavaScript方法。 让我们先看一下使用getNamespace()之前的场景。

    package com.journaldev.portlet;
    
    import java.io.IOException;
    
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.GenericPortlet;
    import javax.portlet.PortletException;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    
    public class RenderResponseNamespaceOne extends GenericPortlet{
    	
    	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
    		response.getWriter().println("<html>"
    				+ "<head>"
    				+ "<script>"
    				+ "var message = 'Handle Submit, Portlet One';"
    				+ "function handleSubmit(){"
    				+ " alert('Handle Submit, The Portlet Is '+message);"
    				+ "}"
    				+ "</script>"
    				+ "</head>"
    				+ "<form action="+response.createActionURL()+">"
    				+ "  <input type='button' value='Click On Me' onclick='handleSubmit()'/>"
    				+ "</form>"
    				+ "</html>");
    
    	}
    	
    	public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
    		System.out.println("Handled Request ..");
    	}
    }
    package com.journaldev.portlet;
    
    import java.io.IOException;
    
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.GenericPortlet;
    import javax.portlet.PortletException;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    
    public class RenderResponseNamespaceTwo extends GenericPortlet{
    	
    	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
    		response.getWriter().println("<html>"
    				+ "<head>"
    				+ "<script>"
    				+ "var message = 'Handle Submit, Portlet Two';"
    				+ "function handleSubmit(){"
    				+ " alert('Handle Submit, The Portlet Is '+message);"
    				+ "}"
    				+ "</script>"
    				+ "</head>"
    				+ "<form action="+response.createActionURL()+">"
    				+ "  <input type='button' value='Click On Me' onclick='handleSubmit()'/>"
    				+ "</form>"
    				+ "</html>");
    
    	}
    	
    	public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
    		System.out.println("Handled Request ..");
    	}
    }

    Here’s detailed explanation for the code listed above:

    这是上面列出的代码的详细说明:

    • As the same message variable is defined for both of the Portlet, the last value of message variable will be used.

      由于为两个Portlet定义了相同的消息变量,因此将使用消息变量的最后一个值。
    • Both of Portlets will use the same message variable and specifically the last one of this variable.

      两个Portlet都将使用相同的消息变量,尤其是此变量的最后一个。

    To get this issue resloved, getNamespace() can be used, following below the solution that you may use as long as your JavaScript code is listed on the Portlet itself.

    要解决此问题,只要在Portlet本身上列出了JavaScript代码,就可以在下面的解决方案下面使用getNamespace()。

    package com.journaldev.portlet;
    
    import java.io.IOException;
    
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.GenericPortlet;
    import javax.portlet.PortletException;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    
    public class RenderResponseNamespaceOne extends GenericPortlet{
    	
    	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
    		response.getWriter().println("<html>"
    				+ "<head>"
    				+ "<script>"
    				+ "var "+response.getNamespace()+"message = 'Handle Submit, Portlet One';"
    				+ "function "+response.getNamespace()+"handleSubmit(){"
    				+ " alert('Handle Submit, The Portlet Is '+"+response.getNamespace()+"message);"
    				+ "}"
    				+ "</script>"
    				+ "</head>"
    				+ "<form action="+response.createActionURL()+">"
    				+ "  <input type='button' value='Click On Me' onclick='"+response.getNamespace()+"handleSubmit()'/>"
    				+ "</form>"
    				+ "</html>");
    
    	}
    	
    	public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
    		System.out.println("Handled Request ..");
    	}
    }
    package com.journaldev.portlet;
    
    import java.io.IOException;
    
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.GenericPortlet;
    import javax.portlet.PortletException;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    
    public class RenderResponseNamespaceTwo extends GenericPortlet{
    	
    	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
    		response.getWriter().println("<html>"
    				+ "<head>"
    				+ "<script>"
    				+ "var "+response.getNamespace()+"message = 'Handle Submit, Portlet Two';"
    				+ "function "+response.getNamespace()+"handleSubmit(){"
    				+ " alert('Handle Submit, The Portlet Is '+"+response.getNamespace()+"message);"
    				+ "}"
    				+ "</script>"
    				+ "</head>"
    				+ "<form action="+response.createActionURL()+">"
    				+ "  <input type='button' value='Click On Me' onclick='"+response.getNamespace()+"handleSubmit()'/>"
    				+ "</form>"
    				+ "</html>");
    
    	}
    	
    	public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
    		System.out.println("Handled Request ..");
    	}
    }

    Here’s detailed explanation for the code listed above:

    这是上面列出的代码的详细说明:

    • If you’ve used the sample above, you should find two different handleSubmit() method as well as two different message variables that are named Pluto_PortletConcepts_RenderResponseNamespaceOne__1332422274_0_message and Pluto_PortletConcepts_RenderResponseNamespaceTwo__1332422274_1_message respectively.

      如果使用了上面的示例,则应该找到两个不同的handleSubmit()方法以及两个不同的消息变量,它们分别名为Pluto_PortletConcepts_RenderResponseNamespaceOne__1332422274_0_messagePluto_PortletConcepts_RenderResponseNamespaceTwo__1332422274_1_message
    • This strategy would help as long as the JavaScript code is provided within the Portlet. If you’ve set your JavaScript code inside an external file, this strategy isn’t so helpful.

      只要在Portlet中提供了JavaScript代码,该策略就将有所帮助。 如果您已将JavaScript代码设置在外部文件中,则此策略不是很有用。

    动作回应 (Action Response)

    Typically, action response used for two different major missions; for passing the parameters for the render phase through using of setRenderParamater() and for redirect the request into any other resources than let the normal flow proceeds. Redirection has been done using of sendRedirect() as you can redirect into any resources like Servlet or JSP. Both of these behaviors are discussed and we also had provided samples for both of them.

    通常,行动响应用于两个不同的主要任务; 通过使用setRenderParamater()传递渲染阶段的参数,以及将请求重定向到其他任何资源(正常流程除外)。 重定向已使用sendRedirect()完成,因为您可以重定向到任何资源,例如Servlet或JSP。 讨论了这两种行为,我们还提供了两种示例。

    摘要 (Summary)

    Portlet API contains a lot of concepts that we must be aware of. This tutorial has discussed the most APIs that you should be familiar with as they would be helpful in the next coming tutorials. Contribute us by commenting below and find downloaded source code.

    Portlet API包含许多我们必须意识到的概念。 本教程讨论了您应该熟悉的大多数API,因为它们将在以后的教程中有所帮助。 通过在下面评论来贡献我们,并找到下载的源代码。

    翻译自: https://www.journaldev.com/4808/portlet-tutorial

    portlet

    展开全文
  • Portlet jQueryUI portlet和读取MySQL数据库PHP后端 Liferay php portlet开发人员
  • Portlet之间的通信--- Liferay 内部Portlet通信-Liferay中的示例Portlet 示例:从Portlet A输入标题,并使用Portlet B在同一页面上显示标题。
  • Vaadin Hibernate Portlet 示例 这是将移植到 Liferay portlet 并移植到使用 Maven 构建的尝试。 有关更多信息,请参阅的,将 ,,如果您有兴趣将 Spring 3 Portlet MVC 与 Liferay 6 结合使用,您可能还想查看. 此...
  • liferay-gis-portlet
  • Ajax Jquery Portlet 这个 portlet 是为了帮助那些希望看到 Ajax 在 Liferay Portlet 中使用 JQuery 工作的用户。 在这个 portlet 中,我添加了三个链接,点击后发送请求以获取用户信息并使用 Ajax 在门户上显示它...
  • 1. portlet的类结构 2. portlet的过滤器,拦截器
  • jquery portlet

    2013-11-11 19:51:19
    基本JQUERY UI的一个portlet实现,采用MVC设计方式,实现拖动,布局,智能添加等功能,其部分源码用了兔子的jquery ui portlet
  • 自定义登录portlet Liferay 自定义登录 Portlet。 网址:tariqliferay.blogspot.com
  • portlet_Portlet生命周期

    2020-07-17 14:04:52
    As we’ve seen previously, Portlet is conceptually very similar to Servlet as they can only operate within a container. Both Servlet and Portlet have an obligations that their design must satisfy to ...

    portlet

    As we’ve seen previously, Portlet is conceptually very similar to Servlet as they can only operate within a container. Both Servlet and Portlet have an obligations that their design must satisfy to allow them interact with their containers.

    如前所述,Portlet在概念上与Servlet非常相似,因为它们只能在容器内运行。 Servlet和Portlet都有其设计必须满足的义务,以允许它们与容器进行交互。

    As you should implement doGet(), doPost(), doDelete(), etc, you must also implement the Portlet’s specific methods like doView(), doHelp(), doEdit(), etc.

    在实现doGet()doPost()doDelete()等时,还必须实现Portlet的特定方法,如doView()doHelp()doEdit()等。

    Let’s firstly starting by developing our first Portlet by implementing the Portlet interface than using of GenericPortlet and highlights the most important things.

    首先,通过实现Portlet接口而不是使用GenericPortlet来开发我们的第一个Portlet,并重点介绍最重要的事情。

    Following sections would help cover these concepts:

    以下各节将帮助涵盖这些概念:

    实现Portlet接口 (Implementing Portlet Interface)

    Generally, you can develop your Portlet by extending the GenericPortlet, any class that’s extending the GenericPortlet or by implementing the Portlet interface.

    一般情况下,你可以通过扩展开发您的portlet GenericPortlet ,这就是扩展任何类GenericPortlet或实现Portlet接口。

    package com.journaldev.portlet;
    
    import java.io.IOException;
    
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.Portlet;
    import javax.portlet.PortletConfig;
    import javax.portlet.PortletException;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    
    public class LifecyclePortlet implements Portlet {
    	private static int renderCount = 0;
    	private static int actionCount = 0;
    	private static int initCount = 0;
    
    	@Override
    	public void init(PortletConfig config) throws PortletException {
    		initCount++;
    	}
    	@Override
    	public void processAction(ActionRequest request, ActionResponse response)
    			throws PortletException, IOException {
    		synchronized(this){
    			actionCount++;
    		}
    	}
    	@Override
    	public void render(RenderRequest request, RenderResponse response)
    			throws PortletException, IOException {
    		synchronized(this){
    			renderCount++;
    		}
    
    		response.getWriter().print("<form action="+response.createActionURL()+">"
    				+ "<p> The number of initiated Portlets by the container is :: "+initCount+"</p>"
    						+ "<p> The number of processed actions by the container is :: "+actionCount+"</p>"
    								+ "<p> The number of achieved render by the container is :: "+renderCount+"</p>"
    									+"<input value='Submit' type='submit'/><br/>"
    										+ "<a href='"+response.createRenderURL()+"'>Render Again</a>"
    											+ "</form>");
    	}
    	@Override
    	public void destroy() {
    		initCount--;
    		System.out.println("The number of Portlets get deployed :: "+initCount);
    	}
    }
    <project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>com.journaldev</groupId>
    	<artifactId>LifecyclePortlet</artifactId>
    	<packaging>war</packaging>
    	<version>0.0.1-SNAPSHOT</version>
    	<name>LifecyclePortlet</name>
    	<url>https://maven.apache.org</url>
    	<properties>
    		<deployFolder>D:/Apache Pluto/pluto-2.0.3/webapps</deployFolder>
    	</properties>
    	<dependencies>
    		<!-- Java Portlet Specification V2.0 -->
    		<dependency>
    			<groupId>org.apache.portals</groupId>
    			<artifactId>portlet-api_2.0_spec</artifactId>
    			<version>1.0</version>
    			<scope>provided</scope>
    		</dependency>
    	</dependencies>
    	<build>
    		<plugins>
    			<!-- bind 'pluto2:assemble' goal to 'process-resources' lifecycle -->
    			<!-- This plugin will read your portlet.xml and web.xml and injects required
    				lines -->
    			<plugin>
    				<groupId>org.apache.portals.pluto</groupId>
    				<artifactId>maven-pluto-plugin</artifactId>
    				<version>2.1.0-M3</version>
    				<executions>
    					<execution>
    						<phase>generate-resources</phase>
    						<goals>
    							<goal>assemble</goal>
    						</goals>
    					</execution>
    				</executions>
    			</plugin>
    			<!-- configure maven-war-plugin to use updated web.xml -->
    			<!-- This plugin will make sure your WAR will contain the updated web.xml -->
    			<plugin>
    				<artifactId>maven-war-plugin</artifactId>
    				<version>2.1.1</version>
    				<configuration>
    					<webXml>${project.build.directory}/pluto-resources/web.xml</webXml>
    				</configuration>
    			</plugin>
    			<plugin>
    				<artifactId>maven-antrun-plugin</artifactId>
    				<executions>
    					<execution>
    						<id>copy</id>
    						<phase>integration-test</phase>
    						<configuration>
    							<tasks>
    								<copy file="target/${project.build.finalName}.war" tofile="${deployFolder}/${project.build.finalName}.war" />
    							</tasks>
    						</configuration>
    						<goals>
    							<goal>run</goal>
    						</goals>
    					</execution>
    					<execution>
    						<id>delete</id>
    						<phase>clean</phase>
    						<configuration>
    							<tasks>
    								<delete file="${deployFolder}/${project.build.finalName}.war" />
    								<delete dir="${deployFolder}/${project.build.finalName}" />
    							</tasks>
    							<detail>true</detail>
    						</configuration>
    						<goals>
    							<goal>run</goal>
    						</goals>
    					</execution>
    				</executions>
    			</plugin>
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-compiler-plugin</artifactId>
    				<version>3.1</version>
    				<configuration>
    					<source>1.7</source>
    					<target>1.7</target>
    				</configuration>
    			</plugin>
    		</plugins>
    	<finalName>${project.artifactId}</finalName>
    	</build>
    </project>

    portlet.xml

    portlet.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <portlet-app xmlns="https://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
    	version="1.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="https://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
                            https://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
    
    	<portlet>
    		<description>First Portlet</description>
    		<portlet-name>PortletOne</portlet-name>
    		<display-name>First Portlet</display-name>
    
    		<portlet-class>com.journaldev.portlet.LifecyclePortlet</portlet-class>
    
    		<supports>
    			<mime-type>text/html</mime-type>
    			<portlet-mode>VIEW</portlet-mode>
    		</supports>
    
    		<portlet-info>
    			<title>Lifecycle Portlet</title>
    			<short-title>Lifecycle Portlet</short-title>
    			<keywords>Lifecycle</keywords>
    		</portlet-info>
    
    	</portlet>	
    
    	<portlet>
    		<description>Second Portlet</description>
    		<portlet-name>PortletTwo</portlet-name>
    		<display-name>Second Portlet</display-name>
    
    		<portlet-class>com.journaldev.portlet.LifecyclePortlet</portlet-class>
    
    		<supports>
    			<mime-type>text/html</mime-type>
    			<portlet-mode>VIEW</portlet-mode>
    		</supports>
    
    		<portlet-info>
    			<title>Lifecycle Portlet</title>
    			<short-title>Lifecycle Portlet</short-title>
    			<keywords>Lifecycle</keywords>
    		</portlet-info>
    
    	</portlet>
    </portlet-app>

    Here’s detailed explanation for code listed above:

    这是上面列出的代码的详细说明:

    • Executing mvn clean integration-test package will get your project to be packaged and deployed against your Apache Pluto.

      执行mvn clean integration-test package将使您的项目被打包并针对Apache Pluto进行部署。
    • LifecyclePortlet has implemented the Portal interface, as it’s obvious all contract methods must be implemented.

      LifecyclePortlet已经实现了Portal接口,因为显然必须实现所有合同方法。
    • Portlet deployment descriptor portlet.xml has defined two different Portlets that are referenced the same Portlet class. Such that deployment is acceptable as it can be deployed any number of Portlets that refer the same Portlet class with different names. It could also be to deploy two Portlets have the same name but make sure you are got deployed them into two different contexts.

      Portlet部署描述符portlet.xml已经定义了两个引用相同Portlet类的不同Portlet。 这样的部署是可以接受的,因为可以部署使用相同名称引用相同Portlet类的任意数量的Portlet。 也可能是部署两个具有相同名称的Portlet,但要确保将它们部署到两个不同的上下文中。
    • When it create a Portlet by implementing Portlet interface, render(), processAction(), init(), destroy() should be overridden.

      当通过实现Portlet接口来创建Portlet时,应该重写render()processAction()init()destroy()
    • When the Portlet get deployed, the Portlet container would call the init() at the initialization phase.

      当部署Portlet时,Portlet容器将在初始化阶段调用init()
    • When the client has activated submit button that’s displayed at the Portlet, the Portlet container has received such that call and it’s called processAction() method by its turn.

      当客户机激活了Portlet上显示的Submit按钮时,Portlet容器已收到这样的调用,并且该调用又被称为processAction()方法。
    • When the client has activated the renderAgain link that’s rendered at the Portlet, the Portlet container has received such that call and it’s called render() method by its turn.

      当客户端激活了在Portlet上渲染的renderAgain链接时,Portlet容器已收到这样的调用,并且该调用又被称为render()方法。
    • If you’ve execute mvn clean against LifecyclePortlet project, you should notice that your WAR file and its un-packaged format (WAR folder) are deleted. Deletion the context will cause that your defined Portlets to be destroyed.

      如果已对LifecyclePortlet项目执行mvn clean ,则应注意,您的WAR文件及其未打包的格式(WAR文件夹)已删除。 删除上下文将导致您定义的Portlet被销毁。
    • To get your WAR file removed a new execution has been added at the maven-antrun-plugin.

      为了删除您的WAR文件,在maven-antrun-plugin添加了新的执行。

    Now, let’s see what might happen if we have removed the deployed WAR and its unpackaged folder. Absolutely, removing your deployed application will get the context listener to be invoked as it will destroy the all resources that are deployed including these defined Portlets inside the portlet.xml file.

    现在,让我们看看如果删除了已部署的WAR及其未打包的文件夹会发生什么。 绝对,删除已部署的应用程序将使上下文侦听器被调用,因为它将破坏已部署的所有资源,包括portlet.xml文件中已定义的Portlet。

    As we have two deployed Portlets (PortletOne, PortletTwo), we print out the numbers of remaining Portlets inside the destroy() method. This method has invoked similar to Servlet’s destroy() method that’s invoked once the contained project has undeployed.

    因为我们有两个已部署的Portlet(PortletOne,PortletTwo),所以我们打印出destroy()方法中剩余Portlet的数量。 此方法的调用类似于Servlet的destroy()方法,该方法在取消包含项目后立即调用。

    If you’ve looked deeply at the console messages, you should notice the Portlet context /LifecyclePortlet-0.0.1-SNAPSHOT be removed. Usually, the concepts of undeploy and context removal are used interchangeably.

    如果您已深入查看控制台消息,则应注意已删除了Portlet上下文/LifecyclePortlet-0.0.1-SNAPSHOT 。 通常,取消部署和上下文删除的概念可以互换使用。

    Portlet生命周期 (Portlet Lifecycle)

    As simple as that, we can break down the Portlet lifecycle into these below stages:

    如此简单,我们可以将Portlet生命周期分解为以下几个阶段:

    • Creation of Portlet.

      创建Portlet。
    • Processing of a number of user requests (or it might be none).

      处理多个用户请求(或者可能没有)。
    • Removal and garbage collection of the Portlet.

      Portlet的除去和垃圾回收。

    Let’s delve thoroughly to discuss these stages deeply.

    让我们深入研究这些阶段。

    Portlet创建阶段 (Portlet Creation Stage)

    The creation of the Portlet is the most expensive and complicated phase among mentioned phases as it consists of three distinct steps: loading the classes, invoking the constructors and initializing the Portlet.

    Portlet的创建是上述阶段中最昂贵,最复杂的阶段,因为它包含三个不同的步骤:加载类,调用构造函数和初始化Portlet。

    Generally, the container is able to load the classes required by the Portlet before constructor invocation. The Portlet that’s loaded is considered as a minor part in compare with the whole application that might contain a lot of classes and libraries. As such the specification demands that the loading of the Portlet class must be done using the same classloader as the rest of the Portlet application that the loaded Portlet referred to.

    通常,容器能够在构造函数调用之前加载Portlet所需的类。 与可能包含许多类和库的整个应用程序相比,已加载的Portlet被视为次要部分。 因此,规范要求必须使用与加载的Portlet所引用的Portlet应用程序其余部分相同的classloader来完成Portlet类的加载。

    The Portlet container may decide to create an instance of your loaded Portlet’s class either when the Portlet container starts the Portlet application (WAR) or when the container determines that Portlet is used to serve certain request.

    当Portlet容器启动Portlet应用程序(WAR)或容器确定Portlet用于满足某些请求时,Portlet容器可能会决定创建已加载的Portlet类的实例。

    The most important thing that you must take care of is the time needed of Portlet’s resources to be initialized, for which the Portlet would wait until it’s finished to serve the first request. Once the first request has served, every request that’s coming after so would be served normally.

    您必须注意的最重要的事情是初始化Portlet资源所需的时间,Portlet将等待该时间完成,直到完成为第一个请求。 一旦第一个请求得到处理,那么随后的每个请求将被正常处理。

    While initialization the Portlet is passed an Object instance of PortletConfig interface that’s considered unique to the Portlet definition and provides access to the initialization parameters and the resource bundle configured for the Portlet in the Portlet definition.

    在初始化Portlet时,会传递PortletConfig接口的Object实例,该对象实例被视为Portlet定义的唯一实例,并提供对初始化参数和为Portlet定义中的Portlet配置的资源束的访问。

    Until the init() method has been invoked successfully, the Portlet isn’t considered as an active Portlet. In case your Portlet class has provided some of static initialization blocks, they must not trigger any methods that make this assumption.

    在成功调用init()方法之前,该Portlet不会被视为活动Portlet。 如果您的Portlet类提供了一些静态初始化块,则它们不得触发任何进行此假设的方法。

    You can use the Portlet configuration object (PortleConfig) for providing a lot of configurations that’s meant for the Portlet itself like a database connection URL and others.

    您可以使用Portlet配置对象( PortleConfig )提供许多针对Portlet本身的配置,例如数据库连接URL等。

    Init() method is error-prone by its nature, you may access a database that’s already down or you don’t have a proper permission over it. For such cases, init() has defined as it throws a PortletException. You may also can throw an UnavailableException in between, but regardless of the exception type being thrown, you must ensure that all resources that been acquired are released as the destroy() method won’t be called subsequently. However, failure of initialization does mean that the Portlet container won’t place the Portlet object into active service and it must release the Portlet object.

    Init()方法本质上很容易出错,您可能会访问已关闭的数据库,或者您对该数据库没有适当的权限。 对于这种情况, init()已定义为引发PortletException 。 您也可以在两者之间抛出UnavailableException ,但是无论抛出何种异常类型,都必须确保释放所有已获取的资源,因为随后不会调用destroy()方法。 但是,初始化失败确实意味着Portlet容器不会将Portlet对象置于活动服务中,它必须释放Portlet对象。

    According to Java Portlet Specification 2.0, the Portlet container may reattempt to instantiate and initialize the Portlets at any time after failure. In case you’ve used UnavilableException and provided a wait time, the Portlet container must wait for the specified time before creating and initializing a new Portlet object. Practically, this feature

    根据Java Portlet Specification 2.0,Portlet容器可以在失败后的任何时间重新尝试实例化和初始化Portlet。 如果您已使用UnavilableException并提供了等待时间,则Portlet容器必须等待指定的时间才能创建和初始化新的Portlet对象。 实际上,此功能

    In case you’ve got a RuntimeException during initialization, it must be handled as a PortletException.

    如果在初始化过程中遇到RuntimeException ,则必须将其作为PortletException进行处理。

    请求处理阶段 (Request Handling Stage)

    Once the Portlet get initialized, it’s become waiting for users interactions. The interactions with the Portlets can be done through set of requests, these requests are translated into render() and processAction() requests.

    一旦Portlet初始化,它就开始等待用户交互。 与Portlet的交互可以通过一组请求完成,这些请求被转换为render()processAction()请求。

    Action requests are are asking the Portlets to change the state of its underlying application, while the render requests are displaying the Portlet with its current states. Practically, a subsequent render() request has been initiated once the processAction() got finished.

    动作请求正在要求Portlet更改其基础应用程序的状态,而渲染请求正在显示具有当前状态的Portlet。 实际上,一旦processAction()完成,便会启动后续的render()请求。

    As we’ve stated previously, you can make a render request and action request by calling createRenderURL() and createActionURL() respectively against passed response object.

    如前所述,您可以通过分别对传递的响应对象调用createRenderURL()createActionURL()来发出渲染请求和动作请求。

    Generally, RenderRequest that’s passed for render() method is responsible for providing:

    通常,传递给render()方法的RenderRequest负责提供:

    • The state of the Portlet window (minimized, maximized, etc.)

      Portlet窗口的状态(最小化,最大化等)
    • The mode of the Portlet (e.g VIEW, EDIT, etc.)

      Portlet的模式(例如VIEW,EDIT等)
    • The context of the Portlet.

      Portlet的上下文。
    • The session associated with the Portlet (including authorization information).

      与Portlet关联的会话(包括授权信息)。
    • The preferences information associated with the Portlet.

      与Portlet关联的首选项信息。
    • Any render parameters that have been set on a render URL from a posted form or that have been set during the processAction() method.

      从发布表单在渲染URL上设置的任何渲染参数,或在processAction()方法期间设置的任何渲染参数。

    RenderResponse is also responsible of writing the Portlet’s content fragment into Portal page as it’s also capable to render URLs into that content, which will invoke actions to the Portlet (e.g createActionURL(), createRenderURL(), etc).

    RenderResponse还负责将Portlet的内容片段写入门户网站页面,因为它还能够将URL呈现到该内容中,这将调用对Portlet的操作(例如createActionURL() ,createRenderURL()等)。

    ActionRequest object represents the opportunity to change the state of the Portlet, it provides everything that’s already offered by PortletRequest along with direct access to the content of the HTTP request made by the user of the Portal. To respond to processAction() the Portlet should update its ActionResponse object which provides methods to:

    ActionRequest对象代表更改Portlet状态的机会,它提供PortletRequest已经提供的所有内容,以及对门户网站用户发出的HTTP请求内容的直接访问。 为了响应processAction() ,Portlet应该更新其ActionResponse对象,该对象提供以下方法:

    • Redirect the client to a new Page.

      将客户端重定向到新的页面。
    • Change the mode of the Portlet.

      更改Portlet的模式。
    • Add or modify rendering parameters for the user’s session.

      添加或修改用户会话的渲染参数。

    The processAction() proposed above makes a trivial change for the actionCount counter and so it doesn’t have to inform the container of any changes via the response. Following sample shows you how can use the ActionResponse to make a change in the response.

    上面建议的processAction()actionCount计数器进行了微不足道的更改,因此不必通过响应将任何更改通知容器。 以下示例显示了如何使用ActionResponse来更改响应。

    package com.journaldev.portlet;
    
    import java.io.IOException;
    
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.Portlet;
    import javax.portlet.PortletConfig;
    import javax.portlet.PortletException;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    
    public class LifecyclePortlet implements Portlet {
    	private static int renderCount = 0;
    	private static int actionCount = 0;
    	private static int initCount = 0;
    
    	@Override
    	public void init(PortletConfig config) throws PortletException {
    		initCount++;
    	}
    	@Override
    	public void processAction(ActionRequest request, ActionResponse response)
    			throws PortletException, IOException {
    		synchronized(this){
    			actionCount++;
    		}
    		response.sendRedirect(request.getContextPath()+"/index.html");
    	}
    	@Override
    	public void render(RenderRequest request, RenderResponse response)
    			throws PortletException, IOException {
    		synchronized(this){
    			renderCount++;
    		}
    
    		response.getWriter().print("<form action="+response.createActionURL()+">"
    				+ "<p> The number of initiated Portlets by the container is :: "+initCount+"</p>"
    						+ "<p> The number of processed actions by the container is :: "+actionCount+"</p>"
    								+ "<p> The number of achieved render by the container is :: "+renderCount+"</p>"
    									+"<input value='Submit' type='submit'/><br/>"
    										+ "<a href='"+response.createRenderURL()+"'>Render Again</a>"
    											+ "</form>");
    	}
    	@Override
    	public void destroy() {
    		initCount--;
    		System.out.println("The number of Portlets get deployed :: "+initCount);
    	}
    
    }

    index.html

    index.html

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="ISO-8859-1">
    <title>ActionResponse Sample</title>
    </head>
    	<body>
    		<p>ActionResponse redirects the client into this page</p>
    	</body>
    </html>

    Here’s some of important points need to notice:

    这里有一些重要的注意事项:

    • Determine of context path of Portlet application has been done through using of ActionRequest.

      已经通过使用ActionRequest确定了Portlet应用程序的上下文路径。
    • ActionResponse does redirect the action request to be served by using different content (i.e index.html).

      ActionResponse确实通过使用其他内容(即index.html)来重定向要处理的操作请求。

    Portlet销毁阶段 (Portlet Destroying Stage)

    As we’ve stated earlier, the destroy() method won’t be invoked as a subsequent phase when the initialization phase is failed. To allow Portlet container from destroying a certain Portlet, the Portlet must be instantiated and initialized successfully and all processing threads on the Portlet’s instance have completed.

    如前所述,初始化阶段失败时,不会将destroy()方法作为后续阶段调用。 为了允许Portlet容器销毁某个Portlet,必须成功实例化和初始化Portlet,并且必须完成Portlet实例上的所有处理线程。

    If you’ve integrated with third parties, the destroy() method is the best place to notify those third parties about the Portlet is becoming unavailable. According for Java Portlet Specification 2.0, after destroy() method completes, the Portlet container must release the Portlet object so that it’s eligible for garbage collection. Portlet implementations shouldn’t use finalizers.

    如果您已与第三方集成,则destroy()方法是通知这些第三方有关Portlet变得不可用的最佳位置。 根据Java Portlet Specification 2.0,在destroy()方法完成之后,Portlet容器必须释放Portlet对象,以便可以进行垃圾回收。 Portlet实现不应使用终结器

    线程问题 (Threading Issues)

    According to Java Portlet Specification 2.0, The Portlet container is able to handle the requests concurrently. Portlet developers must design their Portlets to handle concurrent execution from multiple threads from within the processAction() and render() methods or any of the optional lifecycle methods, like prcoessEvent() or serveResource(), at any particular time.

    根据Java Portlet Specification 2.0,Portlet容器能够同时处理请求。 Portlet开发人员必须设计其Portlet,以在任何特定时间处理processAction()render()方法或任何可选的生命周期方法(例如prcoessEvent()serveResource()内多个线程的并发执行。

    Actually, implementations of the request and response objects aren’t guaranteed to be thread safe. This means that they must only be used within the scope of thread invoking the processAction(), render(), processEvent() and serveResource() methods.

    实际上,不能保证请求和响应对象的实现是线程安全的。 这意味着它们只能在调用processAction()render()processEvent()serveResource()方法的线程范围内使用。

    To remain Portable, Portlet applications shouldn’t give references of the request and response objects to objects executing in other threads as the resulting may be non-deterministic.

    为了保持可移植性,Portlet应用程序不应将请求和响应对象的引用提供给在其他线程中执行的对象,因为结果可能是不确定的。

    In other words, any combination and number of simultaneous calls to render() and/or processAction() would be safe unless the Portlet has used an instance variables and/or external resources.

    换句话说,除非Portlet使用实例变量和/或外部资源,否则同时调用render()和/或processAction()任何组合和数量都是安全的。

    As we’ve stated earlier at the provided sample, all counters had defined as an instance variables and so, they’re not safe when it comes to be processed by concurrent threads. For handling increments for all of them concurrently, we’ve stated them within a synchronized block.

    正如我们之前在提供的示例中所述,所有计数器都已定义为实例变量,因此,当它们被并发线程处理时,它们是不安全的。 为了同时处理所有这些增量,我们在一个同步块中声明了它们。

    Portlet生命周期摘要 (Portlet Lifecycle Summary)

    Similar for Servlet, user requests for Portlet are handled through well-defined lifecycle that’s maintained by the Portlet container. This tutorial has focused on the lifecycle and its details as well as for threading issue. Contribute us by commenting below and find downloaded source code.

    与Servlet类似,用户对Portlet的请求是通过Portlet容器维护的定义明确的生命周期来处理的。 本教程重点讨论生命周期及其详细信息以及线程问题。 通过在下面评论来贡献我们,并找到下载的源代码。

    翻译自: https://www.journaldev.com/4732/portlet-lifecycle

    portlet

    展开全文
  • appconnector-portlet-local appconnector-portlet-local

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,961
精华内容 8,784
关键字:

Portlet