liferay與portlet之間的通信
從我做Liferay到現(xiàn)在,這個問題一直都存在著,直到最近我才算是找到了一個可靠的方案,能夠滿足各種需求,從我最開始做到現(xiàn)在一共用到了四種方案,從低到高,我們一個一個的講。
一、通過URL傳值
這個是我在項目中***次遇到這樣的問題,找出的一個方案,原理就是A把B需要的參數(shù)加在自已生成的URL后面,然后再把整個頁面view一次,B根據(jù)取得的參數(shù)再做相應的處理,取URL參數(shù)代碼如下:
Java代碼
- public class CurrentURLUtil {
- public static Log log = LogFactory.getLog(CurrentURLUtil.class);
- public static int contain(String currentURL, String param) {
- return currentURL.indexOf(param);
- }
- public static String getString(String currentURL, String param) {
- try {
- int paramIndex = contain(currentURL, param);
- if (paramIndex == -1) {
- // log.warn("CurrentURL don't contain the parameter that name
- // is:"+param+",and method will return a blank");
- return "";
- } else {
- int afaterParamSperatorIndex = currentURL.indexOf("&", paramIndex+1);
- if (afaterParamSperatorIndex == -1) {
- return currentURL.substring(paramIndex + param.length() + 1);
- } else
- return currentURL.substring(paramIndex + param.length() + 1,
- afaterParamSperatorIndex);
- }
- } catch (RuntimeException e) {
- // TODO Auto-generated catch block
- return "";
- }
- }
- public static String getString(String currentURL, String param, String defaultStr) {
- String value = getString(currentURL, param);
- if(Validator.isNull(value))
- return defaultStr;
- else
- return value;
- }
- public static long getLong(String currentURL, String param) {
- String value = getString(currentURL, param);
- if (null == value || value.trim().equals("")) {
- return 0;
- } else if(Validator.isNumber(value))
- return Long.parseLong(value);
- else
- return 0;
- }
這種方法有比較多的缺陷,比如傳的參數(shù)只能是string,如果是map,list,大數(shù)據(jù)就不可行了,另外還有一個問題,安全性不高,你無法預料到這個頁面上有多少portlet,每個portlet會有多少操作,而每個操作都會產(chǎn)生一個url,會不會出現(xiàn)相同key?出錯的機率較高。
二、通過session傳值
這種方式和***種方式原理都是相同的,只不過要安全一些。A觸發(fā)一個action,在action里面把自已要處理的工作做完了后,把B需要的東西放在session里面,B在render里面去取這些東西,然后來完成自已的工作,或者就在JSP里面完成這些工作。但是這樣就出現(xiàn)了一個問題,你無法知道A先處理完還是B先處理完,解決的這個問題的方法有兩個,一個是讓B在處理之間等待一段時間,這個時間A一定能把工作完成,另外一個方法是用鎖的方式來解決,建一個static map,A負責開鎖,B負責鎖上,兩個千萬不能搞錯,當鎖為空或false時,B就去等侍,直到鎖打開。但是一定要記得在B處理完成后把鎖銷毀。這種方式,我也只在項目中用過一次。
三、通過模擬B的PortletURL
后面兩種方式也是我最近半年來才學會的,應該是安全的。先上一段代碼是模擬B的PortletURL的關(guān)鍵
Java代碼
- private static long _getPlidFromPortletId(HttpServletRequest request, long groupId,
- boolean isPrivate, String portletId, Entry
... entry) { - long plid = 0;
- if (entry == null) {
- plid = PortalUtil.getPlidFromPortletId(groupId, isPrivate, portletId);
- if(Validator.isNull(plid))
- plid = Long.valueOf(0);
- } else {
- try {
- List
layouts = LayoutLocalServiceUtil.getLayouts(groupId, isPrivate, LayoutConstants.TYPE_PORTLET); - for (Layout layout : layouts) {
- LayoutTypePortlet layoutTypePortlet =
- (LayoutTypePortlet)layout.getLayoutType();
- if (layoutTypePortlet.hasPortletId(portletId)) {
- if (PortalUtil.getScopeGroupId(layout, portletId) == groupId) {
- plid = layout.getPlid();
- List
list = PortletPreferencesLocalServiceUtil - .getPortletPreferences(plid, portletId);
- if (Validator.isNotNull(list)) {
- for (PortletPreferences pre : list) {
- int i = 0;
- if (entry.length < 1){
- plid = pre.getPlid();
- // _plidCache.put(key, plid);
- return plid;
- }
- javax.portlet.PortletPreferences jpre = PortletPreferencesSerializer
- .fromXML(PortalUtil.getCompanyId(request), pre
- .getOwnerId(), pre.getOwnerType(), plid,
- portletId, pre.getPreferences());
- for (; i < entry.length; i++) {
- Entry en = entry[i];
- if (!jpre.getValue(en.getKey().toString(),
- StringPool.BLANK).equals(
- en.getValue().toString()))
- break;
- }
- if (i == entry.length){
- plid = pre.getPlid();
- // _plidCache.put(key, plid);
- return plid;
- }
- }
- }
- }
- }
- }
- } catch (SystemException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- return plid;
- }
- public static PortletURL getPortletURL(long groupId, String portletId,
- HttpServletRequest request, Entry
... entry) { - long plid = _getPlidFromPortletId(request, groupId, false, portletId, entry);
- return new PortletURLImpl(request, portletId, plid,
- PortletRequest.RENDER_PHASE);
- }
- public static PortletURL getPortletURL(long groupId, long plid, String portletId,
- HttpServletRequest request, Entry
... entry) { - return new PortletURLImpl(request, portletId, plid,
- PortletRequest.RENDER_PHASE);
- }
根據(jù)上面代碼能看出,最關(guān)鍵是要取得plid,如果你兩個需要通信的portlet在一個頁面上,那就省了大事了,不然你就要去調(diào)用_getPlidFromPortletId這個,***一個參數(shù)是為了匹配這個portlet的configartion信息,因為一個網(wǎng)站有十幾個頁面,可能其中三個頁面會有這一個portlet,增加這個參數(shù)能提高準確性,但是影響性能。PortletURL得到了,那后面的事就好辦了,如果你是A只是為了傳信息本身不做任何處理,把參數(shù)放到PortletURL里,然后用就可以了,如果A要做完自已的工作再傳,那就以Action里面做完自已的工作,然后sendRedirect到PortletURL.toString()就可以了。這種方式應該是比較安全可靠的,并且我在幾個項目中都已經(jīng)實施過了。注意 :此方案僅能支持B屬性
四、通過jQuery.ajax異步通信
這個是***的一個方案,目前正在進行的項目我用了這個方案,其基本思想是:A后臺通知B去工作,然后A前臺讓B顯示工作結(jié)果,這個方案比較酷。具體實現(xiàn)如下:
1.A通過jQuery.ajax去請求B的jsonAction(參照前面Liferay異步提交文章)
2.然后根據(jù)返回結(jié)果讓B顯示處理結(jié)果(參照前面Liferay異步刷新文章中的第二種類型)
注:如果你A也要處理工作,那就讓A先處理然后根據(jù)結(jié)果再調(diào)用B的jsonAction,***讓A和B都分別顯示各自的工作結(jié)果。當然你也可以把A和B要做的工作都放在一個jsonAction里面
【編輯推薦】