블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2014. 5. 26. 09:44 Study Frameworks/Liferay Portal

포틀릿에서 Action Phase 수행후 Render Phase로 정보들 어떻게 전달 될 수 있는지 알아보자 



Action 에서 Render Phase로 정보전달 방식

  - render parameters를 통한 정보 전달 : REQUEST SCOPE

> Action Phase

  processAction 안에서 actionResponse.setRenderParameter("parameter-name", "value");  값을 설정


> Render Phase

  renderRequest.getParameter("parameter-name"); 호출하여 값을 얻어옴 


> 단, action phase에서는 only read 이므로 set이 가능하려면 portlet.xml 에 다음 설정을 한다. 해당 설정을 하게되면 action phase parameters 가 render phase parameters로 복사된다. 

<init-param>

    <name>copy-request-parameters</name>

    <value>true</value>

</init-param>


> action parameter를 render parameter로 전달하게 되면 action phase이후 모든 포틀릿의 render phase가 호출되는 것임을 유의 


  - 세션 방식의 전달 : SESSION SCOPE

> actionRequest에 설정하고 JSP가 읽는다. 해당 설정값은 JSP에 딱 한번 사용되고 자동으로 삭제한다 

//SessionMessages 사용 경우 

package com.liferay.samples;


import java.io.IOException;

import javax.portlet.ActionRequest;

import javax.portlet.ActionResponse;

import javax.portlet.PortletException;

import javax.portlet.PortletPreferences;

import com.liferay.portal.kernel.servlet.SessionMessages;

import com.liferay.util.bridges.mvc.MVCPortlet;


public class MyGreetingPortlet extends MVCPortlet {

    public void setGreeting(

            ActionRequest actionRequest, ActionResponse actionResponse)

    throws IOException, PortletException {

        PortletPreferences prefs = actionRequest.getPreferences();

        String greeting = actionRequest.getParameter("greeting");


        if (greeting != null) {

            try {

                prefs.setValue("greeting", greeting);

                prefs.store();

                SessionMessages.add(actionRequest, "success");

            }

            catch(Exception e) {

                SessionErrors.add(actionRequest, "error");

            }

        }

    }

}


// view.jsp 에서 sucess / error 사용 

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>

<%@ page import="javax.portlet.PortletPreferences" %>


<portlet:defineObjects />


<liferay-ui:success key="success" message="Greeting saved successfully!"/>

<liferay-ui:error key="error" message="Sorry, an error prevented savingyour greeting" />


<% PortletPreferences prefs = renderRequest.getPreferences(); String

greeting = (String)prefs.getValue(

    "greeting", "Hello! Welcome to our portal."); %>


<p><%= greeting %></p>


<portlet:renderURL var="editGreetingURL">

    <portlet:param name="mvcPath" value="/edit.jsp" />

</portlet:renderURL>


<p><a href="<%= editGreetingURL %>">Edit greeting</a></p>


  - Liferay Portal 은 multi parameters들을 포틀릿에 전달하므로 namespace 구분을 하는게 중요하다 

<portlet:namespace />  를 사용하면 포틀릿별 유니크한 네임스페이스를 가질 수 있다 

예) submitForm(document.<portlet:namespace />fm);  form에 대한 것


Liferay는 namespaced 파라미터만 포틀릿에 접근할 수 있다. 그러나 third-part 에서 unamespaced parameter가 존재하면

 liferay-portal.xml 에서 기능을 꺼주어야 한다. 

<requires-namespaced-parameters>false</requires-namespaced-parameters>



Multi Action 추가

  - 포틀릿에 원하는 Action만큼 추가할 수 있다

1) 메소드 명칭은 사용자 정의 & 두개의 파라미터 받음 

    public void setGreeting(ActionRequest actionRequest, ActionResponse actionResponse) 

         throws IOException, PortletException {...

    }


    public void sendEmail(ActionRequest actionRequest, ActionResponse actionResponse) 

        throws IOException, PortletException {

        // Add code here to send an email

    }


2) setGreeting 명칭은 JSP에서 actionURL의 name과 일치해야 한다 

<portlet:actionURL var="editGreetingURL" name="setGreeting">

    <portlet:param name="mvcPath" value="/edit.jsp" />

</portlet:actionURL>



포틀릿 URL Mapping을 친숙한 방법으로 전환

  - v6 부터 human readable 하게 url을 만들 수 있다. 

 > 원래 보이는 형태 

http://localhost:8080/web/guest/home?p_p_id=mygreeting_WAR_mygreetingportlet

    &p_p_lifecycle=0&p_p_state=normal&p_p_mode=view&p_p_col_id=column-1

    &p_p_col_count=2&_mygreeting_WAR_mygreetingportlet_mvcPath=%2Fedit.jsp


 > friendly url 변환 

http://localhost:8080/web/guest/home/-/my-greeting/edit

  - liferay-portlet.xml 에서 </icon> 이후 <instanceable> 바로 전에 하기 설정을 넣음 

1) liferay-portlet.xml 설정 내역 

<liferay-portlet-app>

<portlet>

<portlet-name>mobiconsoft_greeting</portlet-name>

<icon>/icon.png</icon>

<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class>

<friendly-url-mapping>mobiconsoft_greeting</friendly-url-mapping>

<friendly-url-routes>mobiconsoft/greeting/mobiconsoft-greeting-friendly-url-routes.xml</friendly-url-routes>

<instanceable>false</instanceable>

<header-portlet-css>/css/main.css</header-portlet-css>

<footer-portlet-javascript>/js/main.js</footer-portlet-javascript>

</portlet>


2) src/main/resources/폴더 밑의 monbiconsoft/greeting/ 폴더 밑으로 mobiconsoft-greeting-friendly-url-routes.xml 생성 및 입력


<?xml version="1.0"?>

<!DOCTYPE routes PUBLIC "-//Liferay//DTD Friendly URL Routes 6.2.0//EN"

"http://www.liferay.com/dtd/liferay-friendly-url-routes_6_2_0.dtd">


<routes>

    <route>

        <pattern>/{mvcPathName}</pattern>

        <generated-parameter name="mvcPath">/{mvcPathName}.jsp</generated-parameter>

    </route>

</routes>


3) eclipse의 context menu에서 "Liferay" -> "Maven" -> "deploy"를 선택하면 war파일 생성됨 


4) eclipse에서 테스트 서버 수행하면 deploy 폴더의 war 파일들이 자동배포된다. test@liferay.com (패스워드 : test) 로그인

    로그인후 우측 상단의 "+" 를 클릭하고 Sample 메뉴에서 mobiconsoft_greeting을 추가하면 하기 무한루프 오류가 발생함

    (추후 오류현상 추적필요)


시도하고 시도해 보고 실패에서 배워보자. 다음엔 포틀릿를 좀 더 고도화 해보자 



<참조> 

  - Action -> Render Phase 정보전달

  - Multi Action 추가하는 방법

posted by 윤영식

포틀릿을 생성하고 세부사항에 대하여 알아보고, 포틀릿의 두가지 Phase를 이해하자. 이를 위해 Maven 기반으로 포틀릿을 생성하고 Java와 JSP를 생성/수정해 보도록 한다. 

완성된 포틀릿의 edit 모습

 


포틀릿 생성

  - 이클립스 IDE를 통한 생성

  - CLI 명령으로 통한 생성

// CLI 생성

// 이름의 뒤에 자동으로 "-portlet"이 붙는다 

$ cd ~/development/liferay_portal/plugins-sdk-6.2/portlets

$ create.sh mobiconsoft-greeting "hi youngsik"

Buildfile: /Users/xxx/development/liferay_portal/plugins-sdk-6.2/portlets/build.xml

.. 중략 ..

BUILD SUCCESSFUL

Total time: 1 second


// 배포

$ ant deploy 

Buildfile: /Users/xxx/development/liferay_portal/plugins-sdk-6.2/portlets/build.xml

deploy:

    .. 중략 ..

     [copy] Copying 1 file to /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/deploy

BUILD SUCCESSFUL

Total time: 9 seconds


* 만일 tomcat ROOT를 변경하였다면 deploy/*.war는 기본 폴더인 {TOMCAT_HOME}/webapps/ 밑으로 들어간다. 

tomcat을 수행하기전에 deploy/*.war 파일을 변경된 폴더 밑으로 copy한 후 시작한다. (변경된 폴더로 deploy하는 설정을 못 찾겠음)



Portlet 구조이해

  - 톰켓에 배포된 디렉토리 구조

> 자바 소스, 웹 리소스, 환경 설정 3가지로 구성되어있다.

  톰켓의 단일 Context로 운영된다. 즉, J2EE Context 폴더 구조임 


> xml 환경파일들

 portlet.xml : JSR-286 Portlet 스펙에 대한 환경파일

 liferay-display.xml : 화면구성 위저드에서 카테고리 지정 

 liferay-plugin-package.properties : hot deploy 설정

 liferay-portlet.xml : liferay portal server와 특화된 portlet 설정들

 

> 리소스들

 html : 클라이언트에 표현되는 것으로 <html>, <head> 태그는 없어야 함

 css, js : 다른 css와 충돌하지 않도록 namespace를 준다 


  - portlet.xml

    + MVCPortlet : 포틀릿 전체 기능이 내장된 놈. 우리가 만드는 포틀릿은 실제 요것을 상속받아서 구현된다. 

    + portlet-info : 카테고리되었을 때 이름 지정 

<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0">

<portlet>

<portlet-name>mobiconsoft-greeting</portlet-name>

<display-name>hi youngsik</display-name>

<portlet-class>com.liferay.util.bridges.mvc.MVCPortlet</portlet-class>

<init-param>

<name>view-template</name>

<value>/view.jsp</value>

</init-param>

<expiration-cache>0</expiration-cache>

<supports>

<mime-type>text/html</mime-type>

</supports>

<portlet-info>

<title>hi youngsik</title>

<short-title>hi youngsik</short-title>

<keywords>hi youngsik</keywords>

</portlet-info>

<security-role-ref>

<role-name>administrator</role-name>

</security-role-ref>

<security-role-ref>

<role-name>guest</role-name>

</security-role-ref>

<security-role-ref>

<role-name>power-user</role-name>

</security-role-ref>

<security-role-ref>

<role-name>user</role-name>

</security-role-ref>

</portlet>

</portlet-app>


  - liferay-portlet.xml 

    + header-portlet-css : <header> 태그에 들어갈 css 

    + footer-portlet-javascripit : </body> 끝에 들어갈 javascript 

    + instanceable : 해당 포틀릿이 한페이지 멀티로 나오는 인스턴스들인지 true / false 설정

<?xml version="1.0"?>

<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 6.2.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_6_2_0.dtd">


<liferay-portlet-app>

<portlet>

<portlet-name>mobiconsoft-greeting</portlet-name>

<icon>/icon.png</icon>

<header-portlet-css>/css/main.css</header-portlet-css>

<footer-portlet-javascript>/js/main.js</footer-portlet-javascript>

<css-class-wrapper>mobiconsoft-greeting-portlet</css-class-wrapper>

</portlet>

<role-mapper>

<role-name>administrator</role-name>

<role-link>Administrator</role-link>

</role-mapper>

<role-mapper>

<role-name>guest</role-name>

<role-link>Guest</role-link>

</role-mapper>

<role-mapper>

<role-name>power-user</role-name>

<role-link>Power User</role-link>

</role-mapper>

<role-mapper>

<role-name>user</role-name>

<role-link>User</role-link>

</role-mapper>

</liferay-portlet-app>



포틀릿을 수정해 보기 

  - liferay-portal.xml 에서 instanceable=false 추가 

<instanceable>false</instanceable>

  - view.jsp 파일 수정 

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<%@ page import="javax.portlet.PortletPreferences" %>


<portlet:defineObjects />


<%

PortletPreferences prefs = renderRequest.getPreferences();

String greeting = (String)prefs.getValue("greeting", "Hello! Welcome to our portal.");

%>


<p><%= greeting %></p>


<portlet:renderURL var="editGreetingURL">

    <portlet:param name="mvcPath" value="/edit.jsp" />

</portlet:renderURL>


<p><a href="<%= editGreetingURL %>">Edit greeting</a></p>

  - edit.jsp 파일 신규 추가

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>


<%@ page import="javax.portlet.PortletPreferences" %>


<portlet:defineObjects />


<%

PortletPreferences prefs = renderRequest.getPreferences();

String greeting = renderRequest.getParameter("greeting");

if (greeting != null) {

    prefs.setValue("greeting", greeting);

    prefs.store();

%>

    <p>Greeting saved successfully!</p>

<%

}

%>


<%

greeting = (String)prefs.getValue("greeting", "Hello! Welcome to our portal.");

%>


<portlet:renderURL var="editGreetingURL">

    <portlet:param name="mvcPath" value="/edit.jsp" />

</portlet:renderURL>


<aui:form action="<%= editGreetingURL %>" method="post">

    <aui:input label="greeting" name="greeting" type="text" value="<%=greeting %>" />

    <aui:button type="submit" />

</aui:form>


<portlet:renderURL var="viewGreetingURL">

    <portlet:param name="mvcPath" value="/view.jsp" />

</portlet:renderURL>


<p><a href="<%= viewGreetingURL %>">&larr; Back</a></p>

  - {SDK}/portlets 밑에서 수정했으면 다시 deploy를 이미 www 폴더에서 수정했다면 tomcat 다시 restart 한다.

// 수정한 view.jsp 


// 신규 추가한 edit.jsp 



  - *.jsp 에서 중요한 사항

    +  http://java.sun.com/portlet_2_0 에서 정의한 <portlet:renderURL> 태그(taglib)를 사용한다  

    +  edit.jsp에서 aui(AlloyUI == YUI3)를 이용하여 form을 만들고 있다 

    + <portlet:defineObjects/> 를 넣으면 renderRequest, portletConfig, portletPreferences 를 jsp에서 사용할 수 있다. 이것은 jsp에서만 유효하고 여러가지 오브젝트를 사용토록 해준다 

RenderRequest renderRequest: represents the request sent to the portlet to handle a render. renderRequest is only available to a JSP if the JSP was included during the render request phase.


ResourceRequest resourceRequest: represents the request sent to the portlet for rendering resources. resourceRequest is only available to a JSP if the JSP was included during the resource-serving phase.


ActionRequest actionRequest: represents the request sent to the portlet to handle an action. actionRequest is only available to a JSP if the JSP was included during the action-processing phase.


EventRequest eventRequest: represents the request sent to the portlet to handle an event. eventRequest is only available to a JSP if the JSP was included during the event-processing phase.


RenderResponse renderResponse: represents an object that assists the portlet in sending a response to the portal. renderResponse is only available to a JSP if the JSP was included during the render request phase.


ResourceResponse resourceResponse: represents an object that assists the portlet in rendering a resource. resourceResponse is only available to a JSP if the JSP was included in the resource-serving phase.


ActionResponse actionResponse: represents the portlet response to an action request. actionResponse is only available to a JSP if the JSP was included in the action-processing phase.


EventResponse eventResponse: represents the portlet response to an event request. eventResponse is only available to a JSP if the JSP was included in the event-processing phase.


PortletConfig portletConfig: represents the portlet’s configuration including, the portlet’s name, initialization parameters, resource bundle, and application context. portletConfig is always available to a portlet JSP, regardless of the request-processing phase in which it was included.


PortletSession portletSession: provides a way to identify a user across more than one request and to store transient information about a user. A portletSession is created for each user client. portletSession is always available to a portlet JSP, regardless of the request-processing phase in which it was included. portletSession is null if no session exists.


Map<String, Object> portletSessionScope: provides a Map equivalent to the PortletSession.getAtrributeMap() call or an empty Map if no session attributes exist.


PortletPreferences portletPreferences: provides access to a portlet’s preferences. portletPreferences is always available to a portlet JSP, regardless of the request-processing phase in which it was included.


Map<String, String[]> portletPreferencesValues: provides a Map equivalent to the portletPreferences.getMap() call or an empty Map if no portlet preferences exist.



Liferay IDE를 통한 개발 (주의사항)

  - 기본 {TOMCAT_HOME}/webapps/ROOT 를 사용한다. 

  - 기존 ~/liferay_portal/www 에서 다시 원위치로 설정한다.

1) {TOMCAT_HOME}/conf.xml 에서 위치 변경

<Host appBase="/Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps" autoDeploy="true" name="localhost" unpackWARs="true">


2) {PLUGIN_SDK}/build.<username>.properties

app.server.tomcat.lib.global.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/lib/ext

app.server.tomcat.deploy.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps

app.server.parent.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2

app.server.tomcat.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42

app.server.type = tomcat

app.server.tomcat.portal.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps/ROOT

  - 또한 Maven으로 생성시 pom.xml에서 <version> 은 "1.0.0-SNAPSHOT"이 아니라 "portlet" 이라고 준다 



포틀릿의 2 Phase Execution 이해 

  - Action Phase와 Render Phase로 구성된다

  - Action Phase

    + 하나의 포틀릿에서만 유저 인터렉션이 일어날 수있다. 

    + 사용자의 prefereneces는 한번만 변경되고 재변경되지 않는다 

  - Render Phase

    + action phase가 있은 후 모든 포틀릿의 render phase를 호출한다.

1) action phase를 만들기위해서 기존에 Eclipse에서 생성한 "mobiconsoft-sample"에서 자바소스를 추가한다 

    (CLI 방식일 경우 : {SDK}/porlets/mobiconsoft-sample-portlet/WEB-INF/src 밑에 둔다)

     MVCPorlet을 상속받는다 

package com.mobiconsoft.sample;


import java.io.IOException;

import javax.portlet.ActionRequest;

import javax.portlet.ActionResponse;

import javax.portlet.PortletException;

import javax.portlet.PortletPreferences;

import com.liferay.util.bridges.mvc.MVCPortlet;


public class YoungSikGreetingPortlet extends MVCPortlet {

    @Override

    public void processAction(ActionRequest actionRequest, ActionResponse actionResponse)

        throws IOException, PortletException {

        PortletPreferences prefs = actionRequest.getPreferences();

        String greeting = actionRequest.getParameter("greeting");


        if (greeting != null) {

            prefs.setValue("greeting", greeting);

            prefs.store();

        }


        super.processAction(actionRequest, actionResponse);

    }

}


2) portlet.xml 파일의 내용에서 MVCPortlet을 바꾼다 

<portlet-class>com.mobiconsoft.sample.YoungSikGreetingPortlet</portlet-class>


3) edit.jsp 안에 action을 넣어보자 

   - renderURL : render phase에서만 호출 된다 

   - actionURL : 페이지안의 모든 포틀릿을 rendering 하기전에 action phase를 수행한다

   - resourceURL : xml, images, json, AJAX 요청등

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>


<%@ page import="com.liferay.portal.kernel.util.ParamUtil" %>

<%@ page import="com.liferay.portal.kernel.util.Validator" %>

<%@ page import="javax.portlet.PortletPreferences" %>


<portlet:defineObjects />


<%

    PortletPreferences prefs = renderRequest.getPreferences();

    String greeting = (String)prefs.getValue("greeting", "Hello! Welcome to our portal.");

%>


<portlet:actionURL var="editGreetingURL">

    <portlet:param name="mvcPath" value="/edit.jsp" />

</portlet:actionURL>


<aui:form action="<%= editGreetingURL %>" method="post">

        <aui:input label="greeting" name="greeting" type="text" value="<%=

    greeting %>" />

        <aui:button type="submit" />

</aui:form>


<portlet:renderURL var="viewGreetingURL">

        <portlet:param name="mvcPath" value="/view.jsp" />

</portlet:renderURL>


<p><a href="<%= viewGreetingURL %>">&larr; Back</a></p>


4) deploy 해서 확인해 볼 수 있다. 



<참조>

  - 포틀릿 해부하기 

  - 포틀릿 수정하기 

  - 포틀릿 2 Phase Execution

  - pom.xml 파일 샘플 

pom-userxxx-liferay.xml

posted by 윤영식
prev 1 next