JSF会话超时重定向时如何避免javax.servlet.ServletException异常
问题根因
你当前的写法只通知了JSF无需执行后续的渲染响应阶段,但没有终止当前执行栈的代码逻辑,会话超时后未完成初始化的Bean属性被页面EL表达式解析时就会触发空指针异常,错误日志也随之生成。
解决方案
按优先级从高到低提供3种可行方案:
方案1:全局过滤器实现会话超时校验(最推荐)
直接在Servlet层做超时拦截,根本不会进入JSF生命周期,从根源避免后续EL渲染的问题,适合全局统一的会话超时控制:
import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebFilter(urlPatterns = "/*", asyncSupported = true) public class SessionTimeoutFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; String contextPath = req.getContextPath(); // 放行公共资源、登录页等无需校验的路径 String requestUri = req.getRequestURI(); if (requestUri.startsWith(contextPath + "/login") || requestUri.startsWith(contextPath + "/public/")) { chain.doFilter(request, response); return; } // 会话校验逻辑 HttpSession session = req.getSession(false); if (session == null || session.getAttribute("loginUser") == null) { resp.sendRedirect(contextPath + "/login.xhtml?timeout=1"); return; } chain.doFilter(request, response); } }
方案2:修正Backing Bean内的重定向写法
如果必须在Backing Bean内做超时判断,使用JSF原生的重定向API,执行后立刻终止当前方法执行:
import javax.faces.context.FacesContext; import javax.faces.application.ResponseCompleteException; // 会话超时判断逻辑 if (sessionExpired) { FacesContext facesContext = FacesContext.getCurrentInstance(); String redirectUrl = facesContext.getExternalContext().getRequestContextPath() + "/login.xhtml"; // 原生redirect方法会自动设置302状态、Location头,自动调用responseComplete facesContext.getExternalContext().redirect(redirectUrl); // 无返回值的方法(比如@PostConstruct)直接抛ResponseCompleteException终止流程 throw new ResponseCompleteException(); // 有返回值的动作方法直接return null即可,无需抛异常 // return null; }
如果你的项目使用PrimeFaces,可使用同时兼容普通请求和Ajax请求的写法:
import org.primefaces.context.RequestContext; if (sessionExpired) { RequestContext.getCurrentInstance().redirect(redirectURL); throw new ResponseCompleteException(); }
方案3:临时规避错误日志
如果暂时无法调整业务逻辑,可以在日志配置中过滤掉该类会话超时触发的NPE,避免无效告警。但该方案只是临时规避,优先选择前两种方案从根源解决问题。
内容的提问来源于stack exchange,提问作者John Hammond
相关产品推荐
相关产品推荐

