Liferay Portal额外研究-银狐999

来源:互联网 发布:php一句话小马后门代码 编辑:程序博客网 时间:2024/05/16 00:55
 

Liferay Portal额外研究(一):初步在新Tomcat下部署

开发者在线 Builder.com.cn 更新时间:2008-03-19作者:银狐999 来源:CSDN

本文关键词: 部署 tomcat JAVA

Liferay额外研究(一):初步在新Tomcat下部署
 
从现在开始,会把我最近在研究的开源Portal Liferay一些心得贴出来。研究Liferay版本:Liferay Professional 4.0.0
 
柯自聪兄弟写过一系列的Liferay Portal开发文章,参考http://www.blogjava.net/eamoi/。所以基础性内容,本文不再细说,可参考柯自聪的文章或Blog
 
(一)部署Liferay Portlet
       Liferay简单部署一个portlet并不是很复杂,通过WEB-INF目录下的portlet.xmlliferay-portlet.xmlliferay-display.xml描述即可。
 
 
描述
portlet.xml
portlet.xml用来定义Portlet的诸如部署名称、初始化参数、支持模式、resource bundle等普通的初始化信息,包括:portlet-namedisplay-nameportlet-classinit-paramexpiration-cathesupportsportlet-infosecurity-role-ref等等。其正式的规范请参考:http://java.sun.com/xml/ns/Portlet/Portlet-app_1_0.xsd
liferay-portlet.xml
定义Portlet默认可用的用户组、默认模板、是否支持多个实例等,规范由http://www.liferay.com/dtd/liferay-Portlet-app_3_5_0.dtd
liferay-display.xml
定义Portlet默认的所属类别。Liferay PortalPortlet实行按类别管理和划分用户权限。
 
       Liferay是基于Struts Template页面模版技术来实现页面的,所以Liferay默认提供了com.liferay.portlet.StrutsPortlet这个Portlet Class来完成Portlet处理的;当然为了简单对普通jsp页面的处理,Liferay也提供了com.liferay.portlet.JSPPortlet等其他Portlet Class
 
       Liferay扩展了Portlet Mode,增加了about,config,preview,print等几种模式。所以,开发人员基于Liferay进行扩展Portlet Class需要基于com.liferay.portlet.LiferayPortlet。当然,允许直接继承javax.portlet.GenericPortlet进行扩展。
 
(二)部署Liferay应用在新下载的Tomcat
 
       这一块耗费我不少时间,因为Liferay采用了其修改后的Tomcat(实际上是Tomcat5.5,这是我后来才知道的)。
       但我很不喜欢Liferay这种绑定方式,而且默认开发必须采用其层层Ant Build方式,并且绑定其Tomcat或其他其修改后提供的server。——当然,在Liferay可能认为这样可以减少开发人员对环境配置的关心。
 
       让我来看看,如何在一个新下载的Tomcat5.0.28上成功部署Liferay应用:
 
(1)      首先把liferay工程目录放置Tomcat_Home/目录下,当然,你可以放置在Tomcat_Home/web-apps目录下。
(2)      其次,需要把liferay默认的目录下的Common/lib/ext目录下的一些jarcopyTomcat_Home/common/lib目录下。注意,不要放置在ext目录下,默认tomcat5.0.28是不自动加载ext目录下的jar包的,这跟Tomcat5.5不同。这些jar包主要是:hsql.jarcommons-logging.jarlog4j.jar这三个。
(3)      liferay默认的目录下的Common/lib/ext中的portal-shared.jar portlet.jar,可以移到liferay应用的WEB-INF/lib中。
(4)      拷贝Root.xml Tomcat_HomeconfCatalinalocalhost目录下,配置webcontext信息。并在此配置DataSource注意,liferay的默认运行中的配置是Tomcat5.5的写法,所以此处配置DataSource的写法,就必须更改为Tomcat5.0的写法。否则,运行过程中会抛“Cannot create JDBC driver of class '' for connect URL 'null'”异常
<Context docBase="D:Tomcat5028 liferay" path="" reloadable="true">
<Resourcename="jdbc/LiferayPool"auth="Container"
               type="javax.sql.DataSource"    />
<ResourceParams name="jdbc/LiferayPool">
           <parameter>
<name>factory</name>
               <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
XXX(其他配置,此处略)
     </ResourceParams>
</Context>
有关Liferay对连接池的引用,可以去Portal.properties配置文件中修改。默认此配置文件已经被打在了liferayportal-ejb.jar中。
 
(5)      配置jaasconf。讲jaas.config文件放置在Tomcat_Homeconf目录下。并在catalina.bat文件中增加 -Djava.security.auth.login.config=%CATALINA_HOME%/conf/jaas.config 来设置jaas的配置。当然,这首先一定要保证在前面的Root.xmlContext中配置JAASRealm
//注意,暂时必须把liferay应用配置成为默认根应用,否则不可以正确运行。
<Context docBase="D:
Tomcat5028 liferay"path="" reloadable="true">
<Realm className="org.apache.catalina.realm.JAASRealm"
          appName="PortalRealm"
           userClassNames="com.liferay.portal.security.jaas.PortalPrincipal"
          roleClassNames="com.liferay.portal.security.jaas.PortalRole"
          debug="99"
          useContextClassLoader="false" />     
</Context>
              jaas.config的文件中,设置如下内容:
PortalRealm {
     com.liferay.portal.shared.security.jaas.PortalLoginModule required;
};
              Jaas是需要被正确配置的,否则系统不可以正确登陆,而且会一直不断的访问/jaas_securit_check,而不能登陆。
 
基本上进行如上操作之后,即可在Tomcat5.0.28下单独运行。
 
 

Liferay Portal额外研究(二):对Liferay进行瘦身

Spring配置管理XML应用服务器Struts
Liferay的体系是很庞杂的,居然有些文章对外宣称Liferay是微内核,我想写这文章的哥们没有搞清楚什么是“微内核”。
 
       Liferay 受其企业版本影响不小,毕竟Liferay公司主要还是“企业行为”,而不是一个单纯的一个“开源团体”行为。所以Liferay Portal本身内嵌了大量的Portlet,而且这些Portlet和Liferay Portal Framework甚至还有些交融。这就是为什么liferay portal-ejb.jar会有3M多。
 
       虽然我们可以通过修改system.properties,portlet.properties,protal-spring这些基础配置文件来修改声明哪些服务不需要加载,也可以通过修改 WEB-INF目录下的portlet.xml,liferay-portlet.xml以及liferay-display.xml这些文件来删除一些不需要的portlet。
 
       但是,我想真正敢真么干的,估计很少。这是为什么呢,就是应为Liferay内部实现的结构和代码,并不是非常良好。而对于这一块的优化,也没有很详细的帮助使用手册。在Liferay的网站上,只有一些教开发人员如何部署在不同服务器和数据库,如何新增一些portlet和theme,以及如何修改权限方面的浅显参考手册。
 
       接下来就讲一讲对Liferay的瘦身操作,Liferay变成一个只提供最基本的Portal框架和部署机制的portal context,而去掉那些多余的portlet。—— 因为这些多余的portlet大多国内的项目没有任何利用价值,但是如果需要部署的话,则会大大影响系统响应性能,而且让开发也变得比较麻烦。
 
       当然,是否按照我今天说的方式对Liferay进行瘦身,这全凭习惯。有些朋友不愿改变Liferay的结构,只希望单纯通过配置来加载,也是可以的。
 
(1)保留Liferay最基本的一些组件
      
       Liferay提供了一些基本组件,这些组件不属于Portal框架之内,但是整个portal服务是基于这些组件。
包结构
说明
com.liferay.counter
主要提供主建操作服务,Liferay内部的提供的组织结构表维护,就是采用counter提供的主建自增机制
com.liferay.filters
提供一些基础的基于servlet filter的过滤器
com.liferay.taglib
提供最基本的web展示标签
com.liferay.util
提供最基本的一些公共组件
       以上这四个组件是必须保留的,另外还有两个基本组件:com.liferay.mail(提供邮件服务)和com.liferay.wsrp(提供webservice服务)。这个实际上应该属于可选的,如果觉得需要的话,也可以纳入。
 
(2)保留Liferay的Portal基础服务
       Liferay的基础服务是以com.liferay.portal作为基础的,基本属于此包内的都尽量保留。目前其子package说明如下:
包结构
说明
com.liferay.portal
此包下放置了portal服务相关的一些异常
com.liferay.portal.action
负责一些struts action处理,比如Login等
com.liferay.portal.definitions
此包不是类包,而是负责放置一些定义相关的dtd文件资源。具体需要哪些dtd,可以参考com.liferay.portal.util. EntityResolver类
com.liferay.portal.dependencies
此包也不是类包,而是负责一些依赖性的资源文件。
com.liferay.portal.deploy
负责自动部署和热部署
com.liferay.portal.events
这个包内主要是一些行为处理类
com.liferay.portal.im
即时消息的支持
com.liferay.portal.jcr
提供JSR-170 JCR的支持,并内部提供Jackrabbit的实现支持
com.liferay.portal.job
对一些时间调度性Job的支持
com.liferay.portal.language
对语言的支持包
com.liferay.portal.lucene
对全文检索的支持
com.liferay.portal.model
一些模型对象的集合
com.liferay.portal.security
 
com.liferay.portal.servlet
 
com.liferay.portal.spring
 
com.liferay.portal.struts
 
com.liferay.portal.theme
提供对“主题”,也就是界面风格的支持
com.liferay.portal.tools
 
com.liferay.portal.util
 
com.liferay.portal.velocity
 
com.liferay.portal.wsrp
 
 
       其实我们可以把Liferay这些portal服务再缩简一些,但刚开始建议大家不要随便的删减,保留原始的即可。
 
(3)缩减portlet应用
       Liferay提供了大量的portlet应用,有大概七八十个。正应为这些portlet的加载和部署,让Liferay启动缓慢,消耗系统资源多。实际上,保持Liferay Portal正常运行,只需要其中几个就可以了,剩下的,我们可以根据需要进行删减。
 
       下面列出了一些最基本的portlet,只需要保留如下的这些portlet即可保证liferay的正常启动和运行
包结构
说明
com.liferay.portlet
Liferay Portlet的一些基础类
com.liferay.portlet.admin
管理portlet
com.liferay.portlet.calendar
日期portlet虽然可以不需要,但是其内部提供对job的调度。
com.liferay.portlet.communities
这个是负责配置用户其所在的group,利用可以配置用户所拥有的工作区。
com.liferay.portlet.enterpriseadmin
 
com.liferay.portlet.language
 
com.liferay.portlet.layoutconfiguration
 
com.liferay.portlet.login
 
com.liferay.portlet.myaccount
用于配置用户信息
com.liferay.portlet.myplaces
用于控制用户的工作区选择
com.liferay.portlet.portletconfiguration
 
com.liferay.portlet.themegallery
用于控制主题风格
com.liferay.portlet.translator
这个包必须要,虽然portlet可以不用,但是被portal.language包引入了
com.liferay.portlet.wsrp
这个包必须要。
 
       只需要保证如上的portlet在系统中,即可保证Liferay的正常运行。
 
       但是,不以为只需要简单得讲起他的Porlet删除即可,那就大错特错了。Liferay在这一层面做的非常不友善,内部代码由一点点地耦合。很多地方依靠写if else来判断,所以造成了在portal这个服务包中,竟然存在很多地方引用portlet中的类。
       不过这个倒不难修改,只需要花费一点点时间,简单修改一下就可以了。比较容易,此处就不多说。
 
(4)从配置文件中删除无用portlet的部署
      
       这个主要是修改WEB-INF目录下的portlet.xml,liferay-portlet.xml以及liferay-display.xml这些文件。只需要依次把那些不需要的portlet删除即可。没有什么难度,细心点就可以了。
 
(5)修改服务配置文件
 
       Liferay的配置文件也是很多,放置也是在好几个地方:
位置
配置文件说明
/WEB-INF
portlet描述和struts等配置文件
/WEB-INF/classes
system.properties和portal.properties配置文件
/WEB-INF/classes/META-INF
portal-spring.xml,portal-hbm.xml,portal-log4j.xml配置文件。此位置可调,具体可以修改portal.properties内容。
 
       为了让系统正确运行,我们还需要修改system.properties和portal.properties配置文件,这是Liferay核心配置文件。Liferay的很多服务都是在此配置文件中声明和修改。具体修改哪些本文不细说,改篇专门作个专题讲。
 
       还需要修改portal-spring.xml(如果是professional版,则是portal-spring-professional.xml)。需要将那些已经没有的类bean删除。否则Liferay现在的加载机制,一旦碰到没有的类的bean,则加载不成功了。
       当然portal-hbm.xml也是需要修改的,去掉那些不需要的类即可。
 
       基本上经过以上五个步骤,Liferay即可完成手身了。在真实系统研发过程中,不一定非要选择这样的瘦身方式,毕竟这种方式,对后续Liferay版本的维护带来一定的工作量。—— 但是,如果这么尝试一把,则可以在通过调试过程中,对Liferay的配置体系和代码结构体系有个较为清晰的认识
 

Liferay Portal额外研究(三):IFrame Portlet地session丢失疑难处理

分类: Liferay Portal 39人阅读 评论(0)收藏 举报

       Liferay提供了一种非常的简单web应用整合和单点登陆的方式:Iframe Portlet。利用Iframe Portlet可以很容易将一个已经存在的web应用纳入,并且支持利用form的post或get方式,实现用户的登陆。
 
       对于Liferay这样的机制没有任何问题,实现的也非常巧妙;但是对于很多web应用系统来说,使用Liferay IFrame Portlet的form方式实现登陆后,虽然可以成功登陆,但是在显示的新页面中,却发现用户信息丢失,或者更准确的说,是session丢失。
 
       其实,这种现象跟Liferay关系不大,而是应用本身决定的。事实上,所有的portal context的iframe 方式,都有可能发生这个情况。
 
       因为很多web应用系统,在执行Login操作的后,习惯性的选择redirect操作,这样会强制浏览器中的显示地址变更为转移的地址。事实上这是个很正确的做法,在正常境况下,不会有任何问题,而且还可以很好的防止页面刷新等所带来的问题。
 
       但是在Liferay的IFrame Portlet中,web应用这样的Redirect操作,造成了调转到新页面后,session变成了一个新的,从而造成放置在原有session中的login user信息丢失。
 
       跟踪并做了如下的一组测试(Liferay和webapp在不同的JVM环境下):
应用
位置
session id
(Liferay)
执行form post前
D03E1B828395EF5BCB1063A8290BD254
(APP_A)
Login操作
397BB3656E2A12A96CE3F16E0A89C607
(APP_A)
登陆后的新页面
58A1054C6EDE4A7D6CFA2FCDBB3E0736
       从上面可以明显看出来,redirect之后,web应用的新页面产生了新的sessionid      
 
       解决这个问题,有两种方式,这两种方式都依赖于被liferay portlet纳入的web应用自身。
       方式一:Login操作后,不采用Redirect方式,而是Dispatcher方式。
       方式二:Login操作后,依然采用redirect方式,但将当前的jsessionid赋予新的页面。
 
Dispatcher方式:
 
ServletContext sc = getServletContext();
RequestDispatcher rd = null;
rd = sc.getRequestDispatcher("/index.jsp");
rd.forward(request, response);
 
Redirect方式(保持同一个session):
      
response.sendRedirect(“
index.jsp;jsessionid=397BB3656E2A12A96CE3F16E0A89C607”)
       有一种情况下,无所谓是否采用Redirect方式,这就是在Liferay和webapp在同一个JVM环境下。
 

Liferay Portal额外研究(4):修改用户登录后的默认布局和内容

开发者在线 Builder.com.cn 更新时间:2008-03-19作者:银狐999 来源:CSDN

本文关键词: 用户登录 JAVA

 Liferay在用户第一次登陆后,都会为其产生一个默认的私有首页Layout。 在Liferay早期版本,可以在系统管理员管理界面中,配置默认的group layout。但是在4.1版本中已经没有这个功能,所以默认情况下,新注册的用户,在登陆后,首先看到的其私有place都是一样的内容,而这些内容都是liferay提供的。
 
    对我们自定的Company来说,这肯定是不合适的,我们需要自己定义用户登录后,默认显示的内容和布局。
 
    后来在Liferay forum中,找到了一篇帖子,给了解决此种问题的解决办法:在portlet-ext.properties中配置一个 default.user.layout.group 属性(自定义的),用于指明默认的layout-group。在ServicePreAction类的扩展修改 addDefaultLayouts 操作,满足特定的需求应用。这种扩展的方式就是,将指定layout-group拷贝给用户第一默认的,这样就不会再使用liferay默认的了。—— 当然这样的方式是比较简单的,可能在系统实施过程中,有比这更加复杂的需求。

 
新建默认的Community
首先,通过新增一个新的Community,命名为User_Default,并新增一个private的page与内容.
 
配置默认的Community
首先在ext项目的 ext-ejb目录下,修改portal-ext.properties文件,增加如下设置:
 
default.user.layout.group=User_Default

然后通过build,将portal-ext.properties移动到 ext项目的
    extserverstomcatwebappsROOTWEB-INFclasses 目录下。
 
构造LayoutCopy类
public class LayoutCopy ...{
    
    private static Log _log = LogFactory.getLog(LayoutCopy.class);
    
    private User user;

    private String ownerId;

   private Group userGroup;
   public LayoutCopy(User user) ...{
       super();

       this.user = user;

        this.ownerId = getOwnerId(user.getGroup().getGroupId(), false);
       this.userGroup = user.getGroup();
   }

   public void copyDefaultUserLayout(HttpServletRequest httpReq)
           throws SystemException, PortalException ...{
      // set in the portal-ext.properties:
       // default.user.layout.group=Default User
       // and create then group/community "Default User" 
       // CWPPropsUtil.DEFUALT_USER_LAYOUT_GROUP = "default.user.layout.group"
       Group group = GroupLocalServiceUtil.getGroup(user.getCompanyId(),
               PropsUtil.get("default.user.layout.group"));

       try ...{
           String groupOwnerId = getOwnerId(group.getGroupId(), true);
           List privateLayouts = LayoutLocalServiceUtil
                   .getLayouts(groupOwnerId);

           for (Iterator itr = privateLayouts.iterator(); itr.hasNext();) ...{
               Layout layout = (Layout) itr.next();
               Layout newLayout = copyLayout(layout);
               copyPreferences(httpReq, newLayout, layout);
           }
       } catch (PortalException e) ...{
           _log.error("Cannot copy private layouts", e);
       } catch (Exception e) ...{
           _log.error("Cannot copy public layouts", e);
       }

       try ...{
           String groupOwnerId = getOwnerId(group.getGroupId(), false);
           List publicLayouts = LayoutLocalServiceUtil
                   .getLayouts(groupOwnerId);

           for (Iterator itr = publicLayouts.iterator(); itr.hasNext();) ...{
               Layout layout = (Layout) itr.next();
               Layout newLayout = copyLayout(layout);
               copyPreferences(httpReq, newLayout, layout);
           }
       } catch (PortalException e) ...{
           _log.error("Cannot copy public layouts", e);
       } catch (Exception e) ...{
           _log.error("Cannot copy public layouts", e);
       }

   }

   public void resetLayout(HttpServletRequest httpReq) throws SystemException, PortalException ...{
       String ownerId = getOwnerId(user.getGroup().getGroupId(), false);
       LayoutLocalServiceUtil.deleteLayouts(ownerId);
       PortletPreferencesLocalServiceUtil.deletePortletPreferences(ownerId);

       ownerId = getOwnerId(user.getGroup().getGroupId(), true);
       LayoutLocalServiceUtil.deleteLayouts(ownerId);
       PortletPreferencesLocalServiceUtil.deletePortletPreferences(ownerId);

       copyDefaultUserLayout(httpReq);
   }

   public Layout copyLayout(Layout groupDefaultLayout) throws SystemException,
           PortalException ...{
       Layout layout = LayoutLocalServiceUtil.addLayout(
               userGroup.getGroupId(), user.getUserId(), groupDefaultLayout
                      .isPrivateLayout(), groupDefaultLayout
                       .getParentLayoutId(), groupDefaultLayout.getName(user
                       .getLocale()), groupDefaultLayout.getType(),
               groupDefaultLayout.isHidden(), null);

       LayoutLocalServiceUtil.updateLayout(layout.getLayoutId(), layout
        .getOwnerId(), groupDefaultLayout.getTypeSettings());
       layout = LayoutLocalServiceUtil.updateLookAndFeel(layout.getLayoutId(),
               layout.getOwnerId(), groupDefaultLayout.getThemeId(),
               groupDefaultLayout.getColorSchemeId());

       // layoutMapping.put(groupDefaultLayout.getPrimaryKey(),
       // layout.getPrimaryKey());

       return layout;
   }

   protected void copyPreferences(HttpServletRequest httpReq, Layout layout,
           Layout copyLayout) throws Exception ...{

       String companyId = layout.getCompanyId();

       LayoutTypePortlet copyLayoutTypePortlet = (LayoutTypePortlet) copyLayout
               .getLayoutType();

       List copyPortletIds = copyLayoutTypePortlet.getPortletIds();

       for (int i = 0; i < copyPortletIds.size(); i++) ...{
           String copyPortletId = (String) copyPortletIds.get(i);

           // Copy preference

           PortletPreferencesPK prefsPK = PortletPreferencesFactory
                   .getPortletPreferencesPK(httpReq, copyPortletId, layout
                           .getPlid());

           PortletPreferencesLocalServiceUtil.getPreferences(companyId,
                   prefsPK);

           PortletPreferencesPK copyPrefsPK = PortletPreferencesFactory
                   .getPortletPreferencesPK(httpReq, copyPortletId, copyLayout
                           .getPlid());

           PortletPreferencesImpl copyPrefsImpl = (PortletPreferencesImpl) PortletPreferencesLocalServiceUtil
                   .getPreferences(companyId, copyPrefsPK);

           PortletPreferencesLocalServiceUtil.updatePreferences(prefsPK,
                   copyPrefsImpl);

           // Copy portlet setup

           prefsPK = new PortletPreferencesPK(copyPortletId, layout
                   .getLayoutId(), layout.getOwnerId());

           PortletPreferencesLocalServiceUtil.getPreferences(companyId,
                   prefsPK);

           copyPrefsPK = new PortletPreferencesPK(copyPortletId, copyLayout
                   .getLayoutId(), copyLayout.getOwnerId());

           copyPrefsImpl = (PortletPreferencesImpl) PortletPreferencesLocalServiceUtil
                   .getPreferences(companyId, copyPrefsPK);

           PortletPreferencesLocalServiceUtil.updatePreferences(prefsPK,
                   copyPrefsImpl);
       }
   }

   private String getOwnerId(String groupId, boolean privateLayout) ...{
       if (privateLayout) ...{
           return Layout.PRIVATE + groupId;
       } else ...{
           return Layout.PUBLIC + groupId;
       }
   }

}
 
 
修改com.liferay.portal.events.ServicePreAction类
 
    是在 ext工程的 ext-ejb/src下修改,新建com.liferay.portal.events包,并把原始的ServicePreAction类拷贝至此,然后修改,修改后通过ext-ejb下的build.xml编译部署。
 
在ServicePreAction类中新增一个addDefaultLayouts方法:
protected void addDefaultLayouts(HttpServletRequest httpReq, User user)
                throws PortalException, SystemException {
            if (user.hasPrivateLayouts()) {
                return;
            }
           (new LayoutCopy(user)).copyDefaultUserLayout(httpReq);
}
 
然后,修改run方法中对原始addDefaultLayouts方法的调用方法:
if (layoutsRequired) { 
    String user_layout_group = PropsUtil.get("default.user.layout.group");
    if(user_layout_group==null || user_layout_group.length()==0){
            addDefaultLayouts(user);
    }else{
            addDefaultLayouts(req, user);
    }
}
 
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
http://www.21tx.com 2007年06月18日 银狐999

作者:胡长城(银狐999)
时间:2006年9月3日晚

     Liferay默认提供的基于Struts Action扩展的PortletAction是不支持多分发命令的,也就是我们一般常用的DispatchAction。但在我们日常基于Struts处理的操作中,已经大量的沿用了DispatchAction处理方式,采用“cmd=queryall”诸如此类的方式。
    本文就来给大家讲解如何通过扩展,让Liferay实现对多分发命令Action的支持。
 
    首先让我们来看看Liferay是如何处理的:
     portlet.XML中,我们一般会配置如下:
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)<portlet-class>com.liferay.portlet.StrutsPortlet</portlet-class>
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
<init-param>
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)    
<name>view-action</name>
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)    
<value>/ext/reports/view_reports</value>
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
</init-param>
 
       这样Liferay面对一个Portlet请求的时候,会根据请求model来执行Portlet的doView或doEdit方式。当执行doView的时候就会请求其view-action所配置的Action URL所代表的Action来处理。
      其处理流程大致是:Portlet类——〉RequestProcessor——〉StrutsAction处理类
 
     我们可以通过两种扩展方案来实现对多分发的支持:
     方案(一):扩展Liferay的StrutsPortlet类,并写一个DispatchPortletAction类,这样不用扩展RequestProcessor实现。
     方案(二):扩展RequestProcessor与,并写一个DispatchPortletAction类,这样可以直接使用Liferay所提供的StrutsPortlet类。对于RequestProcessor的扩展,在通过portal.properties文件中通过配置“struts.portlet.request.processor”属性来设置。
 
    接下来就两种方案做分别的详细讲解(本篇先讲方案一):
 
方案(一)
 
首先让我们写一个DispatchPortletAction类,此类可以通过扩展Liferay本身的PortletAction实现,也可以通过扩展Struts本身的DispatchAction实现。本人是选择后一种方式,这样扩展的代码量较少,都不要自己写execute方式,直接使用基类的即可。
对于DispatchPortletAction主要扩展dispatchMethod和getMethodName方法。注意在getMechodName方法中,还追加了从request.getAttribute(parameter)获取方法名称,并注意unspecified方法,这个是在没有指明访问方法的时候默认执行的,所以开发人员在后续写自己的Action一定要实现这个。

Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)public class DispatchPortletAction extends DispatchAction ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)    
protected ActionForward dispatchMethod(ActionMapping mapping,
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            ActionForm form, HttpServletRequest request,
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            HttpServletResponse response, String name) 
throws Exception ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        PortletConfig portletConfig 
= (PortletConfig) request
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                .getAttribute(WebKeys.JavaX_PORTLET_CONFIG);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        RenderRequest renderRequest 
= (RenderRequest) request
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                .getAttribute(WebKeys.JAVAX_PORTLET_REQUEST);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        RenderResponse renderResponse 
= (RenderResponse) request
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                .getAttribute(WebKeys.JAVAX_PORTLET_RESPONSE);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        
if (name == null...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            
return this.unspecified(mapping, form, portletConfig,
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                    renderRequest, renderResponse);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        }

Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        Method method 
= null;
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        
try ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            method 
= getMethod(name);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        }
 catch (NoSuchMethodException e) ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            String message 
= messages.getMessage("dispatch.method",
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                    mapping.getPath(), name);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            log.error(message, e);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            String userMsg 
= messages.getMessage("dispatch.method.user",
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                    mapping.getPath());
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            
throw new NoSuchMethodException(userMsg);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        }

Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        ActionForward forward 
= null;
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        
try ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            Object args[] 
= ...{ mapping, form, portletConfig, renderRequest,
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                    renderResponse }
;
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            forward 
= (ActionForward) method.invoke(this, args);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        }
 catch (ClassCastException e) ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            String message 
= messages.getMessage("dispatch.return",
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                    mapping.getPath(), name);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            log.error(message, e);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            
throw e;
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        }
 catch (IllegalAccessException e) ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            String message 
= messages.getMessage("dispatch.error",
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                    mapping.getPath(), name);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            log.error(message, e);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            
throw e;
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        }
 catch (InvocationTargetException e) ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            Throwable t 
= e.getTargetException();
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            
if (t instanceof Exception) ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                
throw ((Exception) t);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            }
 else ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                String message 
= messages.getMessage("dispatch.error",
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                        mapping.getPath(), name);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                log.error(message, e);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)                
throw new ServletException(t);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            }

Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        }

Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        
return (forward);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)    }

Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)    
protected String getMethodName(ActionMapping mapping, ActionForm form,
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            HttpServletRequest request, HttpServletResponse response,
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            String parameter) 
throws Exception ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        String methodName 
= request.getParameter(parameter);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        
if (methodName == null || methodName.length() == 0...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)             methodName 
=
 (String) request.getAttribute(parameter);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        }

Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        
return methodName;
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)    }

Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)    
public ActionForward unspecified(ActionMapping mapping, ActionForm form,
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            PortletConfig config, RenderRequest req, RenderResponse res)
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            
throws Exception ...{
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)        
return null;
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)    }

Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)    
private static Log log = LogFactory.getLog(DispatchPortletAction.class);
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)    
protected Class[] types = ...{ ActionMapping.class, ActionForm.class,
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)            PortletConfig.
class, RenderRequest.class, RenderResponse.class }
;
Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)}

Liferay Portal额外研究(5):对多分发命令Action的支持(方案一)

        这样后续多分发Action在书写的时候,只需要定义不同的方法即可,但是方法的参数需要依照如下规范,如下一个queryAll的方法:
public ActionForward queryAll(ActionMapping mapping, ActionForm form,
            PortletConfig config, RenderRequest req, RenderResponse res)
            
throws Exception {
    
//业务处理
//返回ActionForward即可
}

 
         在那些portlet配置文件的view-action属性中,是不能够增加参数的,比如你不能够采用 /ext/reports/view_reports?cmd=queryAll这种方式。所以我们需要在扩展的Portlet中做一些拦截。
可能有人会说,我不需要在初始的view-action中增加参数。事实上这个的确不是强制,如果不追加参数,则会访问unspecified方法。但是对于Portlet的显示,其Normal和Max页面显示,都会请求默认的view-action。所以我们需要在Portlet类实现上扩展,于是扩展了一个DispachStrutsPortlet,如下:


public
 class DispachStrutsPortlet extends StrutsPortlet {

      
public void doView(RenderRequest req, RenderResponse res)
                                                                   
throws IOException, PortletException {
               
//注意我的命令参数是cmdx,而不是通常的cmd。
                String cmd = req.getParameter("cmdx");
                
if(cmd==null || cmd.length()==0){
                       
if (req.getWindowstate().equals(Windowstate. MAXIMIZED)) {
                        req.setAttribute(
"cmdx","queryAll");
                }
                
super.doView(req, res);
        }
}
 
如上面的实现,则表示,如果Portlet是Normal页面状态请求的时候,则在view-action的时候,则仅访问默认的unspecified方法;如果是Max页面状态,则执行queryAll方法。
 
有一个需要注意的地方,由于“cmd”参数已经被Liferay使用,所以我们需要用另外的变量来表示方法。这里我采用的是“cmdx”。
 

Liferay Portal额外研究(六):Portlet附件上传处理的点滴

首先更正上一篇有关多分发Action处理的一些严重Bug。
 
更正一:在上篇中,我比较倾向于直接基于Struts DispatchAction扩展,这是错误的,应该尽量基于PortletAction,虽然这样会让扩展增加一些Struts DispatchAction本已有的代码,但是这才是符合Portlet Action处理思想的。并且在Liferay的内部处理中,对于actionurl处理的情况下,是强制必须基于PortletAction扩展的。
更正二:在上篇中,多分发处理的样例代码只侧重对Render的多分发,其实这是不完善的,也容易造成误导。在Porttal的Portlet请求处理,是分为:Action和Render两个阶段的。其实真正的多业务处理更应该在Action阶段来完成,Render则主要负责对push位置和页面数据进行渲染。
 
Liferay中开发附件上传处理应用,要比在单纯Servlet和Struts Action中开发简单很多。但是需要注意的是,必须在Action阶段才能处理附件File对象,而在Render阶段已经不能处理了。
 
让我们首先来看一下com.liferay.portal.servlet.MainServlet 类,此类是所有“/c”请求的转移控制类。在此类中,liferay对含有文件上传的请求做了拦截和封装,利用UploadServletRequest 类来包装原始的http request请求

if ((contentType != null&&
            (contentType.startsWith(
"multipart/form-data"))) {
            req 
= new
 UploadServletRequest(req);
}

        在UploadServletRequest类中,则将所有当前请求参数进行了提取,并对上传的文件做了临时存储。实际上内部是采用Apache Commons Upload进行的封装。
   
    这样在PortletAction的procesAction处理中,可以对上传附件进行业务处理和存储。       当然,你可以通过ActionRequest来强制自己获取原始的UploadServletRequest对象,可以如下操作:

 

public class NewFileUploadAction extends PortletAction {
    
public void
 processAction(
            ActionMapping mapping, ActionForm form, PortletConfig config,
            ActionRequest req, ActionResponse res)
        
throws
 Exception {
        
         
//注意这里面是获取UploadPortletRequest对象

        UploadPortletRequest urequest = PortalUtil.getUploadPortletRequest(req);
         File f 
= urequest.getFile("file1"
);
}

 

 

 

//req是ActionRequest对象
ActionRequestImpl reqImpl = (ActionRequestImpl)req;
HttpServletRequest httpReq 
=
 reqImpl.getHttpServletRequest();
UploadServletRequest urequest 
= (UploadServletRequest)httpReq;

 

      置于在Action处理阶段,获取到UploadServletRequest对象后存储附件、过滤附件类型等操作就很容易实现了,此处不再累赘叙述。
   
  不过在附件上传中都会涉及到一个问题:控制附件上传的大小和类型。对于类型的控制,liferay没有提供任何控制和扩展实现机制,这个只能开发人员在外围自己实现。

    对于控制附件上传大小,则只能通过在system_ext.properties配置“com.liferay.util.servlet.UploadServletRequest.max.size”属性来统一设置。
    从这两个方面来讲,liferay对附件的处理不够灵活,在开发过程中,还需要做一定封装来辅助。
 
    稍微在这里补充一点,开发人员可以通过在页面请求url中,根据参数来决定是否执行action阶段。
    如下所示,通过renderResponsecreateActionURLcreateReanderURL来决定提交请求是否执行Action阶段,但注意,都会执行reader阶段的。

 

<%
PortletURL portletURL 
= renderResponse.createActionURL();
portletURL.setWindowState(WindowState.MAXIMIZED);
portletURL.setParameter(
"struts_action""/venus/template/fileupload/FileUpoadAction"
);
portletURL.setParameter(
"cmdx""uploadfile"
);
portletURL.setParameter(
"cmd""add"
);
%>


<form name="testForm" method="post" 
action
="<%= portletURL.toString() %>"
 
enctype
="multipart/form-data">

</form>

 

Liferay Portal额外研究(7):修改用户登录首页布局之方案二

ZDNet软件频道 时间:2007-12-15 作者:胡长城 | CSDN 我要评论()
本文关键词:首页布局用户登录修改
Liferay Portal额外研究(7):修改用户登录首页布局之方案二

在第四篇《Liferay Portal额外研究(4):修改用户登录后的默认布局和内容》中,我讲了修改用户登录首页布局的方案,此篇再给提供一种更简洁的处理方案。

        在第四篇的方案,其实有些违背Liferay的扩展本意,Liferay提供了在外围配置的方式,来统一设置用户的第一次默认登陆首页。
        在portal_ext.properties中通过修改相应参数来控制:

# Set the layout name.
default.user.layout.name=Home

# Set the layout template id that matches an existing TPL.
default.user.layout.template.id=2_columns_ii

# Set the layout ids for the column specified in the layout template.
default.user.layout.column-1=82,23,61,65,
default.user.layout.column-2=8,11,36,33,
default.user.layout.column-3=
default.user.layout.column-4=

# Enter either "800x600" or "1024x768" to set the layout resolution.
default.user.layout.resolution=800x600

    可以通过修改“default.user.layout.template.id”属性来控制页面的布局格式;通过修改“default.user.layout.column-X”的属性来控制不同列防止的portlet。

   但如果为了更加符合一些商业性的需求,比如同一个Location的下的user默认布局相同,等等,这些则需要重载ServicePreAction类,重载 addDefaultLayouts 方法来实现,然后再在portal_ext.properties修改相应属性即可。

servlet.service.events.pre=com.liferay.portal.events.ServicePreAction

 

原创粉丝点击