自定义PhaseListener:应在哪个阶段终止用户会话?
问题解答
一、PhaseListener终止会话的阶段与时机选择
推荐在**PhaseID.RESTORE_VIEW阶段的beforePhase方法**中执行会话终止逻辑,理由如下:
RESTORE_VIEW是JSF请求处理的首个阶段,此时尚未启动任何页面相关的业务逻辑处理,完全匹配你“与页面无关的特殊系统条件”的需求,能避免后续阶段执行时引发不必要的资源加载或逻辑执行异常。- 选择
beforePhase而非afterPhase:在RESTORE_VIEW的before阶段,会话仍处于有效状态,可正常调用request.logout()和session.invalidate();若等到after阶段执行,视图恢复流程已启动,部分资源可能已被初始化,此时终止会话容易导致视图处理异常。
二、Servlet过滤器解决数据库连接重复建立的问题
Servlet过滤器被多次调用通常是因为静态资源(如CSS、JS、图片)请求也会触发过滤器。可通过以下方式解决:
1. 仅对JSF请求执行连接逻辑
判断当前请求是否指向JSF的FacesServlet(通常映射为*.xhtml,需匹配你项目中的实际配置),仅在这类请求中建立数据库连接:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String servletPath = httpRequest.getServletPath(); // 根据项目中FacesServlet的映射调整判断条件 boolean isFacesRequest = servletPath.endsWith(".xhtml"); if (isFacesRequest) { // 建立数据库连接 // ... 你的连接初始化代码 } try { chain.doFilter(request, response); } finally { if (isFacesRequest) { // 关闭数据库连接 // ... 你的连接关闭代码 } } }
2. 结合请求属性标记连接状态
通过请求属性记录是否已建立连接,避免同一请求多次触发连接逻辑(可结合上面的JSF请求判断进一步优化):
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { final String CONNECTION_MARKER = "dbConnectionEstablished"; HttpServletRequest httpRequest = (HttpServletRequest) request; boolean isFacesRequest = httpRequest.getServletPath().endsWith(".xhtml"); if (isFacesRequest && request.getAttribute(CONNECTION_MARKER) == null) { // 建立数据库连接 // ... 你的连接初始化代码 request.setAttribute(CONNECTION_MARKER, true); } try { chain.doFilter(request, response); } finally { if (isFacesRequest && request.getAttribute(CONNECTION_MARKER) != null) { // 关闭数据库连接 // ... 你的连接关闭代码 request.removeAttribute(CONNECTION_MARKER); } } }
内容的提问来源于stack exchange,提问作者Toru
相关产品推荐
相关产品推荐

