portlet session共享

来源:互联网 发布:java pow方法 编辑:程序博客网 时间:2024/04/30 18:50

一,问题描述
用户会话session是servet规范中标准的对象,它代表了用户活动的生命周期,因此在我们以往的web开发中,经常将用户信息放置到session对象中。然而随着真正意义上的portal时代的到来,portlet的开发让身在其中的人们感到了稍许的不自在,其中很重要的一个因素就是对于session的管理。

在portal中,一个war是一系列portlet的组合,它的意义等价于以前servlet开发中的webapp,因此一个portlets的war就代表了部署在portal server上的一个应用程序,我们又知道在servlet规范中,session的范围是和用户会话相关的,而此会话是相对于具体的某个应用的,即同一个用户登录到不同的web应用后,他的session也是不同的,例如某个用户登录了部署在同一个服务器上的两个web应用:办公自动化系统和财务系统,那么在办公自动化系统中会有该用户的一个sesion,而在财务系统中会有用户的另外一个不同的session。

在portal server中也是这样的,既然不同的portlets war代表不同的应用,那么不同的portlets war之间session也是不同的,即是不能共享的。我想这是我们所能接受的,但是在同一个portlets war中的portlet之间共享session,这应该是个可以达到的基本要求吧,但是对于这一点,不同的portlet规范给出的答案也是不一样的。

下面我们看一下JSR168和IBM Portlet对session问题的回答。

二,不同portlet规范对session问题的回答

1,JSR168方面

JSR168是JCP关于portlet的一个标准,它在自己框架中加入了对session问题的解决方法,在JSR168中,portlet session是可以设置作用范围的,目前有两个作用范围:应用范围(application_scope)和portlet范围(portlet_scope),对于应用范围的session属性,是在同一个portlets war中共享的,而对于portlet范围的session属性,只能是在该portlet具体实例内共享的。如下是JSR168规范中的API:

PortletSession session = request.getPortletSession();

session.setAttribute("attributeName1", "attributeValue1", PortletSession.APPLICATION_SCOPE);
session.setAttribute("attributeName2", "attributeValue2", PortletSession.PORTLET_SCOPE);
session.setAttribute("attributeName3", "attributeValue3");

如上,设置了session属性的范围后,attributeName1是可以在整个portlets war内取到的,而attributeName2只能在该portlet 实例内取到,attributeName3没有设置作用范围,则默认位portlet_scope,因为也只能在该portlet实例内取到。

2,IBM Portlet方面

可以说IBM portlet在同一个portlets war内session的共享做的很不够,在wps4.1中可以通过如下方面解决:在web.xml的servlet定义中,加入下面的参数:

< init-param>
    < param-name> com.ibm.wps.portlet.session< /param-name>
    < param-value> shared< /param-value>
< /init-param>

但是这种共享并不是想象中的在portlets war内共享,而是只有部署在同一个页面中的该war中的portlet实例之间才能共享session,也就是说,即使是同一个portlets war的portlets,如果被部署在不同的页面,那么他们之间的session也是不能共享的,这显然限制很大,没有太大的实际上的意义。

三,实际的portlet项目开发中,该如何解决session的问题

通过前面已经知道,如果使用JSR168开发,则问题基本上可以解决,具体请参看上面的叙述,但是如果使用IBM portlet开发,则需要使用其它方式了。下面介绍的是针对IBM portlet在session方面所做的一种方式,效果还是可以的。

通过查阅相关资料以及进行相关实验,我们最终发现,IBM portlet session基本上只能在具体的 concrete portlet实例(即已经部署到页面中的某个portlet实例)范围内有效,因此我们每个portlet都需要重新组建session,即通过用户标识以及其它一些辅助类,获取用户相关信息并将信息设置到portlet session之中,为了能让每个portlet在做就体逻辑之前就将session信息初始化好,我采用如下的一个方案:

通过IBM portlet规范知道,每个concrete portlet可以定义他的视图默认页面,我们一般定义为某个路径下的index.jsp,因为到index.jsp的时候,portlet的其它逻辑还没有执行,因此此时是获取用户相关数据并存放到portlet session中的好时机,如下:


<%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI"%>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<portletAPI:init/>
<%
//获取相关数据放置到session属性中。
com.ibm.portal.puma.User portalUser= (com.ibm.portal.puma.User) portletRequest.getUser();
String userId=portalUser.getUserID();
session.setAttribute("userId",userId);
String department=new UserManager().getUserDepartmentBySn(userId);
session.setAttribute("department",department);
//准备完session信息后,导向到具体的应用逻辑页面。
portletConfig.getContext().include("next.jsp",portletRequest,portletResponse);
%>
按照上面的方式,原来需要在HttpSession存储的信息,现在每个需要这些信息的portlet都自己去后台取一次,然后设置到自己的PortletSession之中。这种方式虽然感觉笨了一些,但至少是一种解决方式,可以尝试一下,还是不错的。

四,从portlet session问题看portal

portlet session的问题可能是不少人所不能理解的,为什么用户登录portal后,他所看到的东西可能不是在同一个session范围内,为什么同一个用户看到的不同的portlet可能会属于不同的session。其实这涉及到对portal的理解问题。

portal我们知道是门户的意思,也知道上面是一个个的portlet应用,每个portlet可能代表着一个不同的应用,这里的应用和上面说的应用可能概念还不太一样,这里的应用主要是指业务。

另外我们知道portlet有自己的规范,只要按照规范开发出的portlet,则就可以部署到portal server之中,那么在portal server中,很有可能包含了各种各样的portlet,有些portlet是同一个业务的,而另外一些portlet是为另一个业务的,请注意一点,portal server中的这些业务,并不一定只包含你自己做的,或你们公司自己做的,也有可能包含各个厂商自己已经做好的,还有可能客户后来又新添加的。

这样一来,如果不同业务或风马牛不相及的业务之间可以共享session的话,那么很可能会引起session的混乱,例如厂家A的portlet在session中设置了company属性为company_A,而厂家B的portlet在session中设置了company属性为company_B,如果session是在用户登录后的所有portlet之间共享的话,那么就会引起数据混乱,而导致严重的业务问题。

基于此,portal server中提出了portlets应用的概念(portlet war),一个portlets 应用就是一组portlets,这些portlets被打成一个符合portal要求的war包,然后可以部署到portal server之中。在portal server中,portal会将每个portlet应用看作是一个独立的应用,就好像是Tomcat下的webapps中的应用一样,也许你觉得将portlets 应用看作是web应用很难,但你想一想,一个portlets应用中,包含了一个web应用所有的东西,有独立的web.xml,有独立的lib和classes以及tld等等,只能说portlet应用不仅是一个web应用,而且是一个实现了portlet功能的更为强大的web应用。

我们知道一个portal server中可以部署多个这样的portlet 应用,这实际上就相当于在一个portal server中部署了多个web应用,再想下去你可能会觉得非常惊叹:既然不同的portlet war是不同的web应用(就像tomcat webapps下的应用一样),那么我们登录portal后,实际上看到的是多个web应用的聚合,不知你是否理解我现在说的,你想想以前访问tomcat时,我们一般都是通过某个context path然后访问到webapps下的具体应用,但是你是否想过如果将webapps下的所有应用在一个系统在内聚合访问,那将是怎样的一番景象呢!portal做的就是这个!

因此portets 应用(portlets war)之间不能共享session是理所当然的,就好像tomcat webapps下的不同应用不能共享session是一个道理,当然同一个portlets应用内(即同一个web应用内)共享session这应该是被支持的,JSR168做的就很好,IBM的portlet在这方面真是有些问题。

基于此我们再理解一下Websphere中的server1和WebSphere_Portal两个服务器,我们以前可能会奇怪,为什么我们可以直接在server1部署web应用程序,然后通过url进行访问,而WebSphere_Portal中却不可以部署web应用程序然后通过url访问呢,现在可以告诉你,server1部署的web应用是符合servlet标准的web应用,或者说是普通的web应用,而再WebSphere_Portal中实际上也可以部署web应用,只是只能部署较为特殊的一种web应用,即portlets应用。另外我们在Websphere控制台中只能部署企业级应用程序(包括普通的web应用),我们在里面找不到可以部署portlet这种特殊web应用的地方,实际上我们都清楚,portlet应用的部署是在portal的管理短实现的,而不是在websphere的控制台中.