포틀릿을 생성하고 세부사항에 대하여 알아보고, 포틀릿의 두가지 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 %>">← 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 %>">← Back</a></p>
4) deploy 해서 확인해 볼 수 있다.
<참조>
- 포틀릿 해부하기
- 포틀릿 수정하기
- 포틀릿 2 Phase Execution
- pom.xml 파일 샘플
pom-userxxx-liferay.xml