2014年3月19日 星期三

Liferay portlet config設定~~

1.先在自己的 portlet.xml 定義config項目;

<..more...>

<init-param>
<name>view-template</name>
<value>/html/tab1.jsp</value>
</init-param>
<init-param>
<name>config-template</name>
<value>/html/configuration.jsp</value>
</init-param>


<..more...>

2.再來 liferay-portal.xml 也定義class的路徑與類別



<liferay-portlet-app>
<portlet>
<portlet-name>yourPortletName</portlet-name>
<icon>/icon.png</icon>
<configuration-action-class>
com.liferay.portal.kernel.portlet.DefaultConfigurationAction
</configuration-action-class>

<..more...>


3.開始設計你的configuration.jsp 這個頁面 會在你的portlet右上角板手圖示裡面顯示;
 以下是為了要讓使用者可以自由選擇顯示筆數
deltaSet  會在search container  的 delta = " <%=deltaSet %>"  用到;


<%@include file="/html/init.jsp"%>

<liferay-portlet:actionURL portletConfiguration="true"
var="configurationURL" />
<aui:form action="<%=configurationURL%>" method="post">
<!-- 以下是用來控制寫入的 -->
<aui:input name="<%=Constants.CMD%>" type="hidden"
value="<%=Constants.UPDATE%>" />

<aui:select label="顯示筆數"
name="preferences--deltaSet--">
<aui:option label="5" selected="<%= deltaSet == 5 %>" />
<aui:option label="10" selected="<%= deltaSet == 10 %>" />
<aui:option label="20" selected="<%= deltaSet == 20 %>" />
<aui:option label="30" selected="<%= deltaSet == 30 %>" />
<aui:option label="50" selected="<%= deltaSet == 50 %>" />
</aui:select>
<%!SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); %>
<aui:input name="abc" label="最後設定日期" disabled="true" value="<%=mdfDate2%>"/>
<aui:input name="preferences--mdfDate2--" type="hidden" value="<%=sdf.format(new Date())%>"/>

<aui:button type="submit" />
</aui:form>

name的命名規則  一定要這樣   "preference--你高興--"   不然他不認得這是preference的變數;


4. 這是init.jsp   的寫法;  這樣只要任何頁面有 include init.jsp   都可以取得 config中設定的變數
來自由使用;
preferences 所儲存的設定變數 會寫入資料庫; 不用怕重開之後會不見;

<%
PortletPreferences preferences = renderRequest.getPreferences();

String portletResource = ParamUtil.getString(request,
"portletResource");
if (Validator.isNotNull(portletResource)) {
preferences = PortletPreferencesFactoryUtil.getPortletSetup(
request, portletResource);
}

int deltaSet = GetterUtil.getInteger(preferences.getValue("deltaSet",
null));
String mdfDate2 = GetterUtil.getString(preferences.getValue("mdfDate2",
null), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
%>

GetterUtil.getString(value, default Value );  如果第一個參數value是null  那他會以第二個參數給預設;


String title = GetterUtil.getString(xxx.getTitle(), "你高興" );
if(xxx.getTitle() == null)
title = "你高興";




更深入的了解 可以參考:
http://rritw.com/a/bianchengyuyan/C__/20130823/414769.html
http://go.rritw.com/supercharles888.blog.51cto.com/609344/1281101





















2014年3月18日 星期二

implement Indexer to a portlet

參考資料:
http://blog.csdn.net/smile_juan/article/details/8117497



1. 我們需要先在 liferay-portlet.xml 加入自己indexer的class

<portlet>
<portlet-name>BookServiceBuilder</portlet-name>
<icon>/icon.png</icon>
<indexer-class>
com.xxx.xxx.xxx.ProjetIndexer</indexer-class>
...more



2. 開始實作indexer 的類別



import java.util.List;
import java.util.Locale;
import javax.portlet.PortletURL;
import com.fansysoft.danny.model.MyData;
import com.fansysoft.danny.service.MyDataLocalServiceUtil;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.search.BaseIndexer;
import com.liferay.portal.kernel.search.Document;
import com.liferay.portal.kernel.search.DocumentImpl;
import com.liferay.portal.kernel.search.Field;
import com.liferay.portal.kernel.search.SearchContext;
import com.liferay.portal.kernel.search.SearchEngineUtil;
import com.liferay.portal.kernel.search.Summary;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.service.ClassNameLocalServiceUtil;
import com.liferay.portal.util.PortletKeys;
import com.liferay.portlet.asset.model.AssetCategory;
import com.liferay.portlet.asset.service.AssetCategoryLocalServiceUtil;
import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;


public class ProjetIndexer extends BaseIndexer{

public static final String[] CLASS_NAMES = { MyData.class.getName() };
public static final String PORTLET_ID = WebKeys.PORTLET_ID;
Log logger = LogFactoryUtil.getLog(ProjetIndexer.class);




@Override
public String[] getClassNames() {
logger.info("get class names..");
return CLASS_NAMES;
}




@Override
public String getPortletId() {
logger.info("get portlet id..");
return PORTLET_ID;
}




@Override
protected String getPortletId(SearchContext arg0) {
logger.info("get portlet id..SearchContext");
return PORTLET_ID;
}




@Override
protected void doDelete(Object obj) throws Exception {
logger.info("do delete..");
MyData book = (MyData) obj;
Document document = new DocumentImpl();
document.addUID(this.getPortletId(), book.getPrimaryKey());
SearchEngineUtil.deleteDocument(book.getCompanyId(),
document.get(Field.UID));
}




@Override
protected Document doGetDocument(Object obj) throws Exception {
logger.info("do get document...");
MyData MyData = (MyData) obj;
long companyId = MyData.getCompanyId();
long groupId = getParentGroupId(MyData.getGroupId());
long scopeGroupId = MyData.getGroupId();
long userId = MyData.getUserId();
long resourcePrimKey = MyData.getPrimaryKey();



String myDataId = String.valueOf(MyData.getMydataId());
String myDataName = MyData.getUserName();
String myDataAge = String.valueOf(MyData.getUserAge());
String myDataPhone = MyData.getUserPhone();
String myDataEmail = MyData.getUserEmail();
String myDataCreateDate = MyData.getCreateDate().toString();




long[] assetCategoryIds = AssetCategoryLocalServiceUtil.getCategoryIds(
MyData.class.getName(), resourcePrimKey);




List<AssetCategory> categories = AssetCategoryLocalServiceUtil
.getCategories(MyData.class.getName(), resourcePrimKey);




String[] assetCategoryNames = StringUtil.split(ListUtil.toString(
categories, "name"));
String[] assetTagNames = AssetTagLocalServiceUtil.getTagNames(
MyData.class.getName(), resourcePrimKey);
Document document = new DocumentImpl();
document.addUID(this.getPortletId(), resourcePrimKey);
document.addKeyword(Field.COMPANY_ID, companyId);
document.addKeyword(Field.PORTLET_ID, getPortletId());
document.addKeyword(Field.GROUP_ID, groupId);
document.addKeyword(Field.SCOPE_GROUP_ID, scopeGroupId);
document.addKeyword(Field.USER_ID, userId);
document.addText(Field.CLASS_PK, myDataId);
document.addText(Field.USER_NAME, myDataName);
document.addText(Field.CONTENT, myDataAge);
document.addText(Field.DESCRIPTION, myDataPhone);
document.addText(Field.SNIPPET, myDataEmail);
document.addText(Field.CREATE_DATE, myDataCreateDate);
// document.addKeyword(Field.TITLE, title);




document.addKeyword(Field.ASSET_CATEGORY_IDS, assetCategoryIds);
document.addKeyword("assetCategoryNames", assetCategoryNames);
// document.addKeyword(Field.ASSET_CATEGORY_NAMES, assetCategoryNames);
document.addKeyword(Field.ASSET_TAG_NAMES, assetTagNames);




document.addKeyword(Field.ENTRY_CLASS_NAME, MyData.class.getName());
document.addKeyword(Field.ENTRY_CLASS_PK, resourcePrimKey);
return document;
}




@Override
protected Summary doGetSummary(Document document, Locale arg1,
String snippet, PortletURL portletURL) throws Exception {
logger.info("do get summary..");
String title = document.get(Field.TITLE);
String content = snippet;
if (Validator.isNull(snippet)) {
content = document.get(Field.DESCRIPTION);
if (Validator.isNull(content)) {
content = document.get(Field.CONTENT);
}
}
String resourcePrimKey = document.get(Field.ENTRY_CLASS_PK);
portletURL.setParameter("jspPage", "/html/indexer/view.jsp");
portletURL.setParameter("resourcePrimKey", resourcePrimKey);
return new Summary(title, content, portletURL);
}




@Override
protected void doReindex(Object obj) throws Exception {
logger.info("do reindex...1");
MyData book = (MyData) obj;
SearchEngineUtil.updateDocument(book.getCompanyId(),
doGetDocument(book));
}




@Override
protected void doReindex(String[] ids) throws Exception {
logger.info("do reindex...2");
long companyId = GetterUtil.getLong(ids[0]);
// unimplemented
}




@Override
protected void doReindex(String arg0, long classPK) throws Exception {
logger.info("do reindex...3");
MyData book = MyDataLocalServiceUtil.getMyData(classPK);
doReindex(book);
}
}








3. 簡單做個jsp 可以讓你輸入keywords 的欄位
view.jsp




<%@include file="/html/indexer/init.jsp" %>




<liferay-portlet:renderURL varImpl="searchURL">
<portlet:param name="jspPage" value="/html/indexer/search.jsp" />
</liferay-portlet:renderURL>
<aui:form action="<%=searchURL%>" method="get" name="fm0">
<liferay-portlet:renderURLParams varImpl="searchURL" />
<aui:input name="redirect" type="hidden" value="<%=currentURL%>" />
<aui:input name="groupId" type="hidden" value="10180" />
<div class="portlet-toolbar search-form">
<span class="aui-search-bar"> <aui:input
inlineField="<%=true%>" label="" name="keywords" size="30"
title="search-entries" type="text" /> <aui:button type="submit"
value="search" />
</span>
</div>
</aui:form>








4.再來做一個取得keywords之後 顯示結果的jsp
search.jsp

<%@ include file="/html/indexer/init.jsp"%>
<%
String redirect = ParamUtil.getString(request, "redirect");
String keywords = ParamUtil.getString(request, "keywords");
%>
<portlet:renderURL var="homeURL">




</portlet:renderURL>
<liferay-portlet:renderURL varImpl="searchURL">
<portlet:param name="jspPage" value="/html/indexer/search.jsp" />
</liferay-portlet:renderURL>


<aui:form action="<%=searchURL%>" method="get" name="fm">
<liferay-portlet:renderURLParams varImpl="searchURL" />
<aui:input name="redirect" type="hidden" value="<%=redirect%>" />


<liferay-ui:header backURL="<%=homeURL%>" title="search" />


<%
PortletURL portletURL = renderResponse.createRenderURL();

portletURL.setParameter("jspPage", "/html/indexer/search.jsp");
portletURL.setParameter("redirect", redirect);
portletURL.setParameter("keywords", keywords);

List<String> headerNames = new ArrayList<String>();


headerNames.add("#");
headerNames.add("Name");
headerNames.add("Age");
headerNames.add("Phone");
headerNames.add("Email");
headerNames.add("CreateDate");




SearchContainer searchContainer = new SearchContainer(
renderRequest,
null,
null,
SearchContainer.DEFAULT_CUR_PARAM,
SearchContainer.DEFAULT_DELTA,
portletURL,
headerNames,
LanguageUtil
.format(pageContext,
"no-entries-were-found-that-matched-the-keywords-x",
"<strong>" + HtmlUtil.escape(keywords)
+ "</strong>"));




try {
Indexer indexer = IndexerRegistryUtil
.getIndexer(MyData.class);
SearchContext searchContext = SearchContextFactory
.getInstance(request);


searchContext.setStart(searchContainer.getStart());
searchContext.setKeywords(keywords);
searchContext.setEnd(searchContainer.getEnd());


Hits results = indexer.search(searchContext);


int total = results.getLength();
searchContainer.setTotal(total);


List resultRows = searchContainer.getResultRows();

for (int i = 0; i < results.getDocs().length; i++) {
Document doc = results.doc(i);

ResultRow row = new ResultRow(doc, i, i);

// Position
row.addText(searchContainer.getStart() + i + 1
+ StringPool.PERIOD);
// Book
long bookId = GetterUtil.getLong(doc
.get(Field.ENTRY_CLASS_PK));

MyData book = null;

try {
book = MyDataLocalServiceUtil.getMyData(bookId);
book = book.toEscapedModel();

} catch (Exception e) {
if (_log.isWarnEnabled()) {
_log.warn("Book search index is stale and contains entry "
+ bookId);
}
continue;
}
PortletURL rowURL = renderResponse.createRenderURL();

rowURL.setParameter("jspPage", "/html/indexer/view.jsp");
rowURL.setParameter("redirect", currentURL);
rowURL.setParameter("resourcePrimKey",
String.valueOf(book.getMydataId()));


row.addText(book.getUserName());
row.addText(String.valueOf(book.getUserAge()));
row.addText(book.getUserPhone());
row.addText(book.getUserEmail());
row.addText(book.getCreateDate().toString());




resultRows.add(row);
}
%>
<span class="aui-search-bar"> <aui:input inlineField="<%=true%>"
label="" name="keywords" size="30" title="search-entries" type="text"
value="<%=keywords%>" /> <aui:button type="submit" value="search" />
</span>


<br />
<br />
<liferay-ui:search-iterator searchContainer="<%=searchContainer%>" />


<%
} catch (Exception e) {
_log.error(e.getMessage());
}
%>
</aui:form>

<%
if (Validator.isNotNull(keywords)) {
PortalUtil.addPortletBreadcrumbEntry(request,
LanguageUtil.get(pageContext, "search") + ": "
+ keywords, currentURL);
}
%>

<%!private static Log _log = LogFactoryUtil
.getLog("ContentManagment.docroot.html.indexer.search_jsp");%>



5. 再來就去實作 自己model的impl 的addxxx{ }
MyDataLocalServiceImpl.

public MyData addMyData(MyData newMyData, long userId,
ServiceContext serviceContext) throws SystemException,
PortalException {
MyData myData = myDataPersistence.create(counterLocalService
.increment(MyData.class.getName()));
myData.setCompanyId(newMyData.getCompanyId());
myData.setGroupId(newMyData.getGroupId());
myData.setUserId(serviceContext.getUserId());



myData.setUserName(newMyData.getUserName());
myData.setUserAge(newMyData.getUserAge());
myData.setUserPhone(newMyData.getUserPhone());
myData.setUserEmail(newMyData.getUserEmail());
myData.setCreateDate(newMyData.getCreateDate());
myData.setModifiedDate(newMyData.getModifiedDate());



myData.setStatus(WorkflowConstants.STATUS_DRAFT);
myDataPersistence.update(myData, false);



Indexer indexer = IndexerRegistryUtil.getIndexer(MyData.class);
indexer.reindex(myData);

return myData;
}


6. 這是我的 service.xml  可供參考



<service-builder package-path="com.xxx.xxx.xxx">
<author>yourName</author>
<namespace>yourNS</namespace>


<entity name="MyData" uuid="true" local-service="true" remote-service="false">

<!-- PK fields -->

<column name="mydataId" type="long" primary="true" />

<!-- Audit fields -->

<column name="userName" type="String" />
<column name="userAge" type="int" />
<column name="userPhone" type="String" />
<column name="userEmail" type="String" />
<column name="createDate" type="Date" />
<column name="modifiedDate" type="Date" />



<column name="status" type="int" />
<column name="statusByUserId" type="long" />
<column name="statusByUserName" type="String" />
<column name="statusDate" type="Date" />
<column name="companyId" type="long" />
<column name="groupId" type="long" />
<column name="userId" type="long" />

<order>
<order-column name="userId" order-by="asc"/>
<order-column name="modifiedDate" order-by="desc"/>
</order>
<!-- Finder methods -->

<finder name="userId" return-type="MyData">
<finder-column name="userId"/>
</finder>
<finder name="userName" return-type="Collection">
<finder-column name="userName" />
</finder>
<finder name="userAge" return-type="Collection">
<finder-column name="userAge"/>
</finder>



<reference package-path="com.liferay.portal" entity="User" />
<reference package-path="com.liferay.portlet.asset" entity="AssetEntry" />
<reference package-path="com.liferay.portlet.ratings" entity="RatingsStats" />



</entity>





2014年3月11日 星期二

用service build 連到非預設database 使用util做CRUD

參考資料:
http://www.liferaysavvy.com/2013/08/liferay-plugin-portlet-connecting-to.html


我的非預設 database : Training
裡面的table  :  training


文件路徑D:\server\liferay-portal-6.1.2-ce-ga3\tomcat-7.0.40\webapps\ROOT\WEB-INF\classes



portal-ext.properties
=============================================
#mysql
jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.url=jdbc:mysql://localhost/lportal61spec?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.default.username=root
jdbc.default.password=root

jdbc.one.driverClassName=com.mysql.jdbc.Driver
jdbc.one.url=jdbc:mysql://localhost/training?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.one.username=root
jdbc.one.password=root

shard.selector=com.liferay.portal.dao.shard.ManualShardSelector
shard.available.names=default,one
shard.default.name=default

jdbc.one   = 待會在文件內會用到的識別子
training  = 是想要連到的databaseName

portal-ext.properties  內容有更動 tomcat 需要重新啟動:


再來 在自己的project裡


先根據外部database 裡面的 table 欄位  做設定;
=====================================================
<service-builder package-path="com.bc.od.store">
<author>yourName</author>
<namespace>yourNS</namespace>

<entity name="Training" local-service="true"  remote-service="false" 
data-source="otherDatasource" session-factory="anotherSessionFactory">
<column name="userId" type="long" primary="true"></column>
<column name="dogName" type="String"></column>
<column name="wifeName" type="String"></column>
</entity>
</service-builder>

黃色字串 是要與下面那份文件 做 識別子;

build它===============

再來建立 ext-spring.xml 檔案
放在專案的  docroot/WEB-INF/src/META-INF  底下;
=====================================================


<?xml version="1.0"?>
<beans default-destroy-method="destroy" default-init-method="afterPropertiesSet"
xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<bean id="otherDatasource"
class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource" ref="otherDatasourceWrapper" />
</bean>
<bean id="otherDatasourceImpl"
class="com.liferay.portal.dao.jdbc.spring.DataSourceFactoryBean">
<property name="propertyPrefix" value="jdbc.one." />
</bean>
<bean id="otherDatasourceWrapper" class="com.liferay.portal.dao.jdbc.util.DataSourceWrapper">
<constructor-arg ref="otherDatasourceImpl" />
</bean>
<bean class="com.liferay.portal.dao.jdbc.util.DataSourceSwapper">
<property name="liferayDataSourceWrapper" ref="otherDatasourceWrapper" />
</bean>
<bean id="anotherHibernateSessionFactory" class="com.liferay.portal.kernel.spring.util.SpringFactoryUtil"
factory-method="newBean">
<constructor-arg
value="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration" />
<constructor-arg>
<map>
<entry key="dataSource" value-ref="otherDatasource" />
</map>
</constructor-arg>
</bean>
<bean id="anotherSessionFactory" class="com.liferay.portal.kernel.spring.util.SpringFactoryUtil"
factory-method="newBean">
<constructor-arg
value="com.liferay.portal.dao.orm.hibernate.PortletSessionFactoryImpl" />
<constructor-arg>
<map>
<entry key="dataSource" value-ref="otherDatasource" />
<entry key="sessionFactoryClassLoader" value-ref="portletClassLoader" />
<entry key="sessionFactoryImplementor" value-ref="anotherHibernateSessionFactory" />
</map>
</constructor-arg>
</bean>
</beans>

每個bean 的id  都有互相參考到... 字串不要打錯:


再來就可以在view.jsp 測試看看  可不可以對 外部 Training 的資料庫的 table training做CRUD


<%
List<Training> trainings= null;
Training  training= null;
try {
trainings= TrainingLocalServiceUtil.getTrainings(-1, -1);
training= TrainingLocalServiceUtil
.createTraining(CounterLocalServiceUtil.increment());
 training.setDogName("aaa");
 training.setWifeName("bbb");
 TrainingLocalServiceUtil.updateTraining(training);

} catch (Exception e) {
e.printStackTrace();
}

if (trainings !=  null ) {

for (Training m : trainings) {
out.print(m.getUserId() + "<br>");
}
}
%>











2014年3月10日 星期一

使用liferay build service 連線到已存在的 table

參考資料
http://liferayatglance.blogspot.jp/2011/11/connecting-to-different-database-using.html



先建立service.xml
=====================================================
<service-builder package-path="com.bc.od.store">
<author>yourName</author>
<namespace>yourNS</namespace>

<entity name="Training" local-service="true" table="training" remote-service="false" data-source="otherDatasource">
<column name="userId" type="long" primary="true"></column>
<column name="firstName" type="String"></column>
<column name="lastName" type="String"></column>
</entity>
</service-builder>

entity name="Training"  (物件名稱)
table="training"             (資料庫table名稱)
data-source="otherDatasource"  (底下那份文件的識別子)



build完後

再來建立 "ext-spring.xml" 放在 WEB-INF/src/META-INF dir底下

ext-spring.xml
=====================================================
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
default-destroy-method="destroy" default-init-method="afterPropertiesSet"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<bean id="otherDatasource" lazy-init="true"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost/training?useUnicode=true" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="liferayHibernateSessionFactory"
class="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration">
<property name="dataSource" ref="otherDatasource" />
</bean>
</beans>

當中的training是 databaseName ;



再來就測試看看 能不能執行溜~~~~~


<%
java.util.List<com.bc.od.store.model.Training> trainings = null;
com.bc.od.store.model.Training aTrain = null;

try{
trainings = com.bc.od.store.service.TrainingLocalServiceUtil.getTrainings(0, 2);
aTrain = com.bc.od.store.service.TrainingLocalServiceUtil.getTraining(1);
}
catch(Exception e){
e.printStackTrace();
}
if(trainings != null){
System.out.println("trainings are not null");
for(com.bc.od.store.model.Training t: trainings){
System.out.println("training: " + t.getFirstName());
}
}

if(aTrain != null){
System.out.println("train is not null: " + aTrain.getLastName());
}
%>


console視窗應該會出現;

trainings are not null
training: aaa
training: bbb
train is not null: aaa















2014年3月5日 星期三

Kaleo Workflow 內嵌自訂portlet



資料來源參考:

http://liferayzone.wordpress.com/2013/11/29/kaleo-workflow-configuration-for-custom-portlet-in-liferay-6-1/



先照上面資料來源做法 照做一次,下面有關於view & controller的部分。



FeedbackController  .  java
=====================================
public class FeedbackController extends MVCPortlet {

public void addFeedback(ActionRequest actionRequest,
ActionResponse actionResponse) throws SystemException, IOException,
PortalException, ParseException {

ThemeDisplay themeDisplay = (ThemeDisplay) actionRequest
.getAttribute(WebKeys.THEME_DISPLAY);
ServiceContext serviceContext = ServiceContextFactory.getInstance(
Feedback.class.getName(), actionRequest);
String feedbackText = actionRequest.getParameter("feedbackText");
long pkId = CounterLocalServiceUtil.increment(Feedback.class.getName());
Long groupId = themeDisplay.getScopeGroupId();
Long userId = themeDisplay.getUserId();
Feedback newFeedback = FeedbackLocalServiceUtil.createFeedback(pkId);
newFeedback.setFeedbackText(feedbackText);
newFeedback.setFeedbackDate(new Date());
newFeedback.setCompanyId(themeDisplay.getCompanyId());
newFeedback.setGroupId(themeDisplay.getScopeGroupId());
FeedbackLocalServiceUtil.addFeedback(newFeedback, userId,
serviceContext);
PortletURL portletURL = PortletURLFactoryUtil.create(actionRequest,
(String) actionRequest.getAttribute(WebKeys.PORTLET_ID),
themeDisplay.getPlid(), PortletRequest.RENDER_PHASE);
portletURL.setParameter("mvcPath", "/html/mylist.jsp");
actionResponse.sendRedirect(portletURL.toString());
}
}



mylist.jsp
==============================================
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="/html/init.jsp"%>


<%
// 返回前頁 
String currentURL = PortalUtil.getCurrentURL(request);
String redirect = ParamUtil.getString(request, "redirect",
currentURL);
%>

<liferay-portlet:renderURL var="addURL">
<liferay-portlet:param name="mvcPath" value="/html/add.jsp" />
<portlet:param name="redirect" value="<%=redirect.toString()%>" />
</liferay-portlet:renderURL>

<aui:button type="button" value="add" onClick="<%=addURL.toString()%>" />
<liferay-ui:search-container emptyResultsMessage="no data">
<liferay-ui:search-container-results>
<%
List<Feedback> tempList = FeedbackLocalServiceUtil
.getFeedbacks(-1, -1);
List<Feedback> myList = new LinkedList<Feedback>();
if (tempList != null && tempList.size() > 0) {
for(Feedback f : tempList){
if(f.getStatus()== WorkflowConstants.STATUS_APPROVED)
myList.add(f);
}
}
results = ListUtil.subList(myList,
searchContainer.getStart(),
searchContainer.getEnd());
total = myList.size();

pageContext.setAttribute("results", results);
pageContext.setAttribute("total", total);
%>

</liferay-ui:search-container-results>


<liferay-ui:search-container-row
className="com.fansysoft.danny.model.Feedback" keyProperty="userId"
modelVar="feedback" escapedModel="<%=true%>">
<liferay-ui:search-container-column-text property="feedbackId"
name="id" />
<liferay-ui:search-container-column-text property="feedbackText"
name="名字" />

<liferay-ui:search-container-column-text name="日期">
<%
SimpleDateFormat sdf = new SimpleDateFormat(
"yyyy/MM/dd");
%>
<%=sdf.format(feedback.getFeedbackDate())%>

</liferay-ui:search-container-column-text>

<liferay-portlet:renderURL var="editURL">
<liferay-portlet:param name="pkId_edit"
value="<%=String.valueOf(feedback.getFeedbackId())%>" />
<liferay-portlet:param name="mvcPath" value="/html/edit.jsp" />
<portlet:param name="redirect" value="<%=redirect.toString()%>" />
</liferay-portlet:renderURL>

<liferay-portlet:actionURL name="deleteData" var="deleteURL">
<liferay-portlet:param name="pkId"
value="<%=String.valueOf(feedback.getFeedbackId())%>" />
</liferay-portlet:actionURL>

<liferay-ui:search-container-column-text name="編輯">
<aui:button type="button" value="edit" onClick="<%=editURL%>" />
</liferay-ui:search-container-column-text>

<liferay-ui:search-container-column-text name="" value="刪除"
href="<%=deleteURL.toString()%>" />
<%-- 
<liferay-ui:search-container-column-jsp name="設定"
path="/html/action.jsp" />
--%>

</liferay-ui:search-container-row>
<liferay-ui:search-iterator />
</liferay-ui:search-container>






add.jsp
==============================================
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="/html/init.jsp" %>

<%
String currentURL = PortalUtil.getCurrentURL(request);
String redirect = ParamUtil.getString(request, "redirect", currentURL);
%>

<liferay-portlet:actionURL name="addFeedback" var="addURL" >
<portlet:param name="<%=Constants.CMD %>" value="<%=Constants.ADD %>"/>
</liferay-portlet:actionURL>

<liferay-ui:header
 backURL="<%= redirect %>"
 title="新增"
/>

<aui:form method="post" action="<%=addURL.toString()%>">
<aui:input type="textarea" name="feedbackText" label="測試輸入欄位" value="danny" />
<%-- <aui:input name="userAge" label="日期" value="2014-3-5 14:47:13" /> --%>
<aui:button type="submit" />

</aui:form>




2014年3月4日 星期二

Kaleo Workflow integration custom portlet

先在自己portlet  建立一個service.xml  以下的欄位可供參考,
建立好後即可build-service。
紅色文字部分是參考到database的 WorkflowInstanceLink 資料表


service.xml


<column name="resourcePrimKey" type="long"></column>
<column name="version" type="int"></column>
<column name="title" type="String"></column>
<column name="content" type="String"></column>
<column name="description" type="String"></column>
<column name="priority" type="int"></column>
<column name="status" type="int"></column>
<column name="statusByUserId" type="long"></column>
<column name="statusByUserName" type="String"></column>
<column name="statusDate" type="Date"></column>

<!-- Order -->

<order by="desc">
<order-column name="modifiedDate" />
</order>
<finder name="R_S" return-type="Collection">
<finder-column name="resourcePrimKey"></finder-column>
<finder-column name="status"></finder-column>
</finder>
<reference package-path="com.liferay.portal" entity="WorkflowInstanceLink"></reference>

=====================================================================

接下來 在 Liferay-portlet.xml 中,加入紅色部分<workflow-handler> 的tag,中間包夾的是workflowHandler的JAVA類別路徑。
請自行創建  class  並extends BaseWorkflowHandler ,並orverride 三個 abstract method。


Liferay-portlet.xml

<portlet>
<portlet-name>WorkflowCustom</portlet-name>
<icon>/icon.png</icon>
<workflow-handler>com.xxx.xxx.portlet.ArticleWorkflowHandler</workflow-handler>
<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>/js/main.js</footer-portlet-javascript>
<css-class-wrapper>WorkflowCustom-portlet</css-class-wrapper>
</portlet>


您需要擴展com.liferay.portal.kernel.workflow.BaseWorkflowHandler


public class ArticleWorkflowHandler extends BaseWorkflowHandler {

public static final String CLASS_NAME = Demo.class.getName();
@Override
public String getClassName() {
// TODO Auto-generated method stub
return CLASS_NAME;
}

@Override
public String getType(Locale locale) {
// TODO Auto-generated method stub
return LanguageUtil.get(locale, "model.resource." + CLASS_NAME);
}

@Override
public Object updateStatus(int status, Map<String, Serializable> workflowContext)
throws PortalException, SystemException {
long userId = GetterUtil.getLong((String) workflowContext.get(WorkflowConstants.CONTEXT_USER_ID));
        long resourcePrimKey = GetterUtil.getLong((String) workflowContext.get(WorkflowConstants.CONTEXT_ENTRY_CLASS_PK));
        ServiceContext serviceContext = (ServiceContext) workflowContext.get("serviceContext");
        return DemoLocalServiceUtil.updateStatus(userId, resourcePrimKey,status, serviceContext);
}

}
====================================================================

Now you need to implement one method called updateStatus() in you LocalServiceImpl class. which will return object of your model class.


public class DemoLocalServiceImpl extends DemoLocalServiceBaseImpl
{
  public Demo updateStatus(long userId, long resourcePrimKey, int status,ServiceContext serviceContext)   
  {
    User user = userPersistence.findByPrimaryKey(userId);
    Date now = new Date();
    // Article
    Demo dempObj = null;
    dempObj.setStatus(status);
    dempObj.setStatusByUserId(user.getUserId());
    dempObj.setStatusByUserName(user.getFullName());
    dempObj.setStatusDate(serviceContext.getModifiedDate(now));
    demoPersistence.update(dempObj, false);
    if (status != WorkflowConstants.STATUS_APPROVED)
    {
      return dempObj;
    }
    return dempObj;
  }
}
=================================================================================


Now Deploy service and portlet you will find out your asset in control panel as showing below .now you can apply any definition on that.





 
資料來源參考
http://liferayzone.wordpress.com/2013/11/29/kaleo-workflow-configuration-for-custom-portlet-in-liferay-6-1/
http://stackoverflow.com/questions/17853340/kaleo-workflow-in-custom-portlet
http://stackoverflow.com/questions/9511344/how-to-integrate-kaleo-workflow-in-custom-portlet
http://www.cignex.com/articles/applying-advanced-workflow-custom-assets-liferay-6