Liferay开发学习(1)
Liferay 6.1開發(fā)學(xué)習(xí)(一):環(huán)境搭建
一、資源準(zhǔn)備
以下資源內(nèi)容可以在Liferay的官方網(wǎng)站下載,1-3在http://www.liferay.com/downloads/liferay-portal/available-releases下載,Liferay IDE在http://www.liferay.com/downloads/liferay-projects/liferay-ide處下載。
請將以上資源解壓,推薦在某一個盤下面建立一個Liferay的目錄,將IDE、SDK、Liferay-portal-6.1.1-ce-ga2和源碼后解壓后放到這個目錄下面。
二、配置SDK
打開Liferay IDE,Window-->Preferences-->Liferay-->Installed Plugin SDK,點(diǎn)擊右邊的Add…按鈕,選擇Liferay plugins SDK的解壓目錄,如下圖所示,點(diǎn)擊OK,完成SDK的配置。
三、配置Liferay運(yùn)行環(huán)境(以Tomcat為例)
打開Liferay IDE,Window-->Preferences-->Server-->Runtime Environment,點(diǎn)擊右邊Add…,在彈出的服務(wù)器選擇里面選擇Liferay,Inc-->Liferay v6.1 CE (Tomcat 7),請?jiān)凇癈reate a new location server”打上勾。
點(diǎn)擊Next,選擇liferay-portal-6.1.1-ce-ga2的解壓目錄,如下圖:
點(diǎn)擊Finish完成Tomcat的配置;或者點(diǎn)擊“Next”,此步驟可以在Liferay source location處選擇Liferay的源碼,或者跳過,推薦關(guān)聯(lián)一下Liferay的源碼,其他的兩個可選,點(diǎn)擊Finish完成Tomca的配置。
四、運(yùn)行Liferay
經(jīng)過上面的三步,在Liferay IDE(Eclipse 4.2)的下方的server面板處,可以看到Liferay 6.1 CE Server,現(xiàn)在點(diǎn)擊運(yùn)行。稍等片刻,待Tomcat啟動完成后,打開瀏覽器輸入http://localhost:8080/,在Liferay第一次運(yùn)行的時候會出現(xiàn)一個配置向?qū)?#xff08;此功能為Liferay 6.1開始新增)。
可以在此配置Liferay門戶名稱、使用語言、管理員的姓名、電子郵件,數(shù)據(jù)庫的連接信息(先在數(shù)據(jù)庫里面建立數(shù)據(jù)庫lportal)等內(nèi)容。如上圖所示,如果出現(xiàn)“數(shù)據(jù)庫連接不能建立。請檢查您的連接設(shè)置。”請檢查數(shù)據(jù)庫是否已經(jīng)建立,或者數(shù)據(jù)庫名、帳號、密碼等信息是否正確。
靜心等待Liferay的初始化,可能需要幾分鐘時間,當(dāng)Liferay初始化完成后,會自動跳轉(zhuǎn)到配置保存成功的頁面。
根據(jù)Liferay的提示進(jìn)行密碼設(shè)置、密碼提示問題設(shè)置等,然后跳轉(zhuǎn)到Liferay的主頁。
五、Liferay IDE的其他配置
設(shè)置工作區(qū)編碼
Liferay的開發(fā)環(huán)境我們需要工程的編碼為UTF-8,新安裝的Eclipse的默認(rèn)編碼為GBK,修改方式為WindowàPreferencesàGeneralàWorkspace,在這下面的Text file encoding處選擇other,UTF-8。點(diǎn)擊OK保存。
代碼提示、控制臺緩沖區(qū)的大小
可以參考前面的一篇博客:MyEclipse/Eclipse的一些技巧
中文字體偏小
可以參考之前一篇博客:解決eclipse3.7中文字體小
六、Liferay的大概使用介紹
在四的基礎(chǔ)上,在右上角可以看到有一個訪問,點(diǎn)擊可以看到有控制面板、我的公共主頁、我的個人主頁、Liferay(這里顯示的是在配置向?qū)幵O(shè)置的門戶名稱)。這幾個內(nèi)容是什么意思呢?
控制面板:這個算是liferay的后臺管理。
我的公共主頁:其他人可以看到的自己的頁面內(nèi)容,一般放置的如個人博客等展示給其他人看的內(nèi)容。
我的個人主頁:個人主頁的東西是只有自己可以看到,其他人看不到的,一般放置自己的日程,收集的站點(diǎn),常用的小工具等等內(nèi)容,是自己的私有空間。
在控制面板里面主要分為個人信息、站點(diǎn)設(shè)置、門戶設(shè)置、服務(wù)器信息等。如果是一般權(quán)限的用戶只能看到個人信息。一般開發(fā)的管理功能的頁面均放置在此控制面板處,后面介紹如何將自己開發(fā)的Portlet,放置在這里。
現(xiàn)在回到“我的公共頁面”或者“我的個人主頁”。依次介紹一下頂部左邊各按鈕的作用。
編輯控制:打上勾之后顯示portlet的控制按鈕,可以勾上和反選看一下效果。如果勾上仍然沒有出現(xiàn)portlet的控制按鈕,而說明當(dāng)前登錄的用戶沒有此portlet的控制權(quán)限。
管理:管理里面有頁面、頁面布局、站點(diǎn)頁面、站點(diǎn)內(nèi)容四個菜單。頁面和站點(diǎn)頁點(diǎn)功能類似,差別只在于點(diǎn)進(jìn)去后的默認(rèn)位置不同;站點(diǎn)內(nèi)容和后臺的控制面板處站點(diǎn)的內(nèi)容一樣。頁面布局是調(diào)整當(dāng)前頁面使用什么樣的布局,如一欄,兩欄,三欄等這些內(nèi)容。
添加:點(diǎn)擊添加顯示的是可以添加的portlet,默認(rèn)的只有幾個,點(diǎn)擊更多,可以看到所有的有權(quán)限的portlet(不同的登錄用戶,根據(jù)權(quán)限的不同看到的portlet不同)。可以添加一些看看效果。
上頁內(nèi)容只是Liferay的一些大概介紹,不熟悉的可以隨便點(diǎn)點(diǎn),熟悉一下相關(guān)內(nèi)容。
七、其他
1、可以嘗試修改一個Liferay里面的eclipse.ini的里面的JVM內(nèi)存配置,可以提高eclipse的響應(yīng),我將里面的-Xms和-Xmx均調(diào)到了768M。
2、可以修改一下Eclipse的代碼提示等,參看http://www.huqiwen.com/2012/06/25/some-skill-about-myeclipse-eclipse/
3、Liferay的學(xué)習(xí)可以多看看Liferay官方網(wǎng)站的文檔和WIKI,雖然質(zhì)量不是很可,但也可以學(xué)到不少內(nèi)容。
http://www.liferay.com/documentation/liferay-portal/6.1/development
http://www.liferay.com/community/wiki
Liferay 6.1開發(fā)學(xué)習(xí)(二):創(chuàng)建一個Portlet工程
使用Liferay的SDK創(chuàng)建一個簡單的Portlet,此Portlet不包括業(yè)務(wù)邏輯、不包括數(shù)據(jù)庫,只有簡單的頁面展現(xiàn),用以說明Portlet的開發(fā)過程。
一、創(chuàng)建Portlet工程
1、打開Liferay IDE,File-->New-->Liferay Project
2、為Portlet工程取名為Study,點(diǎn)擊完成。或者點(diǎn)擊下一步,默認(rèn)選擇Liferay MVC。
補(bǔ)充說明:
Portlet:這個是一般做Liferay開發(fā)選擇的項(xiàng)目,一般說Liferay插件工程,通常都是指的Portlet工程。他的結(jié)構(gòu)和內(nèi)容和普通的WEB工程區(qū)別不大。
Hook:Liferay的Hook是什么東西呢?這個單詞中文可以翻譯成鉤子。是用于重寫或覆蓋Liferay的一些默認(rèn)方法或頁面。為開發(fā)提供了一種在不直修改Liferay核心源碼的情況下修改Liferay核心功能的方法。
Ext:擴(kuò)展工程的開發(fā)方法是Liferay早期版本推薦的開發(fā)方法,在6.x版本之后對ext開發(fā)模式逐漸不再推薦,主要使用Portlet的開發(fā)方法。擴(kuò)展開發(fā)可以繼承Liferay的Portal的大部分接口方法,而Portlet里面可以使用的接口方法均是Services包里面暴露的API。但是和Liferay的核心工程耦合太大,當(dāng)Liferay的版本升級時對Ext工程的影響太大,基本需要重新修改。所以一般不推薦使用Ext模式。
Layout:布局模板,Liferay的布局是可以定制的,如一個頁面中是兩欄式還是三欄式,每個欄里面又有幾行等等,可以使用此模式進(jìn)行快速開發(fā)。
Theme:主題包。Liferay IDE提供的可以幫助開發(fā)人員、設(shè)計(jì)人員快速開發(fā)Liferay主題包的功能,通過此模式提供的向?qū)Чぞ叩?#xff0c;為主題包的開發(fā)大大的提供了便利。
Portlet部署
Liferay的開發(fā)大量依賴Ant(也可以使用maven),在Liferay的開過程中,編譯、代碼生成、打包、部署等都是基于Ant完成的。
1、Liferay 的IDE在Liferay的portlet開發(fā)模式下,ant面板默認(rèn)是可見的,如果找不到可以通過Window-->Show View-->Ant(如果沒有可以在other里面找到)
2、在ant頁板里面,點(diǎn)擊Add-buildfiles將Build.xml文件添加進(jìn)來。
3、點(diǎn)擊Study-portlet前面的小三角,在出現(xiàn)的下拉菜單里面,雙擊deploy,等待Liferay完成部署操作。
如果在此時出現(xiàn)如下錯誤:
Task cannot continue because ECJ is not installed.
ECJ was automatically installed. Please rerun your task.
原因是ECJ包沒有找到,ECJ是什么?ECJ, the Eclipse Compiler for Java, is an open source incremental compiler used by the Eclipse JDT. It is an option for Liferay builds and is in many cases faster than Javac or Jikes. The jar for ECJ is included in Liferay release 4.4.0 and later.http://www.liferay.com/community/wiki/-/wiki/Main/ECJ這是官方解釋。大概意思是ECJ是一個編譯優(yōu)化包,可以提升比Javac和JIKES更好的編譯速度。要想使編譯通過,有兩個兩個方法:
方法一:禁用ECJ。在Liferay的SDK下面找到build.Administrator.properties,此處中間的Administrator名稱不一定是這樣的,具體體系名稱是根據(jù)當(dāng)前系統(tǒng)的用戶名生成的。在里面添加如下內(nèi)容
javac.compiler=modern
#javac.compiler=org.eclipse.jdt.core.JDTCompilerAdapter
方法二:將ECJ的包添加到ant的路徑里面。ecj.jar包可以在Liferay的工程的源碼包\lib\development下面找到。將此包添加到ant的路徑里面。Windows-->preferences-->Ant-->Runtime,在右邊的Classpath-->Ant Home Entries(Default) -->Add External JARs,將ecj包添加進(jìn)來。
4、啟動Tomcat。此portlet工程會自動部署。
5、打開http://localhost:8080/,登錄系統(tǒng)。點(diǎn)擊左上角的添加-->更多-->示例,在這里面可以看到我們剛建立的study portlet,點(diǎn)擊添加,可以將此portlet添加到頁面上。
Portlet工程結(jié)構(gòu)
一個Portlet工程的大概結(jié)構(gòu)如下:
1、src:這里存儲Java相關(guān)文件包,后面會看到還有一個services包。
2、web.xml:此web.xml和普通的web工程的web.xml文件一樣。
3、build.xml,此文件為ant的構(gòu)建文件,一般不需要修改繼承自SDK。
4、Liferay-plugin-package.properties,此文件為包工程的元數(shù)據(jù)信息文件,一般開發(fā)不需要關(guān)注。
5、portlet.xml:portlet定義描述文件,這個文件是標(biāo)準(zhǔn)的portlet 2.0(JSR 268)規(guī)范的文件。在這里定義的信息為portlet的名稱、初始化參數(shù)、模式類型、portlet的相關(guān)信息、權(quán)限等。在此文件里面我們可以看到view-template對應(yīng)的的是/view.jsp,當(dāng)我們在Liferay里面添加此portlet后,看到的頁面內(nèi)容就是view.jsp里面的內(nèi)容。下面的security-rol-ref定義的是哪些角色擁有此portlet的權(quán)限。
6、Liferay-portlet.xml:此文件是liferay擴(kuò)展的portlet的內(nèi)容,portlet.xml文件里面是標(biāo)準(zhǔn)的Portlet內(nèi)容,所有的Portal容器的portlet.xml文件描述、結(jié)構(gòu)都是一樣的。但liferay基于自身平臺的需求,又添加了一個Liferay-portlet.xml來擴(kuò)展portlet的信息。在這里可以看到角色映射,以及Liferay的一些個性化信息,后面有需要的時候詳細(xì)說明。
7、liferay-display.xml:在上一個步驟里面我們在添加portlet的時候,看到study這個portlet是位于示例這個目錄下面的,此文件就是定義相關(guān)的portlet是放置在哪個目錄下面顯示的。
說明:
在Liferay里面,portlet的名稱一般不要重復(fù),portlet.xml,liferay-portlet.xml,lifray-display.xml這三個文件之間的關(guān)聯(lián)就是通過portlet 名稱做標(biāo)識進(jìn)行關(guān)聯(lián)。
Liferay 6.1開發(fā)學(xué)習(xí)(三):Portlet簡述
在上一篇文章里面介紹的那個Portlet是在創(chuàng)建工程時默認(rèn)創(chuàng)建的Portlet頁面,可以對Portlet有一個大概的認(rèn)識,但是很難全面。本篇文章對于Liferay中基于MVC的Portlet創(chuàng)建做一個相對詳細(xì)的描述。
一、Portlet是什么?
Portlet是基于java的web組件,由portlet容器管理,并由容器處理請求,生產(chǎn)動態(tài)內(nèi)容。Portals使用portlets作為可插拔用戶接口組件,提供信息系統(tǒng)的表示層。作為利用servlets進(jìn)行web應(yīng)用編程的下一步,portlets實(shí)現(xiàn)了web應(yīng)用的模塊化和用戶中心化。 portlet規(guī)范,即jsr(Java Standardization Request )168/268,是為了實(shí)現(xiàn)portal和portlet的互操作。它定義了portlet和portlet容器之間的和約,讓portlet實(shí)現(xiàn)個性化、表示和安全的api集。規(guī)范還定義了怎樣在portlets應(yīng)用中打包portlets。(引自百度百科:http://baike.baidu.com/view/58961.htm)
Liferay是portlet規(guī)范的實(shí)現(xiàn),對于portlet規(guī)范實(shí)現(xiàn)的主流產(chǎn)品還有IBM、Oracle等的Portal產(chǎn)品,主流產(chǎn)品的詳細(xì)可以參看:http://www.huqiwen.com/2012/06/11/what-is-liferay/?此篇文章中關(guān)于Liferay市場地位處的圖片。很以很多時候我們將Liferay稱為一個Portal容器,也就是一個提供Portlet運(yùn)行的環(huán)境。
二、創(chuàng)建一個Portlet
1、基于上一節(jié)的Study這個portlet工程的基礎(chǔ)。點(diǎn)擊Liferay IDE上的liferay工具欄,有三個按鈕,點(diǎn)擊中間按鈕,New Liferay Portlet。如下圖,點(diǎn)擊下一步。
Portlet plugin project:這里選擇要創(chuàng)建的portlet屬于哪個插件工程。
Source folder:類的放置位置,一般默認(rèn)。
Portlet Class:要創(chuàng)建的Portlet的控制類的名稱,可以將此類看作Struts中的Action類。
Java package:包名。
Superclass:選擇要繼承哪個類。一般默認(rèn),也就是MVCPortlet。下面這幾個類的關(guān)系如下:MVCPortlet是LiferayPortlet的子類,LiferayPortlet是GenericPortlet的子類。在MVCPortlet中封裝了一些方便開發(fā)的方法,所以一般使用MVCPortlet,如果有特殊需求可以使用他們的父類。
2、在此步驟看到的是Portlet的相關(guān)信息,如模式,JSP位置等,此步驟是portlet.xml文件的可視化編輯,此步驟的所有選項(xiàng)都可以通過編輯portlet.xml完成。點(diǎn)擊下一步。
Porltet Info:這里顯示的是Porltet的名稱,顯示名稱,標(biāo)題等。一般默認(rèn),不需要修改。
Portlet Modes:這里是portlet的模式,View、Edit、Help這三種模式,是portlet規(guī)范里面定義的。
Liferay Portlet Modes:看名知義,Liferay Portlet模式。一般默認(rèn)即可。Portlet默認(rèn)的三種模式,Liferay認(rèn)為不能滿足實(shí)際的需求,所以又新增了這幾種模式。如果選擇多個模式,就可以在portlet的設(shè)置里面看到,可以通過設(shè)置進(jìn)行切換,方便進(jìn)行一些特殊需求,如:config可以用來開發(fā)可配置Porltet,管理員可以為指定的Portlet定制相關(guān)的參數(shù)等。
JSP folder:JSP的存放位置,一般默認(rèn)的命名是html/porltet名稱,一般默認(rèn)即可。html是相對于docroot的,完整路徑是docroot/html/demo/view.jsp。
Create resource bundle file:綁定資源文件,主要是國際化。如果想要porltet的名稱是中文的,測必須使用資源文件,liferay推薦工程中的所有文字描述類的內(nèi)容都使用資源文件來定義,這樣方便國際化,也能避免出現(xiàn)一些可能的亂碼問題。這里先不選,后面詳講國際化。
3、此步驟是Liferay-portlet.xml和liferay-display.xml的可視化編輯。點(diǎn)擊完成即可。
Icon:此portlet的圖標(biāo)。
Allow mutiple instaces:是否允許在同一個頁面中有多個porltet的實(shí)例,默認(rèn)為否。
CSS:當(dāng)前porltet的自定義CSS。一般默認(rèn)。
JavaScript:當(dāng)前portlet自定義JS。一般默認(rèn)。
CSS classname:當(dāng)前portlet的命名空間,防止CSS和其他porltet沖突。
Category:當(dāng)前的portlet,顯示在哪個分類下面,這里是Liferay-display.xml文件的可視化編輯。
三、MVCPortlet的簡單使用
可以看到在工程的com.huqiwen.study包下面生成了一個Demo的java文件,如果只是讓portlet顯示/html/demo/view.jsp里面的內(nèi)容,則不需要在Demo.java文件里面添加內(nèi)容。如果需要讓view.jsp后從臺初始化一些信息,則需要重寫doView文法。view模式顯示時調(diào)用doView方法,edite模式顯示時調(diào)用doEdite方法,config模式顯示時調(diào)用doConfig方法,依此類推。
在此大部分情況下可以將renderRequest當(dāng)然HttpServletRequest使用。如果要轉(zhuǎn)換可以通過PortalUtil.getHttpServletResponse(portletResponse)來進(jìn)行轉(zhuǎn)換。
可以使用renderRequest.setAttribute(arg0, arg1)方法,在前臺頁面通過JSTL等進(jìn)行取值。
這里不詳述,和普通的WEB程序基本一樣。
四、其他
在二里面創(chuàng)建的內(nèi)容都可以通過修改portlet.xml,liferay-portlet.xml,liferay-display.xml等來進(jìn)行修改調(diào)整。創(chuàng)建向?qū)О闹皇且恍┳钔ㄓ玫膬?nèi)容,一些高級的參數(shù)還需要通過修改porltet.xml和liferay-portlet.xml來完成。
通過向?qū)J(rèn)porltet的view展現(xiàn)的JSP命名為view.jsp。此名稱可以在docroot下面修改成相應(yīng)的內(nèi)容,實(shí)際開發(fā)中建議命名中和業(yè)務(wù)相關(guān)的,方便后期查找識別,如用戶的可以命名成userView等,修改名稱的同時需要修改Porltet.xml里面init-param對應(yīng)的名稱,否則會出現(xiàn)找不到頁面的情況。
Liferay 6.1開發(fā)學(xué)習(xí)(四):Service Builder
一、什么是Service Builder?
Service Builder是Liferay IDE(SDK)提供的一種代碼生成方案,開發(fā)人員只需要編輯一個數(shù)據(jù)庫的實(shí)體描述文件,即可根據(jù)本XML文件生成Spring層代碼、Hibernate層代碼、SQL、SQL索引創(chuàng)建文件、Spring和hibernate的配置文件等,可以大提高開發(fā)人員的效率。簡單說就是根據(jù)數(shù)據(jù)庫描述文件,生成service層和持久化層的代碼,開發(fā)人員只需要關(guān)注控制層即可。
二、Service Builder的使用
1、首先需要有一個Portlet的插件工程,創(chuàng)建方法,參考http://www.huqiwen.com/2012/09/01/liferay-6-1-development-studey-2-create-portlet-project/
2、打開Liferay IDE,點(diǎn)擊工具欄中Liferay工具的中間按鈕,New Liferay Service Builder,彈出的向?qū)缦?#xff0c;填寫相關(guān)信息,點(diǎn)擊完成。
Plugin Project:將用于哪個工程,如果有多個工程,請看仔細(xì)。
Service file:數(shù)據(jù)庫描述文件的文件名,使用向?qū)Р豢筛?#xff08;可以手動改,后面詳述)
Package path:包名路徑,這里是定義基礎(chǔ)的包名路徑,建議一般規(guī)則為:公司域名+portlet+功能模塊名
Namespace:命名空間,如果沒有指定數(shù)據(jù)庫的表名,則會在前面添加上此命名空間。
Author:作者名,默認(rèn)讀取系統(tǒng)變量。
Include sample entiry in new file:在自動生成的xml文件中是否包含示例,如果是新手,建議打勾。
3、編輯service.xml文件。在liferay IDE里面提供了service的開視化編輯。簡單介紹一下主要屬性的含義。
Name:實(shí)例名稱,就是通常的JavaBean的名稱。
Local Service:本地服務(wù),一般選中。
Remote Service:遠(yuǎn)程服務(wù),用于為生成Web Service做支持,如果不需要不要選中。
Human Name:人性化名稱。一般留空即可,此處的名字用于生成文檔時使用,如果留空使用Name。
Table:數(shù)據(jù)庫名稱,如果不填寫,使用Name。
Uuid:是否生成一個uuid的字段,具體的根據(jù)數(shù)據(jù)庫設(shè)計(jì)情況而定。可以使用也可以不使用。推薦使用。
Uuid accessor:是否使用uuid存取實(shí)體,根據(jù)情況而定。可以使用也可以不使用。推薦使用。
Persistence Class:持久化類的名稱,推薦留空,讓自動生成。
Data source:數(shù)據(jù)源,一般留空。。
Session Factory:數(shù)據(jù)庫會話工廠,一般留空。
TX Manager:事務(wù)管理,一般留空。
Cache enabled:開啟緩存,推薦選中。
JSON enabled:開啟JSON,生成的代碼中包含實(shí)體的JSON序列化和反序列化,根據(jù)情況而定。如果不使用JSON,請不要勾選。
4、在Columns里面添加字段,填寫字段名稱,類型等。如果要使用特殊的數(shù)據(jù)庫名稱,或者字段有其他需求,請點(diǎn)開Columns,在下面逐個字段上修改。Db Name對應(yīng)的為數(shù)據(jù)庫的字段名稱,其他一般留空即可。
5、Order,查詢結(jié)果根據(jù)哪個字段排序列。
6、Finders:查詢方法。service builder默認(rèn)會生成基本的增刪改查方法,如果有一些根據(jù)字段查詢某些數(shù)據(jù),返回的可以是一個實(shí)體也可以是一個List。
<finder name="userId" return-type="user"><finder-column name="userId" /></finder>這個的意思是生成一個方法叫findyByUserId的方法,傳入的參數(shù)是userId,返回的類型是User。(這個例子只是為說明,一般如果userId是主鍵,service builder生成的方法里面,不寫此finder,已經(jīng)包含此方法)
finder-column這里可以填寫多個參數(shù),return-type,如果是Collection則返回類型是List。
Finders方法,可以根據(jù)實(shí)際情況進(jìn)行填寫,對于使用finders仍不能滿足的方法,后面詳解。
7、點(diǎn)擊ant里面servicer-builder按鈕,等待Liferay進(jìn)行代碼生成。或者將可視化編輯器切換到Diagram,點(diǎn)擊右鍵,service builder。
三、Service Builder生成代碼的使用。
如果是第一次使用Service Builder,請按如下步驟操作。
1、WEB-INF目錄下面找到service目錄,點(diǎn)擊右鍵Build Path-->Use as Source Folder。service包里面主要包括生成的代碼里面的接口方法,方便我們進(jìn)行跨工程的代碼調(diào)用。src里面都 實(shí)現(xiàn)包。
2、Service Builder的使用,一般有兩種方法。一種是獲取一個Service。
CmsArticleLocalService cmsArticleServie = CmsArticleLocalServiceUtil.getService();
然后使用此xxService調(diào)用相關(guān)方法
一種是直接使用xxLocalServiceUtil調(diào)用相關(guān)方法。大部分情況下使用xxLocalServiceUtil進(jìn)行方法調(diào)用。
3、創(chuàng)建一個modle實(shí)例一般使用如,xxLocalServiceUtil.createXX()方法。
四、自定義方法
雖然liferay自動生成的代碼里面包含了常用方法,足以應(yīng)付一般場景,但是有些特殊場景需要一些特殊的方法,如何添加自定義方法呢?
1、找到src下面和此service builder相關(guān)的的xxx.service.impl包,找到xxxLocalServiceImpl的文件,打開在此類里添加相關(guān)的自定義方法。
2、如果是要為modle添加自定義方法,請?jiān)趚xx.modle.impl包里面的,xxImpl文件里面添加自定義方法。
3、修改完成后,再次執(zhí)行Service Builder,會將這些方法自動的添加到其他相關(guān)接口、類里面。Liferay的Service Builder方法一般只允許修改上述兩個類,其他的類一般不要修改,因?yàn)樾薷暮笕绻俅螆?zhí)行service builder會被覆蓋掉。
五、修改字段長度
Liferay自動生成的代,如String字段,默認(rèn)長度是75。如果有特殊的需求,可以在src/META-INF/portlet-model-hints.xml里面修改相應(yīng)的字段映射長度。找到相應(yīng)的實(shí)體,字段,如下:
<field name="InfoId" type="String" ><hint name="max-length">300</hint></field>這樣就可以將InfoId的數(shù)據(jù)庫字段長度定義為300。修改完成重新執(zhí)行service-builder進(jìn)行文件生成。
六、其他技巧
1、一個service.xml文件里面可以有多個實(shí)體名。
2、如果要建立多個service.xml文件,可以在WEB-IN目錄下面建立一個文件夾,比如叫service-builder用來存儲service.xml文件,不同的service.xml執(zhí)行不同的命名,如User-Service.xml等。手動建立,不必使用向?qū)А?/p>
3、如果按照步驟2操作,有多個service.xml文件,則不能執(zhí)行ant里面的service-builder文件,因?yàn)閍nt只會尋找web-inf目錄下面的services.xml文件。所以要在xx-service.xml文件里面切換到Diagram編輯模式,點(diǎn)擊右鍵,build Service,這樣會對當(dāng)前XML文件進(jìn)行構(gòu)建。
4、即使使用了2、3的方法,也不要刪除web-inf目錄下面的service.xml文件,可以保留一份,不然最終部署后的web.xml描述文件里會少生成一些內(nèi)容,導(dǎo)致插件工程不能正常運(yùn)行。
5、同一個插件工程中,不同的xx-services.xml文件必須使用不同的包名,一個services.xml里面可以有多個實(shí)體,但不同的services.xml里面必須使用不同的包名,否則會導(dǎo)致生成的的spring配置文件出現(xiàn)覆蓋情況。
Liferay 6.1開發(fā)學(xué)習(xí)(五):編譯調(diào)試修改源碼
Liferay是一個開源的項(xiàng)目,開源項(xiàng)目的好處有兩個,一方面我們可以通過閱讀源碼提高水平,了解一些技術(shù)的實(shí)現(xiàn)原理,另一方面是如果開源的產(chǎn)品不能滿足我們的實(shí)際需求,可以通過修改源碼實(shí)現(xiàn)。Liferay CE版可以免費(fèi)獲取源碼,EE版需要購買過產(chǎn)品才能獲取源碼。
(以下文件雖然是基于Liferay 6.1.1所寫,但Liferay 6.2.0版本同樣適用,方法、過程、需要注意事項(xiàng)等均一致)
一、導(dǎo)入源碼
源碼可以從Liferay的官方網(wǎng)站上下載。http://www.liferay.com/downloads/liferay-portal/available-releases
下載后解壓源碼,可以使用Eclipse的File-->Import-->General-->Existing Projects in to Workspace。將解壓的源碼導(dǎo)入到Eclipse中。
導(dǎo)入源碼后,如果是6.1.1的源碼,可能會出現(xiàn)如下的錯誤:Project 'portal-trunk' is missing required source folder: 'portal-web/test'。此錯誤是說在build path下面找不到test目錄。解決方法有兩個(6.2.0中導(dǎo)入源碼后,也有類似問題,解決方法同下面兩個原理一樣):
1、在portal-web下面建立一個名為test的目錄。
2、打開源碼工程目錄下面的.classpath文件(使用文本編輯器打開,editplus或notepad++),在其中找到<classpathentry excluding="**/.svn/**|.svn/" kind="src" path="portal-web/test"/>(大概在11行),將此行注釋掉或刪除。然后回到Eclipse中刷新工程(選中工程按F5,或在右鍵菜單中選擇刷新)。
二、編譯源碼
既然要調(diào)試源碼,首先是需要能夠?qū)υ创a進(jìn)行編譯。Liferay的源碼不是一個普通的Web工程,不能使用普通的方法進(jìn)行編譯部署。但liferay官方已經(jīng)提供了相應(yīng)的ant腳本進(jìn)行編譯部署,但首先還需要一些簡單的設(shè)置。
1、打開liferay的源碼目錄,找到app.server.properties文件。
2、將些文件復(fù)制一份,重命名為app.server.{username}.properties的文件,其中的{username}為當(dāng)前系統(tǒng)的帳號名稱。如我的系統(tǒng)帳號是huqiwen,則將其命名為app.server.huqiwen.properties即可。具體的可以打開CMD,以里面顯示用戶名為準(zhǔn)。如下圖:
3、打開此文件,找到app.server.parent.dir=${project.dir}/../bundles。將后面的${project.dir}/../bundles替換為下載的綁定Liferay的Tomcat的路徑,如我的為E:/code/liferay6.1/liferay-portal-6.1.1-ce-ga2,則修改后的地址為:?app.server.parent.dir=E:/code/liferay6.1/liferay-portal-6.1.1-ce-ga2。注意:從地址欄里面復(fù)制的地址為正斜杠,請修改成反斜杠。
4、現(xiàn)在Eclipse的ant面板里面點(diǎn)擊,add buildfiles,將portal源碼里面的build.xml文件添加到ant面板里面。
5、點(diǎn)開此build文件,先點(diǎn)擊compile,再點(diǎn)擊deploy,即可將源碼編譯部署到tomcat中。
三、debug源碼
在二的基礎(chǔ)上deploy后,即可對liferay的相關(guān)源碼進(jìn)行編譯調(diào)試。如果是第一次進(jìn)行debug,可能會跳轉(zhuǎn)到顯示Source not found,此時,點(diǎn)擊下面的“edit source lookup path”,在彈出的對話框里面點(diǎn)擊Add -->Java Project,在這里將我們的Portal-trunk工程勾選上,點(diǎn)擊OK等,即可開始Liferay的源碼調(diào)試。
四、常見問題
1、在編譯的時候出現(xiàn)如下錯誤
Task cannot continue because ECJ is not installed.
ECJ was automatically installed. Please rerun your task.
這個問題在前面的博客里面提到過,http://www.huqiwen.com/2012/09/01/liferay-6-1-development-study-2-create-portlet-project/
解決方法為:
原因是ECJ包沒有找到,ECJ是什么?ECJ, the Eclipse Compiler for Java, is an open source incremental compiler used by the Eclipse JDT. It is an option for Liferay builds and is in many cases faster than Javac or Jikes. The jar for ECJ is included in Liferay release 4.4.0 and later.http://www.liferay.com/community/wiki/-/wiki/Main/ECJ這是官方解釋。大概意思是ECJ是一個編譯優(yōu)化包,可以提升比Javac和JIKES更好的編譯速度。要想使編譯通過,有兩個兩個方法:
方法一:禁用ECJ。在Liferay的SDK下面找到build.Administrator.properties,此處中間的Administrator名稱不一定是這樣的,具體體系名稱是根據(jù)當(dāng)前系統(tǒng)的用戶名生成的。在里面添加如下內(nèi)容
javac.compiler=modern
#javac.compiler=org.eclipse.jdt.core.JDTCompilerAdapter
方法二:將ECJ的包添加到ant的路徑里面。ecj.jar包可以在Liferay的工程的源碼包\lib\development下面找到。將此包添加到ant的路徑里面。Windows-->preferences-->Ant-->Runtime,在右邊的Classpath-->Ant Home Entries(Default) -->Add External JARs,將ecj包添加進(jìn)來。
2、在編譯源碼的時候出現(xiàn):
Please set the environment variable ANT_OPTS to the recommended value of
"-Xmx1024m -XX:MaxPermSize=512m".
這個提示的意思是說當(dāng)前的JVM參數(shù)設(shè)置的太小了,不夠liferay編譯使用,需要增加JVM內(nèi)存的分配,并建議將Xmx參數(shù)設(shè)置成1024m,MaxPermSize設(shè)置成512m。這是因?yàn)閘iferay的源碼比較大,內(nèi)容比較多,使用了大量的classloader等,需要比較大的內(nèi)存。
解決方法上面已經(jīng)給出提示了將環(huán)境變量(其實(shí)就是JVM的參數(shù))推薦設(shè)置成上面的提示。
1)在Liferay工程的源碼里面的build.xml上點(diǎn)擊右鍵-->Run as-->External Tool Configurations
2)在tab標(biāo)簽里面找到Environment,點(diǎn)擊new,在name里面輸入ANT_OPTS,在value里面輸入-Xmx1024m -XX:MaxPermSize=512m,然后點(diǎn)擊apply。
3)再次運(yùn)行ant的編譯,即可正常編譯。
3、如果出現(xiàn)類似如下錯誤,請參考上文的“二、編譯源碼”
Tomcat is not installed in E:/liferay/6.2/bundles/tomcat-7.0.42. If you already have Tomcat
installed, make sure the property "${app.server.tomcat.dir}" points to your
Tomcat installation. If you wish to automatically install Tomcat into
Liferay 6.1開發(fā)學(xué)習(xí)(六):國際化
Liferay的開發(fā)不建議直接在代碼中使用中文等內(nèi)容,建議使用國際化的方式,從資源文件中讀取語言等信息,Liferay在平臺對封裝了許多操作資源文件的類,我們只需要按照此規(guī)則既可方便的實(shí)現(xiàn)國際化。
一、Portlet屬性的國際化
在前面創(chuàng)建的Portlet的時候,portlet的名稱等都是英文的,在添加portlet的時候,顯示的也是英文的,如何將這些信息顯示成中文呢?如將下面Study顯示成中文。
1、檢查portelt.xml的XML文件中的此portlet的信息,是否包含下面的代碼,這個是關(guān)鍵,如果沒有手動的添加到portlet-info標(biāo)簽的上面。如查在portlet的創(chuàng)建向?qū)Ю锩婀催x了“Create resource bundle file”,則會自動生成。
<resource-bundle>content/Language</resource-bundle>
2、工程的src目錄下面找到content包,如果沒有則創(chuàng)建,如果有則打開。在里面新建Language_zh_CN.properties文件,我們的portlet中文信息寫在此文件里面。
3、在此文件中寫入“javax.portlet.title=此處寫相應(yīng)的標(biāo)題文字”,可以直接寫中文,eclipse的properties編輯器,會自動的轉(zhuǎn)換成unicode代碼。一般我們只寫title就可以,如果有特別需求,可以加上javax.portlet.keywords,javax.portlet.short-title等信息。
4、現(xiàn)在重新打包部署此工程,再次添加portlet,即可看到portlet的名稱變成了中文。
注意:<resource-bundle>content/Language</resource-bundle>這里的內(nèi)容定義了,我們存放語言文件的目錄在content目錄下面的Language文件,這里也可以定義成自己喜歡的,只要按照此規(guī)則即可。
二、內(nèi)容的國際化
上面的國際化是portlet屬性信息的國際化,如果是我們想在代碼中使用這些國際化信息呢?比如提示語、按鈕名稱等等。這個地方的方法就和普通的java代碼的國際化一樣,在上面的語言文件中寫入相應(yīng)的key,在代碼中讀取即可。
1、如我們要將“參數(shù)名稱”這個詞國際化,則在Language_zh_CN.properties中寫入:
propertyName=\u53c2\u6570\u540d\u79f0
后面的是參數(shù)名稱的unicode碼,我們在編輯器中直接寫入中文,編輯器會自動轉(zhuǎn)換,如果不能轉(zhuǎn)換可以使用JDK的命令如:
native2ascii -encoding UTF-8 Language_zh_CN.properties.native Language_zh_CN.properties
進(jìn)行中文編碼的轉(zhuǎn)換。
2、在代碼中調(diào)用:
JSP中:LanguageUtil.get(pageContext,"propertyName")
JAVA代碼中:LanguageUtil.get(portletRequest.getLocale(), "propertyName")。其中的第一個參數(shù)為Local,也可以使用Locale.CHINESE
三、Liferay Portlet屬性國際化的修改
在一中提到的portlet屬性的國際化存在一個問題,也就是我們一個語言文件中只能定義一個portlet的屬性信息,如果我們在一個插件工程中需要國際化多個portlet的屬性信息怎么辦?在Liferay的官方論壇、Wiki里面也有不少人討論此問題,但Liferay的解釋就是不支持!在一個資源文件里面只能寫一個portlet的屬性信息。
個人覺得這一點(diǎn)非常不好,如我的一個插件工程中有十幾個portlet,那么難道需要定義十幾個語言資源文件或者拆分成十幾個Portlet?如果支持下面這樣:
javax.portlet.title.MyPortletTitle = My Portlet Title
如果是這樣的才是很合理的,Liferay平臺里面的Portlet的信息就是這樣的形式國際化的,但是插件里面不支持。Liferay平臺本身是使用的Strtus resource bundle,所以和我們的不太一樣。
既然官方不支持,我們就自己動手改造了,好在Liferay是開源的,我們修改他的源碼自己實(shí)現(xiàn)就可以了。
方法如下:
1、參考上一篇文章,http://www.huqiwen.com/2012/09/21/liferay-6-1-development-study-5-compile-debug-deploy/,如果編譯部署關(guān)聯(lián)Liferay的源碼
2、在源碼里面找到PortletResourceBundle.java這個類(小提示:可以在eclipse中使用快捷鍵ctrl+shift+r來快速定位此文件)。找到其中的handleGetObject方法,修改成如下,下面有注釋,顯示了哪里修改的:
@Overrideprotected Object handleGetObject(String key) {if (key == null) {throw new NullPointerException();} String value = null;if (parent != null) {try {value = parent.getString(key);}catch (MissingResourceException mre) {//hqw 2012.09.09 add beginString titlekey = key.concat(StringPool.PERIOD).concat(_portletInfo.getTitle());if (Validator.isNotNull(titlekey)) {titlekey = titlekey.toLowerCase();}try {value = parent.getString(titlekey);} catch (MissingResourceException mre2) {}//end}} if ((value == null) || (value == ResourceBundleUtil.NULL_VALUE)) {value = _getJavaxPortletString(key);} if ((value == null) && ResourceBundleThreadLocal.isReplace()) {value = ResourceBundleUtil.NULL_VALUE;} return value;}在我debug時,發(fā)現(xiàn)liferay只是通過javax.portlet.tiltle這個key值尋找,那我們在給他加上具體的title值就可以了。現(xiàn)在修改后的不但兼容他原來的,而且又支持javax.portlet.title.MyPortletTitle = My Portlet Title。這樣的多好
3、現(xiàn)在使用ant進(jìn)行deploy源碼,再次啟動tomcat就發(fā)現(xiàn),現(xiàn)在的國際化已經(jīng)支持我們需要的形式了。
Liferay 6.1開發(fā)學(xué)習(xí)(七):Layout布局模板開發(fā)
Liferay提供了layout功能,可以方便的自由布局,用戶或者管理員可以根據(jù)選用的布局模板對頁面進(jìn)行自由布局。Liferay默認(rèn)中提供了幾種常用的layout模板,如單欄目、雙欄目(20%/80%,30%/70%)等幾種常用的,但是這些布局模板并不能滿足我們實(shí)際的需求,一些復(fù)雜的布局需要自己開發(fā)。
LayoutTPL開發(fā)
布局模板是一個tpl文件,本身結(jié)構(gòu)非常簡單。基于Liferay IDE可以進(jìn)行可視化的、拖動的形式進(jìn)行布局TPL的開發(fā)。方法如下 :
1、在Eclipse的工具條上,點(diǎn)擊New Liferay Project,在plugin type里面選擇Layout,點(diǎn)擊finish。則完成了Layouttpl工程的建立。
2、工程里面對于開發(fā)有用的文件主要有四個:
*.tpl:這個文件是定義PC訪問時布局模板的文件。
*.wap.tpl:定義手機(jī)訪問時的而已模板文件。
*.png:這個圖片是用于顯示布局模板的縮略圖,方便在選擇模板的時候預(yù)覽此模板的樣式。
liferay-layout-templates.xml:此文件位于WEB-INF目錄下面,用于定義此布局模板的元數(shù)據(jù)信息。
3、通常情況下,我們只需要編輯*.tpl文件即可。如下圖,為我拖出來的一個TPL文件。
4、可以通過鼠標(biāo)可視化的形式,添加column(列)、row(行)等,通過控制點(diǎn)來顯示列寬的百分比等。
布局模板的發(fā)布
主題創(chuàng)建修改完成后,點(diǎn)擊ant中的deploy進(jìn)行發(fā)布即可。
其他說明:
layoutTPL的開發(fā)非常簡單。通過Liferay IDE通夠?qū)崿F(xiàn)快速開發(fā)。有一些小技巧
1、可以在一個TPL工程里面建立多個布局模板,只需要在liferay-layout-templates.xml里面對這些文件進(jìn)行定義描述即可。
2、如果在拖動中不能拖出自己想要的寬度百分比,可以進(jìn)行source模式,手動的修改這些百分比,為 aui-w24,w后面的數(shù)值即是百分比。
3、如果不需要進(jìn)行移動訪問,*.wap.tpl的內(nèi)容可以不用管。
4、建議添加*.png這個縮略多,方便在添加切換的時候預(yù)覽。
Liferay 6.1開發(fā)學(xué)習(xí)(八):主題開發(fā)
Liferay可以為不同的頁面、社區(qū)、組織等提供不同的主題。方便實(shí)現(xiàn)用戶的個性化配置,同時Liferay提供的IDE方便開發(fā)人員進(jìn)行主題的個性化開發(fā)。
Liferay主題的創(chuàng)建
1、在Eclipse的工具條上,點(diǎn)擊New Liferay Project,在plugin type里面選擇Theme,點(diǎn)擊finish。則完成了theme工程的建立。
2、Liferay的主題開發(fā)是在他提供的一個模板的基礎(chǔ)上進(jìn)行修改。我們將個性化的內(nèi)容放置于_diffs目錄下面,在deploy的時候,liferay會自動的將此文件的內(nèi)容合并到主題中,并覆蓋原先相應(yīng)的內(nèi)容。如果沒有覆蓋的則采用默認(rèn)的樣式等。
3、liferay的主題主要有四部分組成,CSS、images、js、template。這幾部分中前三部分,不需要特別說明。template里面是使用Velocity編寫的模板,方便我們修改他相應(yīng)的模板內(nèi)容。
4、依次說明:
CSS
CSS里面的文件是分類的,如forms.css里面是定義的表單相關(guān)的,navigation.css里面是定義的導(dǎo)航相關(guān)的,layout.css是定義的布局相關(guān)的等等。比如我們需要修改導(dǎo)航的樣式,則在_diffs目錄下面建立css目錄,并將上面的navigation.css復(fù)制到_diffs/css/下面。我們在此文件上修改,liferay IDE會自動的編譯覆蓋原先的內(nèi)容。
如果我們需要定義的CSS內(nèi)容,不是liferay本身提供的,而是我們自己新建立的樣式,則推薦將此樣式寫在_diffs/css/custom.css里面。
JS
js的內(nèi)容一般不做修改,也沒有必要在主題包里面定義太多的JS相關(guān)的內(nèi)容。
images
將和自己編輯的主題相關(guān)的圖片存于images目錄下面。如果需要在代碼中引用,可以使用
String imgpath = themeDisplay.getPathThemeImages();
這里取到的imgpath,即為images目錄。
templates
模板文件,用于定義常用的portlet、導(dǎo)航、通用的等模板文件。可以根據(jù)自己的實(shí)際需求進(jìn)行修改。和普通的Velocity一樣,如果對于Velocity不熟悉的,可以大概了解一下,使用起來和普通的HTML沒有太大的區(qū)別。
主題的發(fā)布
主題創(chuàng)建修改完成后,點(diǎn)擊ant中的deploy進(jìn)行發(fā)布即可。
其他說明
在_diffs目錄里面只需要復(fù)制自己要修改的內(nèi)容,不需要修改的則不需要復(fù)制過來,如下圖:
1、我需要修改layout.css,則只需要從上級的CSS目錄里面將此文件復(fù)制過來,在此文件上進(jìn)行修改。不需要修改navigation.css則不用復(fù)制。其他的也類似。
2、圖片,我需要將自定義的圖片保存到common目錄下面,則需要要創(chuàng)建一個comon目錄,在引下面存放自己的文件即可。
3、tumbnail.png文件是存放的主題的縮略圖,方便在切換主題時預(yù)覽。
Liferay 6.1開發(fā)學(xué)習(xí)(九):Hook開發(fā)簡介
一、Hook是什么
hook是什么在http://www.huqiwen.com/2012/09/01/liferay-6-1-development-study-2-create-portlet-project/里面有一個大概的介紹。Liferay提供hook的目的是減少二次開發(fā)的代碼與liferay核心工程的耦合,通過hook我們主要可以主要做以下六件事情:
1、覆蓋事件處理程序:如程序啟動事件(application.startup.events)、登錄注銷事件(login.events.pre、login.events.post)、session的創(chuàng)建銷毀事件等。
2、語言包:比如對liferay的某些翻譯不滿意,需要自定義,則可以使用hook覆蓋liferay的語言包。
3、liferay工程的portlet JSP內(nèi)容:比如想在頂部的top_bar里面添加內(nèi)容、想修改liferay的用戶編輯界面、想修改用戶登錄界面等等。
4、覆蓋portal.properties里面的屬性配置:可以在hook工程里面覆蓋一些liferay的portal.properties里面屬性配置,但是請注意,在hook工程里面只能覆蓋部分的屬性設(shè)置。不能覆蓋的如果需要可以在root/WEB-INF/classes里面添加portal-ext.properties,這個同可以覆蓋所有的。
5、覆蓋liferay的services里面的方法,如UserLocalService、GroupLocalService、OrganizationLocalService等等。
6、Liferay的Model監(jiān)聽程序,比如user、group、blog等的創(chuàng)建、更新、查看;插件的部署;集群的消息傳遞等等監(jiān)聽程序。
二、使用Liferay IDE進(jìn)行hook開發(fā)
1、在liferay IDE中,New Liferay Project-->選擇hook-->輸入project Name,點(diǎn)擊完成,即可創(chuàng)建一個hook工程。
2、在IDE的工具條中,選擇New Liferay hook,選擇我們要創(chuàng)建的hook類型,如下圖:
custom JSp:為自定義的JSP文件
portal properties:覆蓋portal屬性
Services:這個可以可以做兩件事情一是覆蓋事件處理程序;二是覆蓋service類
Lanuage properties:這個覆蓋或者新增國際化的語言文件。
3、以Custom JSPs為例,點(diǎn)擊下一步,如下圖
盡量的使用 Add from Liferay。這樣我們可以在彈出的界面中選擇相應(yīng)的我們要覆蓋的JSP路徑。點(diǎn)擊完成。
4、現(xiàn)在demo-hook工程目錄下的docroot/custom_jsps下面將出現(xiàn)我們上面選擇的路徑的JSP文件,此文件下的JSP路徑一定要和Liferay root下的待覆蓋的JSP路徑相符。現(xiàn)在就可以編輯此JSP來覆蓋我們想覆蓋的內(nèi)容,打開此JSP可以看到這里面的內(nèi)容和portal下面的JSP內(nèi)容完全一樣,修改想修改的部,點(diǎn)擊ant的deploy即可發(fā)布。
5、對于示例中的top_js.jspf文件,可以做什么呢?top_js.jspf此文件是portal的頭部JS的加載程序。比如我要在我的portlet工程里面引用jQuery庫,則可以在top_js.jsp里面將jQuery的庫引進(jìn)來,這樣在portlet的工程里面不用每個頁面都需要引用jQuery,可以避免一個頁面中多個portlet引用jQuery引起的沖突。引用方法如下
在top_js.jspf的最后部分添加:
<script type="text/javascript" src="/html/js/jquery-1.8.0.min.js"></script>
同時,在custom_jsps/html下面建立js目錄,并將jquery-1.8.0.min.js庫復(fù)制到此目錄下面即可。
6、對于portal.properties的覆蓋和語言包的覆蓋類似。Services的覆蓋略有不同,在下一篇文章里面詳述。
Liferay 6.1開發(fā)學(xué)習(xí)(十):在Liferay中使用Ajax
在現(xiàn)在的Web開發(fā)中,Ajax的使用非常頻繁,合理的使用Ajax也是提高用戶體驗(yàn)的一個重要手段,在Liferay中使用Ajax其實(shí)非常方便,但是和普通的web程序稍有差異。
一、簡單示例
客戶端代碼編寫
1、在Liferay中創(chuàng)建一個簡單的Portlet頁面,可以取名為ajaxPortlet,具體的創(chuàng)建過程可以參考;http://www.huqiwen.com/2012/09/03/liferay-6-1-development-study-3-portlet-explicate/
2、在liferay中ajax的請求地址要使用portlet:resourceURL,a這樣定義:<portlet:resourceURL var="ajaxUrl"/>,而不是普通請求的portlet:actionURL。
3、編輯view.jsp頁面,在頁面中添加<portlet:resourceURL var="ajaxUrl"/>,引入Jquery的包(使用jquery做ajax請求),然后編寫一個簡單的ajax請求代碼。
function ajaxTest(){$.post('<%=ajaxUrl%>',{p_p_resource_id:'test1'},function(data){$('#message').html(data);})}這個代碼的意思就是請求一下服務(wù)端,然后將得到的結(jié)果顯示到id為message的html元素中。
4、這樣客戶端的代碼就是編寫完成。具體的詳細(xì)代碼參看下面中的附件。
服務(wù)端代碼編寫
1、在portlet的控制類中重寫serveResource方法。
2、在此方法中添加相應(yīng)的處理類,此處的處理方法和普通的servlet一樣,可以使用下面的代碼。
@Overridepublic void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException {response.setContentType("text/html;charset=UTF-8");PrintWriter out = null;try {out = response.getWriter();} catch (IOException e) {e.printStackTrace();}String result = "這是服務(wù)端返回的結(jié)果信息:";out.println(result);out.flush();out.close();super.serveResource(resourceRequest, resourceResponse);}可以看到其實(shí)和普通的servlet處理基本上是一模一樣。
二、多ajax請求
上面的示例雖然簡單,但仔細(xì)一想就會發(fā)現(xiàn)有一個問題,如果在一個頁面中有多個ajax請求怎么辦?我們要依靠一個resourceID來區(qū)分不同的請求,同樣也是分客戶端和服務(wù)端。
客戶端
方法1:在resourceURL里面添加一個屬性id,如<portlet:resourceURL var="ajaxUrl2" id="test2"/>
方法2:在rsourceURL里面添加一個參數(shù),如:
<portlet:resourceURL var="ajaxUrl1"><portlet:param name="p_p_resource_id" value="test1"/> </portlet:resourceURL>方法3:在ajax請求時添加相應(yīng)的參數(shù),如:
function ajaxTest(){$.post('<%=ajaxUrl1%>',{p_p_resource_id:'test1'},function(data){$('#message').html(data);})}方法4:直接在URL里面拼接
服務(wù)端
服務(wù)端的處理只有一個,取得此resourceID,方法為String resourceID = resourceRequest.getResourceID();然后根據(jù)不同的resourceID判斷處理不同的ajax請求。返回和一般的處理一樣。
其他
在處理返回結(jié)果時,如果不想使用普通的servlet的處理方式,可以使用liferay的ServletResponseUtil.sendFile()方法,此方法主要是用來處理文件的,但用于處理ajax的請求也非常方便。
demo代碼下載:點(diǎn)擊此處下載
Liferay 6.1開發(fā)學(xué)習(xí)(十一):調(diào)度器-定時任務(wù)
在liferay的開發(fā)中經(jīng)常需要執(zhí)行一些定時調(diào)度任務(wù),一般情況下在普通的web開發(fā)中我們使用quartz來做調(diào)度,但是在Liferay中已經(jīng)對于調(diào)度做了一個封裝,方便我們在開發(fā)中執(zhí)行調(diào)度任務(wù),liferay中封裝了兩種方法方便我們做調(diào)度擴(kuò)展。
一、基于Portlet的調(diào)度
如某個的調(diào)度是在某個portlet中使用的,則可以使用一面的方法:
1、? 編寫一個類,實(shí)現(xiàn)接口:com.liferay.portal.kernel.messageing.MessageListener。如下圖所示。其中的doReceive()方法是定時執(zhí)行的內(nèi)容。
2、? 在liferay-portlet.xml里面注冊這個調(diào)度類,添加如下代碼:
<scheduler-entry> <scheduler-event-listener-class> xxx.cmsnewsgather.NewsGatherMessageListener(上面此類的全路徑) </scheduler-event-listener-class><trigger><simple><simple-trigger-value>15</simple-trigger-value><time-unit>minute</time-unit></simple></trigger> </scheduler-entry>scheduler-event-listener-class:里面的類為第一步里面編寫的類
simple-trigger-value:里面為調(diào)度周期的數(shù)值,time-unit為調(diào)度周期的單位。上面的意思為每15分鐘執(zhí)行一次。此時間也可以從配置文件中讀取。則將此標(biāo)簽完成<property-key>newsgather.gather.time</property-key>,其中的newsgather.gather.time為屬性文件(portal.properties)里面配置的值
Time-unit:表示周期的周期可以為:day、hour、minute、second、week這幾個單位。
3、? 上面的代碼即完成了一個調(diào)度器的開始,內(nèi)容為每15分鐘執(zhí)行一次第一步類里面的doReceive()方法。
二、基于servlet的調(diào)度
注:此方法適用于lifery6.0.6,不適用于liferay6.1.x
1、同上,編寫一個實(shí)現(xiàn)com.liferay.portal.kernel.messageing.MessageListener的類。
2、在相應(yīng)工程下面的web.xml里面添加servlet的注冊信息,如下:
<servlet><servlet-name>Lucene Servlet</servlet-name>?????? <servlet-class> xx.xx.servlet.xxxServlet </servlet-class><load-on-startup>2</load-on-startup> </servlet>3、在上面的servlet的init(ServletConfig servletConfig)方法里面添加如下內(nèi)容:
super.init(servletConfig); SchedulerEntry schedulerEntry = new SchedulerEntryImpl();?schedulerEntry.setEventListenerClass(xxxMessageListener.class.getName());schedulerEntry.setTimeUnit(TimeUnit.MINUTE);schedulerEntry.setTriggerType(TriggerType.SIMPLE);schedulerEntry.setTriggerValue(15);?try { SchedulerEngineUtil.schedule( schedulerEntry, PortalClassLoaderUtil.getClassLoader()); }其中的xxxMessageListener為第一步編寫的類。分別在setTimeUnit和setTriggerValue里面設(shè)置調(diào)度的周期單位和時間。
三、兩者的區(qū)別及適用情況
對于方法一是推薦使用的,但是有時候我們可能需要在程序中來設(shè)置調(diào)度周期,但是方法一需要在liferay-portlet.xml里面將調(diào)度的周期和時間就固定了。我們需要做一下變通,如在新聞采集的自動采集的代碼里面就使用的方法一,在liferay工程中的日程管理也是使用了此功能。此方法適用于下面情況
- 需要在程序中設(shè)置調(diào)度周期
- 但是對于時間的精確度需求不是非常高,可以有一定的誤差
如新聞采集的自動采集,如果我們需要對一個網(wǎng)站進(jìn)行新聞的自動采集,我們一般將這個周期設(shè)置成幾個小時重復(fù)執(zhí)行一次,我們可以在liferay-portlet.xml里面設(shè)置成這個調(diào)度是10分鐘或者30分鐘執(zhí)行一次檢查,這個時候我們在doReceive()里面調(diào)用的代碼不是具體的執(zhí)行采集的代碼,而是檢查現(xiàn)在的這個時間是否在下調(diào)度周期中,如果是則執(zhí)行采集,如果不是則跳過。
對于方法二而言,適用于以下情況:
- 需要執(zhí)行調(diào)度的代碼不明確屬于某一個portlet。
- 需要精確控制時間。
只要滿足上面的任何一個條件,都適合使用方法二,方法二里面的調(diào)度時間可以從數(shù)據(jù)庫中讀取也可以從配置文件中讀取。
Liferay 6.1開發(fā)學(xué)習(xí)(十二):文件上傳處理
Liferay中提供了完善的文件處理,從liferay 6.1開始在文件的處理方面,不再區(qū)分文檔和圖片,統(tǒng)一為文件媒體庫。在普通的portlet插件工程中,如果想將文件上傳到Liferay的文檔庫中,大的階段可以分為兩個流程:一、在portlet中將上傳的文件取到,二調(diào)用Liferay的API將文件上傳到文檔庫中。
(注:這里的文件上傳只講服務(wù)端的處理,至于客戶端也就是瀏覽器使用普通的表單文件上傳,還是使用swffileupload或者ajax提交等與服務(wù)端沒有關(guān)系,處理方法都是一樣的)
一、在portlet中取到上傳的文件
這兩的獲取有兩種方法,一種是普通的fileupload的處理方法,一種是使用liferay的API
1、使用fileupload的處理方法:
此種方法的獲取和在普通的servlet里面使用fileupload的方法一樣,核心代碼如下 :
DiskFileItemFactory factory = new DiskFileItemFactory();//PortletFileUpload upload = new PortletFileUpload(factory); ServletFileUpload upload = new ServletFileUpload(factory);upload.setSizeMax(1024 * 1024 * 200);HttpServletRequest servletRequest = PortalUtil.getHttpServletRequest(request);List<FileItem> items = upload.parseRequest(servletRequest);注:也可以使用此行代碼,如果使用了此行則下面的HttpServletRequest servletRequest = PortalUtil.getHttpServletRequest(request)就可以不要,在upload.parseRequest里面?zhèn)鱝ctionRequest。但是此方法在weblogic環(huán)境下面會出錯,所以如果要在weblogic下面運(yùn)行,請使用下面的servletFileUpload。
其他代碼就和在普通的Servlet里面使用fileupload一樣,這里不再多寫。
2、使用Liferay的API獲取上傳文件
推薦使用下面的代碼進(jìn)行文件上傳。
UploadPortletRequest uploadPortletRequest = PortalUtil.getUploadPortletRequest(actionRequest);String sourceFileName = uploadPortletRequest.getFileName("file");String contentType = uploadPortletRequest.getContentType("file");long size = uploadPortletRequest.getSize("file"); // File file = uploadPortletRequest.getFile("file");InputStream is = uploadPortletRequest.getFileAsStream("file");注:其中的getFileName中的file為<input type="file" name="file">中的name值,具體的可以要看自己的調(diào)整。
二、將獲取到的文件上傳到Liferay的文檔庫
1、上傳文件
在portlet中獲取到我們上傳的文件,只算是完成了第一步。取到了上傳的文件,怎么傳到Liferay的文件庫中呢?使用如下的接口
DLAppLocalServiceUtil.addFileEntry(long userId, long repositoryId, long folderId,java.lang.String sourceFileName, java.lang.String mimeType,java.lang.String title, java.lang.String description,java.lang.String changeLog, byte[] bytes,com.liferay.portal.service.ServiceContext serviceContext)
此接口的參數(shù)逐個說明:
long userId:上傳此文件的用戶id
long repositoryId:倉庫存儲ID,此ID一般為groupid
long folderId:文件夾ID,可以自己創(chuàng)建,或使用liferay默認(rèn)的如:DLFileEntryTypeConstants.FILE_ENTRY_TYPE_ID_BASIC_DOCUMENT等,最好是自己根據(jù)上傳資源的情況分類,如新聞的存到新聞文件,博客的存成博客文件等
String sourceFileName:上傳文件的源文件名
String mimeType:算是文件類型,可以使用mimeType = MimeTypesUtil.getContentType(fileName);根據(jù)文件名獲取。
String title:文件標(biāo)題,這個與SourceFileName的區(qū)別在于,此title是最終顯示在系統(tǒng)上的,可以由用戶輸入,源文件名稱是上傳獲取的文件名稱,不能手動改變。可以留空。
String description:關(guān)于此文件的描述,可以留空。
String changeLog:文件修改日志,可以留空。
byte[] bytes:文件的正文件,字節(jié)數(shù)組。
ServiceContext serviceContext:此類可以通過以下代碼
ServiceContext serviceContext = ServiceContextFactory.getInstance(DLFileEntry.class.getName(), request);
獲取。此對象里面包含了一些環(huán)境信息,如groupid,companyid,權(quán)限,門戶路徑,當(dāng)前語言,userId等信息。
在實(shí)際應(yīng)用中可以自己將上面的這個接口再做一層封裝,作為一個公共的文件上傳接口,以供其他需要文件上傳的地方調(diào)用,具體的請自行封裝,這里就不再帖我封裝的代碼。
2、獲取文件路徑
上面的文件上傳之后返回的是一個FileEntry的對象,如果獲取到上傳的文件的路徑呢,方法如下,可以定義一個方法,用來返回文件路徑,此方法對圖片、各式文件都是有效。
public static String getFilePath(FileEntry fileEntry) {if (null!=fileEntry) {return "/documents/" + fileEntry.getRepositoryId() + "/" + fileEntry.getFolderId() + "/"+ HttpUtil.encodeURL(HtmlUtil.unescape(fileEntry.getTitle()), true) + "/" + fileEntry.getUuid();}else {//如有需要,此處可以定義一個默認(rèn)圖片return StringPool.BLANK;}或者下面的這個方法,下面的這個更簡便一些
public static String getFilePath(FileEntry fileEntry) {if (null!=fileEntry) {return "/documents/" + fileEntry.getRepositoryId() + "/" + fileEntry.getUuid();}else {//如有需要,此處可以定義一個默認(rèn)圖片return StringPool.BLANK;}有時候如果文件是一個圖片,上傳的圖片可以很大,如何獲取一個縮略圖呢?如下:
public static String getSmallImagePath(FileEntry fileEntry){String path = getFilePath(fileEntry);
return path+"?imageThumbnail=1";
}
Liferay 6.1開發(fā)學(xué)習(xí)(十三):彈出層/彈出對話框的使用
在日常的開發(fā)中,為了提高用戶體驗(yàn),經(jīng)常會使用彈出層或者彈出框。在Liferay中可以使用AUI的標(biāo)簽及封裝的JavaScript代碼方便的達(dá)到這一目的。針對彈出內(nèi)容的不同,彈出對話框大體上可以分為三種形式,彈出div層、彈出普通的HTML頁或JSP頁面、彈出portlet。
一、彈出div層
有幾種寫法,本質(zhì)上是一樣的,一種是普通的JavaScript代碼,一種是使用aui標(biāo)簽。
1、普通的javascript代碼
<script>function test(){AUI().use('aui-dialog', function(A) {var popup = new A.Dialog({bodyContent: A.one('#webDav').html(),centered: true,destroyOnClose: true,modal: false,title: '彈出層測試',width: 500,buttons: [{label: '確定',handler: function() {alert('點(diǎn)擊了確定');}},{label:'取消',handler:function(){this.close();}}]}).render();}); } </script>代碼看起來有點(diǎn)小復(fù)雜,其實(shí)很簡單,逐步的說明一下:
var popup:?這是定義當(dāng)前的彈出層對象。在其他地方可以使用popup.close()關(guān)閉當(dāng)前的對話框。
bodyContent:?A.one('#webDav').html():表示彈出層的正文,這里是彈出一個id為webDav的對象。A.one('#webDav').html()這是aui代碼的寫法(aui其實(shí)是YUI的衍生版,所以和YUI的用法基本上一樣),表示選擇id為webDav的對象,取其中的html代碼。
centered:彈出后是否居中,默認(rèn)為false.
destroyOnClose:是否在半閉時銷毀
modal: 是否模態(tài)否,也就是是不是鎖定背景是否讓背景可以編輯,值為true/false,默認(rèn)為false,為true時背景不可以編輯。
title:彈出層的標(biāo)題,使用單引號或雙引號。
width:彈出層的寬度,必須為數(shù)字,不能用百分比。如果不寫為自適應(yīng)。
height:彈出層的高度,如果不寫為自適應(yīng)。
buttons:在彈出層上面定義的按鈕。非必須。我們一般添加確定和取消兩個。多個按鈕之間使用逗號分割,text的內(nèi)容為按鈕的顯示值,handler為綁定的方法
2、使用aui標(biāo)簽
<aui:script use="aui-dialog">var create = A.one('#createNew');create.on('click',function(event) {var popup = new A.Dialog({bodyContent: A.one('#webDav').html(),centered: true,modal: true,title: '彈出層測試',width: 500}).render();}); </aui:script>和上面的的基本上差不多,這里是在createNew的對象上綁定了一個click的方法,如果此對象被點(diǎn)擊了,執(zhí)行彈出層代碼。其他的和上面的一樣。
上面使用的是aui標(biāo)簽,所以需要在頁中引入
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>
3、使用Liferay.provide
此種方法和上面的非常類似,如下:
<aui:script> Liferay.provide(window,'showDialog',function() {var A = AUI();var dialog = new A.Dialog({bodyContent: A.one('#webDav').html(),destroyOnClose: true,modal: false,title: '這是標(biāo)題',width: 900}).render();},['aui-dialog'] ); </aui:script>寫法和上面的沒有太多的區(qū)別,只是寫法的不同。showDialog 這個參數(shù)其實(shí)就是函數(shù)名,在其他地方可以直接調(diào)用此方法來彈出下面的彈出層,如果是要傳參數(shù)可以直接寫在showDialog(arg)這個里面。上面的的function里面添加此參數(shù)。如function(arg),在下面直接使用arg參數(shù)即可。
二、彈出一個HTML頁面或者是JSP頁面。
彈出一個頁面的方法和上面的基本上相同,具體看下面的示例。
<aui:script> Liferay.provide(window,'showDialog',function() {var A = AUI();var url= "要彈出的頁面的地址";var dialog = new A.Dialog({destroyOnClose: true,modal: false,title: '這是標(biāo)題',width: 900}).plug(A.Plugin.IO,{uri: url}).render();},['aui-dialog'] ); </aui:script>不同之處是加了一個plug來顯示待彈出的頁面地址。在dialog里面也可以添加bodyContent屬性,里面可以添加上在彈出的過程的提示語,比“頁面正在加載中請稍候……”,在url加載后將替換上面的內(nèi)容。
三、彈出一個portlet頁面。
使用二里面的方法也可以彈出一個portlet頁面,但是有時候會不能正常工作,步驟2的彈出的原理還是彈出一個div,在這個div里面加載目標(biāo)頁面的內(nèi)容。彈出portlet頁面我們需要彈出一個iframe,這樣就可以使彈出的portlet頁面正常工作。方法如下:
<aui:script>Liferay.provide(window,'showPortletUrl',function(url) {var instance = this;Liferay.Util.openWindow({cache: false,dialog: {align: Liferay.Util.Window.ALIGN_CENTER,after: {render: function(event) {this.set('y', this.get('y') + 50);}},width: 1000},dialogIframe: {id: 'siteManagementIframe',uri: url},title: '管理頁面',uri: url});},['liferay-util-window']); </aui:script>在上面的方法中我是將待彈出的porltet的URL以參數(shù)的形式傳進(jìn)來的,調(diào)用的時候方法為:showPortletUrl(url)。dialogIframe中的id為彈出的iframe的id名,uri為待加載的portlet頁面地址。
注意:如果要彈出porltet,請講windowState設(shè)為pop_up,也就是LiferayWindowState.POP_UP這個變量。
Liferay 6.1開發(fā)學(xué)習(xí)(十四):在自己的Portlet中使用Liferay的全文檢索
在Liferay中的全文檢索是使用的Lucene,方便我們的對內(nèi)容進(jìn)行全文檢索。liferay中對文章、文檔、博客、wiki、留言等實(shí)現(xiàn)了全文檢索,如何在我們自己的Portlet中使用Liferay的全文檢索呢?
實(shí)例場景如下:
我們自己實(shí)現(xiàn)了一個CMS,沒有使用Liferay中的Journal類,比如存放新聞的類叫做CmsArticle。我們現(xiàn)在需要對這個新聞進(jìn)行全文檢索,可以檢索新聞?wù)摹?biāo)題、摘要、作者等,同時可以進(jìn)行范圍搜索,如只搜索標(biāo)題、只需要正文或全部等。
一、建立索引類
繼承BaseIndexer類,編寫一個索引類,如叫做CmsArticleIndexer。重寫里面的相關(guān)搜索方法。一般需要重寫
getClassNames
getSummary
doDelete
doGetDocument
doReindex
getPortletId
等幾個方法,其他的方法可以根據(jù)需要進(jìn)行重寫。
簡單貼幾個主要的方法的內(nèi)容:
protected Document doGetDocument(Object obj) throws Exception {CmsArticle article = (CmsArticle)obj; long companyId = article.getCompanyId();long groupId = getParentGroupId(article.getGroupId());long scopeGroupId = article.getGroupId(); ……………………省略相關(guān)字段的獲取和上面的一樣 Document document = new DocumentImpl(); document.addUID(PORTLET_ID, groupId, articleId);document.addKeyword(Field.COMPANY_ID, companyId);document.addKeyword(Field.PORTLET_ID, PORTLET_ID);document.addKeyword(Field.GROUP_ID, groupId);document.addKeyword(Field.SCOPE_GROUP_ID, scopeGroupId);document.addKeyword(Field.USER_ID, userId); //將不同的字段添加到索引中document.addDate(Field.MODIFIED_DATE, modifedDate);document.addText(Field.TITLE, title);document.addText(Field.CONTENT, ArticleUtil.getArticleText(content));document.addText(Field.DESCRIPTION, description);document.addText(Field.USER_NAME, userName);document.addKeyword(Field.ENTRY_CLASS_NAME, CmsArticle.class.getName());document.addKeyword(Field.ENTRY_CLASS_PK, articleId); //這個為必須的,否則會搜索不到內(nèi)容document.addKeyword(Field.ROOT_ENTRY_CLASS_PK, resourcePrimKey);document.addKeyword(Field.TYPE, type); return document;}下面是重建索引的方法,方法很簡單,根據(jù)傳入的companyId或者也可以使用groupid,將某個范圍下面的內(nèi)容進(jìn)行依次取出添加到索引庫里面,這里使用了分頁,如果數(shù)據(jù)量較小可以不用分頁,但數(shù)據(jù)量大時務(wù)必分頁,否則會將內(nèi)存耗盡。
//索引調(diào)用的方法 protected void doReindex(String[] ids) throws Exception {long companyId = GetterUtil.getLong(ids[0]); reindexArticles(companyId); } //從傳入的companyId里面依分頁將數(shù)據(jù)取出添加到索引庫里面 protected void reindexArticles(long companyId) throws Exception {int count = CmsArticleLocalServiceUtil.getCmsArticleCountByCompanyId(companyId,APPROVED_STATUS); int pages = count / Indexer.DEFAULT_INTERVAL; for (int i = 0; i <= pages; i++) {int start = (i * Indexer.DEFAULT_INTERVAL);int end = start + Indexer.DEFAULT_INTERVAL;reindexArticles(companyId, start, end);}} //索引內(nèi)容,在這里可以對新聞的狀態(tài)等進(jìn)行判斷,如只索引審批或發(fā)布過的,未審批的不進(jìn)行索引 protected void reindexArticles(long companyId, int start, int end)throws Exception { List<CmsArticle> articles = CmsArticleLocalServiceUtil.getCmsArticlesByCompanyId(companyId, APPROVED_STATUS,start, end); if (articles.isEmpty()) {return;} Collection<Document> documents = new ArrayList<Document>(); for (CmsArticle article : articles) {Document document = getDocument(article);documents.add(document);} //更新索引 SearchEngineUtil.updateDocuments(getSearchEngineId(),companyId, documents);}上面貼出來的是一些主要方法,可以根據(jù)不同的需求進(jìn)行調(diào)整,不滿足的可以參考Indexer相關(guān)類的實(shí)現(xiàn),liferay里面有博客、wiki、文章等索引實(shí)現(xiàn),的都是很好的學(xué)習(xí)參數(shù)資料,方法為在源碼的Indexer類名上按ctrl+T,查看他的相關(guān)實(shí)現(xiàn)或繼承類。
二、注冊索引類
將上面寫的索引類注冊到portlet中。打開liferay-portlet.xml文件,在相關(guān)的portlet中添加
<indexer-class>xxx.xxx.xxx.cmsarticle.search.CmsArticleIndexer</indexer-class>
這樣就將此索引類注冊到portlet中了。
注冊有什么好處呢?
1、可以在控制面板中的更新插件處,對某一個指定的portlet重建索引。
2、在控制面板中當(dāng)點(diǎn)擊重建所有搜索索引時,可以調(diào)用到此索引類進(jìn)行索引重建立。
3、如果設(shè)置了portal在啟動時更新索引,則liferay可以調(diào)到此類進(jìn)行索引更新。
簡而言之主是注冊之后,可以讓Liferay來管理索引,方便的進(jìn)行統(tǒng)一的索引管理、重建等。
三、搜索
建立完了索引,工作只算完成了一小部分,還有搜索。搜索的過程比建立索引的過程要簡單的多,核心代碼只要兩行。
//實(shí)例化索引類 Indexer indexer = IndexerRegistryUtil.getIndexer(CmsArticle.class); //進(jìn)行搜索 Hits results = indexer.search(searchContext); //從結(jié)果里面取Document Document[] docs = results.getDocs();第一步不需要特別說明,就是對相關(guān)索引類進(jìn)行初始化。第二步里面的搜索參數(shù)是一個searchContext,這是一個什么東西呢?這是Liferay包裝的一個參數(shù)類,可以在里面設(shè)置一些常用的搜索參數(shù),如關(guān)鍵詞、搜索分頁條件等。我們一般可以這樣使用:
//實(shí)例化一個SearchContext SearchContext searchContext = SearchContextFactory.getInstance(request); //start和end是分頁用,如我們只要取前20條,為start=0,end=20 searchContext.setStart(start);searchContext.setEnd(end);searchContext.setKeywords(keyWords);既然有分頁,則需要知道結(jié)果的總條數(shù)才可以,results.length()返回的就的命中的結(jié)果數(shù)量,也就是搜索結(jié)果的總數(shù)。根據(jù)start、end、總條數(shù)即可進(jìn)行分頁處理。
完整的搜索處理類核心代碼
Indexer indexer = IndexerRegistryUtil.getIndexer(CmsArticle.class); SearchContext searchContext = SearchContextFactory.getInstance(request); int start = (pageNumber-1) * pageSize;int end = pageNumber * pageSize;//取消搜索權(quán)限,liferay的搜索權(quán)限是否過濾是根據(jù)searchContext里面是否能獲取到的userId來區(qū)分的searchContext.setUserId(0);searchContext.setStart(start);searchContext.setEnd(end);searchContext.setKeywords(keyWords); //這里是自定義的搜索范圍,liferay默認(rèn)是全部,這里是為了實(shí)現(xiàn)只搜索標(biāo)題、只搜索正文等而添加的的searchContext.setAttribute(ArticleSearchConstants.SEARCH_SCOPE, searchScope);int countResult = 0;try {Hits results = indexer.search(searchContext); //取得搜索關(guān)鍵詞的分詞詞元String[] terms = results.getQueryTerms();//獲取結(jié)果總數(shù)countResult = results.getLength();Document[] docs = results.getDocs();for (int i=0;i<docs.length;i++) {Document document = docs[i];String title = document.get(Field.TITLE);//對標(biāo)題進(jìn)行關(guān)鍵詞高亮String hightLightTitle = StringUtil.highlight(title, terms);//從索引中提取正文片段,如果找不到就取正文的前200個字String snippet = results.getSnippets()[i];String content = snippet;if (Validator.isNull(snippet)) {content = StringUtil.shorten(document.get(Field.CONTENT), 200);}//高亮摘要String higthLightContent = StringUtil.highlight(content, terms);//取新聞的IDString articleId = document.get(Field.ENTRY_CLASS_PK);//取新聞的groupIdlong groupId = GetterUtil.getLong(document.get(Field.GROUP_ID)); //這里可以將數(shù)據(jù)的數(shù)據(jù)封裝到相關(guān)的搜索結(jié)果類里面,進(jìn)行界面上的顯示,下面的搜索結(jié)果類的封裝省略}} catch (SearchException e) {e.printStackTrace();}四、其他說明
1、如何在添加文章或內(nèi)容時對內(nèi)容建立索引?
可以另建立一個索引線程,在內(nèi)容添加的時候?qū)⒋祟愄砑拥剿饕?#xff0c;刪除時從索引中刪除。核心的是使用下面的方法。
indexer.reindex(article);
indexer.delete(article);
2、如何重建所有索引?
可以在控制面板中,服務(wù)器-->插件安裝-->找到此portlet,旁邊有一個重建索引的按鈕,點(diǎn)擊即可完成對索引的重建。
3、索引文件存儲于哪個地方?
默認(rèn)存儲于/data/lucene目錄下面
Liferay 6.1開發(fā)學(xué)習(xí)(十五):可配置portlet開發(fā)
一、什么是可配置portlet
其實(shí)portlet本來就是可以配置的,但我們的開發(fā)大部分情況下只使用view模式,edit和config模式一般沒有使用,對于使用editor和config等模式的portlet,我們可以將他們稱為可配置portlet。通過使用可配置portlet,可以做許多個性化定制。
應(yīng)用場景:
1、如果在首頁上有展現(xiàn)專題的地方,可以建立一個專題展現(xiàn)的portlet,這個地方要展現(xiàn)的內(nèi)容為一個圖片或多個圖片,點(diǎn)擊圖片可以跳轉(zhuǎn)相應(yīng)的鏈接。但是專題可能需要變化,則這里可以添加一個config或edit模式來讓管理員通過配置參數(shù)來定制。
2、如首頁的新聞欄目,設(shè)計(jì)時是展現(xiàn)的A欄目,但是實(shí)際中用戶可能有變化,需要換成其他欄目,同樣可以通過可配置portlet來滿足。
3、如提供RSS訂閱,我們可以在配置項(xiàng)里面設(shè)置RSS的輸出方法為標(biāo)題或者是摘要或者是全文,標(biāo)準(zhǔn)可以為atom或者rss2.0等配置。
4、如有一個指標(biāo)展現(xiàn),用戶需求為可定制的,用戶A可以選擇柱狀圖、用戶B可以選擇折線圖、用戶C可以選擇餅圖等。
包括但不限于以上場景,需要通過配置來適用不同的情況,為用戶提供可配置選項(xiàng)的地方都可以使用可配置portlet。
可配置portlet的開發(fā)方式
可配置portlet的開發(fā)方式,我按數(shù)據(jù)的存儲方式的不同,大概的分為兩種。一種為使用PortletPreferences存儲的,一種為自定義數(shù)據(jù)表結(jié)構(gòu)存儲的。
使用PortletPreferences存儲的方式為將配置數(shù)據(jù)以鍵值對的形式存儲于PortletPreferences的相關(guān)屬性字段里面。以portlet的實(shí)例ID做為識別進(jìn)行存儲信息,適用于配置信息不算太復(fù)雜的場景。
如果配置信息比較復(fù)雜,推薦建立相關(guān)的數(shù)據(jù)庫,將配置信息存儲于數(shù)據(jù)庫中。本文主要介紹存儲于PortletPreferences中的方法,存儲于數(shù)據(jù)庫和普通的portlet的數(shù)據(jù)存儲方法類似。
如果按模式的不同,又可以分為edit、config、help等不同的模式。這些對應(yīng)于建立portlet時選用的modes的不同而不同,這里主要介紹config模式。其他模式類似。
使用Config模式
1、需要有一個建立好的portlet。portlet的創(chuàng)建,參考前面的portlet簡述:http://www.huqiwen.com/2012/09/03/liferay-6-1-development-study-3-portlet-explicate/
2、在Liferay-portlet.xml里面找到此portlet的相關(guān)配置,在里面添加configuration-action-class元素,如下:
<portlet><portlet-name>customjspportlet</portlet-name><icon>/icon.png</icon><configuration-action-class>xx.xxx.xxx.customjspportlet.CustomJspConfigurationAction</configuration-action-class><instanceable>true</instanceable><header-portlet-css>/css/main.css</header-portlet-css><footer-portlet-javascript>/js/main.js</footer-portlet-javascript><css-class-wrapper>customjspportlet-portlet</css-class-wrapper></portlet>3、建立CustomJspConfigurationAction類,此類繼承自DefaultConfigurationAction即可。
4、重寫其中的render方法。如下。
public String render(PortletConfig portletConfig, RenderRequest renderRequest, RenderResponse renderResponse){ String portletId = renderRequest.getParameter("portletResource");PortletPreferences preferences = PortletPreferencesFactoryUtil.getPortletSetup(renderRequest, portletId); renderRequest.setAttribute("customjspConfig_page_title",preferences.getValue("customjspConfig_page_title", StringPool.BLANK));renderRequest.setAttribute("customjspConfig_page_link",preferences.getValue("customjspConfig_page_link", StringPool.BLANK)); return "/html/CustomJspPortlet/config.jsp"; }這個方法是點(diǎn)擊portlet中的配置時進(jìn)入的方法。在這個方法里面做以下幾件事情。
1):我們獲取到了當(dāng)前portlet的PortletPreferences。
2):從PortletPreferences里面獲取key為customjspConfig_page_title和customjspConfig_page_link的數(shù)據(jù),并將他們放到request里面。
3):告訴Liferay我的配置頁的JSP的路徑是哪個。
5、編寫config.jsp頁面。config.jsp頁面里面是我們要配置的一此參數(shù)信息,大部分情況下是一個展現(xiàn)的表單。主要內(nèi)容可以參考如下(從項(xiàng)目中截取的部分代碼,為說明問題已經(jīng)簡化):
<form action="<liferay-portlet:actionURL portletConfiguration="true" />" name="<portlet:namespace />fm" id="<portlet:namespace />fm" method="post"> <ul><li><span>標(biāo)題:</span><input tabindex="1" type="text" name="<portlet:namespace />customjspConfig_page_title" id="<portlet:namespace />customjspConfig_page_title" value="<%=title%>" /></li><li><span>鏈接地址:</span><input id='<portlet:namespace />custom_page_link' name='<portlet:namespace />customjspConfig_page_link' type="text" value="<%=link %>" /> </li><li><input type="button" value="" οnclick="<portlet:namespace />saveConfig()"></li> </ul> </form>這里的關(guān)鍵點(diǎn)為form的action,所有這種模式的可配置portlet的action都可以固定為:<liferay-portlet:actionURL portletConfiguration="true" />。
6、服務(wù)端保存配置信息的處理。步驟5中的action會進(jìn)入步驟3建立的配置類的processAction方法。在上面的配置類里重寫processAction方法。里面的內(nèi)容如下:
public void processAction(PortletConfig portletConfig, ActionRequest actionRequest, ActionResponse actionResponse)throws Exception {String portletResource = ParamUtil.getString(actionRequest, "portletResource"); PortletPreferences preferences = PortletPreferencesFactoryUtil.getPortletSetup(actionRequest, portletResource); if (Validator.isNotNull(preferences)) { //從request里面取數(shù)據(jù)String title = ParamUtil.getString(actionRequest, "customjspConfig_page_title");String link = ParamUtil.getString(actionRequest, "customjspConfig_page_link"); //將數(shù)據(jù)以鍵值對的形式填充到preferences里面preferences.setValue("customjspConfig_page_title", title);preferences.setValue("customjspConfig_page_link", link); //存儲數(shù)據(jù)到數(shù)據(jù)庫中,持久化數(shù)據(jù)preferences.store();SessionMessages.add(actionRequest, "success");}super.processAction(portletConfig, actionRequest, actionResponse);}到這里已經(jīng)完成了可配置portlet的配置部分的開發(fā)。
在view.jsp中使用配置數(shù)據(jù)
前面步驟開發(fā)的配置數(shù)據(jù)的目標(biāo)是為了在view.jsp中使用,在view.jsp中使用可以在view.jsp的action中使用,也可以直接在view.jsp中直接提取,方法為:
PortletPreferences preferences = renderRequest.getPreferences();String title = preferences.getValue("customjspConfig_page_title", StringPool.BLANK);String link = preferences.getValue("customjspConfig_page_link", StringPool.BLANK);通過這樣的方法即可取到前面的配置信息,取取的數(shù)據(jù)具體怎么展現(xiàn),怎么使用,根據(jù)不同的業(yè)務(wù)場景有所不同。
總結(jié)
以上是生活随笔為你收集整理的Liferay开发学习(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图片饱和度更改,c#,winform
- 下一篇: 安卓rtmp推流app_视频直播app开