如何访问 Liferay portlet 请求中 JSF bean 中的 servlet 会话属性?
How to access servlet session attributes within a JSF bean inside a Liferay portlet request?
在 Liferay 6.2.10 和 Liferay-Faces-Bridge 3.2.4 中,是否可以在不使用 <private-session-attributes>false</private-session-attributes>
的情况下仅将单个属性写入原始会话 ?
- 在 JSF-bean / portlet 中,我们配置了一个必须可通过 servlet 下载的导出文件(在同一个 WAR 中)。
- 我们想通过会话共享一个特定的对象,以供门户内部的一些 JSTL 魔法使用。
除了设置 <private-session-attributes>false</private-session-attributes>
,我没有找到其他方法,但这会用大量 JSF 特定对象甚至更多特定于 portlet 的对象污染会话,而这些对象在用户全局会话中是不需要的。由于 war 中的大多数 portlet 需要通信,我要么必须全部切换到 public 会话属性,要么使用 IPC。
我尝试了几种在不使用私有会话属性的情况下只产生积极结果的方法。
ServiceContextThreadLocal.getServiceContext().getRequest().getSession().setAttribute("SERVICE_CONTEXT", true);
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
// Does not matter which way
// PortletSession portletSession = (PortletSession)externalContext.getSession(false);
PortletSession portletSession = ((PortletRequest) externalContext.getRequest()).getPortletSession();
portletSession.setAttribute("PORTLET_SESSION_PORTLET_SCOPE", true, PortletSession.PORTLET_SCOPE);
portletSession.setAttribute("PORTLET_SESSION_APPLICATION_SCOPE", true, PortletSession.APPLICATION_SCOPE);
HttpServletRequest httpServletRequest = PortalUtil.getHttpServletRequest((PortletRequest) externalContext.getRequest());
httpServletRequest.getSession().setAttribute("EXTERNAL_CONTEXT_SERVLET_REQUEST_SESSION", true);
HttpServletRequest outerRequest = PortalUtil.getOriginalServletRequest(httpServletRequest);
outerRequest.getSession().setAttribute("EXTERNAL_CONTEXT_SERVLETS_SERVLET_REQUEST", true);
我想避免的其他选项是:
- 使用
javax.servlet.Filter
和 ThreadLocal
- 将生成的文档(或导出配置)保存到数据库
- 通过客户端将配置重新发布到导出 servlet 来传输配置。
此 answer 建议使用带有 ApplicationScoped 变量的 portletSession,但我无法获取 PortletSession。
通过设置 <private-session-attributes>false</private-session-attributes>
,我在原始会话中设置了以下属性:
- TEST_WITH_EXTERNAL_CONTEXT_SERVLET_REQUEST_SESSION
- TEST_WITH_PORTLET_SESSION_APPLICATION_SCOPE
- TEST_WITH_SERVICE_CONTEXT
- war_app_name_whatever?TEST_WITH_PORTLET_SESSION_PORTLET_SCOPE
以及 全局 用户会话中可见的大量其他对象 (>50)。
谁知道如何只设置一个会话属性?
解包请求直到到达不扩展 javax.servlet.http.HttpServletRequestWrapper
的 class 即可解决问题。
请求由 Liferay 保存并可通过 ServiceContextThreadLocal.getServiceContext().getRequest()
获得。
如果请求包装器位于以 "com.liferay."
开头的包中,Liferays PortalUtil
只会解包,因此如果使用自定义请求包装器则不起作用。
public static <Type, ValueType extends Type> void setOnOriginalSession(Class<Type> type, ValueType value) {
HttpServletRequest request = ServiceContextThreadLocal.getServiceContext().getRequest();
HttpServletRequest originalRequest = unwrapOriginalRequest(request);
HttpSession originalSession = originalRequest.getSession();
String attributeNameForType = getAttributeNameForType(type);
originalSession.setAttribute(attributeNameForType, value);
}
private static HttpServletRequest unwrapOriginalRequest(HttpServletRequest request) {
while (request instanceof HttpServletRequestWrapper) {
HttpServletRequestWrapper httpServletRequestWrapper = (HttpServletRequestWrapper) request;
request = (HttpServletRequest) httpServletRequestWrapper.getRequest();
}
return request;
}
在 Liferay 6.2.10 和 Liferay-Faces-Bridge 3.2.4 中,是否可以在不使用 <private-session-attributes>false</private-session-attributes>
的情况下仅将单个属性写入原始会话 ?
- 在 JSF-bean / portlet 中,我们配置了一个必须可通过 servlet 下载的导出文件(在同一个 WAR 中)。
- 我们想通过会话共享一个特定的对象,以供门户内部的一些 JSTL 魔法使用。
除了设置 <private-session-attributes>false</private-session-attributes>
,我没有找到其他方法,但这会用大量 JSF 特定对象甚至更多特定于 portlet 的对象污染会话,而这些对象在用户全局会话中是不需要的。由于 war 中的大多数 portlet 需要通信,我要么必须全部切换到 public 会话属性,要么使用 IPC。
我尝试了几种在不使用私有会话属性的情况下只产生积极结果的方法。
ServiceContextThreadLocal.getServiceContext().getRequest().getSession().setAttribute("SERVICE_CONTEXT", true);
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
// Does not matter which way
// PortletSession portletSession = (PortletSession)externalContext.getSession(false);
PortletSession portletSession = ((PortletRequest) externalContext.getRequest()).getPortletSession();
portletSession.setAttribute("PORTLET_SESSION_PORTLET_SCOPE", true, PortletSession.PORTLET_SCOPE);
portletSession.setAttribute("PORTLET_SESSION_APPLICATION_SCOPE", true, PortletSession.APPLICATION_SCOPE);
HttpServletRequest httpServletRequest = PortalUtil.getHttpServletRequest((PortletRequest) externalContext.getRequest());
httpServletRequest.getSession().setAttribute("EXTERNAL_CONTEXT_SERVLET_REQUEST_SESSION", true);
HttpServletRequest outerRequest = PortalUtil.getOriginalServletRequest(httpServletRequest);
outerRequest.getSession().setAttribute("EXTERNAL_CONTEXT_SERVLETS_SERVLET_REQUEST", true);
我想避免的其他选项是:
- 使用
javax.servlet.Filter
和ThreadLocal
- 将生成的文档(或导出配置)保存到数据库
- 通过客户端将配置重新发布到导出 servlet 来传输配置。
此 answer 建议使用带有 ApplicationScoped 变量的 portletSession,但我无法获取 PortletSession。
通过设置 <private-session-attributes>false</private-session-attributes>
,我在原始会话中设置了以下属性:
- TEST_WITH_EXTERNAL_CONTEXT_SERVLET_REQUEST_SESSION
- TEST_WITH_PORTLET_SESSION_APPLICATION_SCOPE
- TEST_WITH_SERVICE_CONTEXT
- war_app_name_whatever?TEST_WITH_PORTLET_SESSION_PORTLET_SCOPE
以及 全局 用户会话中可见的大量其他对象 (>50)。
谁知道如何只设置一个会话属性?
解包请求直到到达不扩展 javax.servlet.http.HttpServletRequestWrapper
的 class 即可解决问题。
请求由 Liferay 保存并可通过 ServiceContextThreadLocal.getServiceContext().getRequest()
获得。
如果请求包装器位于以 "com.liferay."
开头的包中,Liferays PortalUtil
只会解包,因此如果使用自定义请求包装器则不起作用。
public static <Type, ValueType extends Type> void setOnOriginalSession(Class<Type> type, ValueType value) {
HttpServletRequest request = ServiceContextThreadLocal.getServiceContext().getRequest();
HttpServletRequest originalRequest = unwrapOriginalRequest(request);
HttpSession originalSession = originalRequest.getSession();
String attributeNameForType = getAttributeNameForType(type);
originalSession.setAttribute(attributeNameForType, value);
}
private static HttpServletRequest unwrapOriginalRequest(HttpServletRequest request) {
while (request instanceof HttpServletRequestWrapper) {
HttpServletRequestWrapper httpServletRequestWrapper = (HttpServletRequestWrapper) request;
request = (HttpServletRequest) httpServletRequestWrapper.getRequest();
}
return request;
}