二、liferay中的实现
liferay在构建actionrequestimpl和renderrequestimpl时,会设置portlet session,如下代码所示:public renderrequestimpl(httpservletrequest req, portlet portlet, cacheportlet cacheportlet, portletcontext portletctx, windowstate windowstate, portletmode portletmode, portletpreferences prefs, string layoutid) { … _req = dynamicreq; _portlet = portlet; _cacheportlet = cacheportlet; _portalctx = new portalcontextimpl(); _portletctx = portletctx; _windowstate = windowstate; _portletmode = portletmode; _prefs = prefs; _ses = new portletsessionimpl( _req.getsession(), _portletname, _portletctx); … }从兰色的部分( _ses = new portletsessionimpl(_req.getsession(),_portletname, _portletctx); )我们可以看到,这个portlet session其实就是portal system的 session 对象。所以无论request调用getsession()或者getportletsession()都将获取portal 系统的session 对象,而无论该portlet 是或者不是属于portal system上下文。而且即使不同portal application的portlet也将使用同一个session 对象(portal 系统)。也就是说,对于某一个portlet来说,如果有对其的session进行的操作,并没有真正的在该application上下文中的session进行操作,而是在portal系统上下文的session中进行操作。
而且liferay提供getportletsession来获取portletsession对象,而不是getsession()方法,所以即使getportletsession()可以获取正确的session对象,开发人员由于习惯问题,也因使用getsession()而得不到。
另外如果调用request.getsession(true)还可能会出现错误,因为liferay在包含某一个portlet内容是,调用portletrequestdispatcherimpl.include()方法,该方法将生成portletservletrequest 和portletservletresponse,请见如下代码:
portletservletrequest portletservletreq = new portletservletrequest( httpreq, reqimpl, pathinfo, querystring, requesturi, servletpath);
portletservletresponse portletservletres = new portletservletresponse( resimpl.gethttpservletresponse(), resimpl);而portletservletrequest的构造函数是如下定义的:public portletservletrequest(httpservletrequest req, renderrequest renderrequest, string pathinfo, string querystring, string requesturi, string servletpath) {
super(req);
_ses = req.getsession(); _renderrequest = renderrequest; _pathinfo = pathinfo; _querystring = querystring; _requesturi = requesturi; _servletpath = servletpath; }所以其session依然是portal系统上下文的。然后问题就出在这里,portletservletrequest实现了getsession()方法,但是没有实现getsession(boolen create)方法,如果用户在此阶段调用getsession(true)的话,在某些情况下就会抛出nullpointerexception
原因见如下代码(请注意我添加的注释部分)//applicationhttprequest:
public httpsession getsession(boolean create) {
if (crosscontext) { // there cannot be a session if no context has been assigned yet if (context == null) return (null);
// return the current session if it exists and is valid if (session != null) return (session.getsession()); // 我的注释:这里将获取portal系统的session对象。 httpsession other = super.getsession(false); if (create && (other == null)) { // first create a session in the first context: the problem is // that the top level request is the only one which can // create the cookie safely other = super.getsession(true); } if (other != null) { session localsession = null; try { // 我的注释:this context did not have the session with session id. it can just be found in the portal // context. so here it will return a null value. localsession = context.getmanager().findsession(other.getid()); localsession.access(); //我的注释:here, localsession is null. so it throws a nullpointexception. } catch (ioexception e) { // ignore } if (localsession == null) { localsession = context.getmanager().createemptysession(); localsession.setnew(true); localsession.setvalid(true); localsession.setcreationtime(system.currenttimemillis()); localsession.setmaxinactiveinterval (context.getmanager().getmaxinactiveinterval()); localsession.setid(other.getid()); } session = localsession; return session.getsession(); } return null;
} else { return super.getsession(create); }
}
