问题描述:
JSF前端页面,长期放置未操作之后再触发一个ajax请求,页面毫无反应,且在控制台报错
问题解析:
由于很久没处理页面,当前的session过期之后,导致的ViewExpiredException。
你触发事件或者ajax请求时,无法触发页面跳转,所以页面停留在这里,并且Session过期导致在JSF第一个Phase的时候出错,于是任何操作也不能进行。
一般的,只要:关闭浏览器或者清一下Session重新开始一次session应该就没事了。
解决方案:
作为开发,我们能很快的看到Console里的异常,并且知道发生了什么。对于用户,就会觉得莫名其妙,所以需要一个拦截器对此进行拦截,并且跳转到Error界面,提示用户重新登录。
具体解决代码(参考了国外论坛):
import java.io.IOException;
import java.util.Iterator;
import javax.faces.FacesException;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TwoExceptionHandler extends ExceptionHandlerWrapper {
protected Logger log = LoggerFactory.getLogger(TwoExceptionHandler.class);//if not necessary remove it
private ExceptionHandler wrapped;
public TwoExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
@Override
public ExceptionHandler getWrapped() {
return this.wrapped;
}
@Override
public void handle() {
for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
ExceptionQueuedEvent event = i.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
Throwable t = context.getException();
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
try {
if (t instanceof ViewExpiredException) {
// redirectPage =
// (String) ec.getRequestMap().get(AuthenticationFilterEntryPoint.ATTRIBUTE_SESSIONTIMEOUT_PAGE);
// ec.redirect(ec.getRequestContextPath() + redirectPage);
ec.redirect(ec.getRequestContextPath() + "/sessionExpired.xhtml");
} else {
//ec.redirect(ec.getRequestContextPath() + "/serverError.xhtml");
}
} catch (IOException e) {
throw new FacesException(e);
} finally {
log.error("Error occurs: {}", t);
i.remove();
}
}
// At this point, the queue will not contain any ViewExpiredEvents.
// Therefore, let the parent handle them.
getWrapped().handle();
}
}
TwoExceptionHandlerFactory.java
package org.cy.web;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;
public class TwoExceptionHandlerFactory extends ExceptionHandlerFactory{
private ExceptionHandlerFactory parent;
public TwoExceptionHandlerFactory(ExceptionHandlerFactory parent) {
this.parent = parent;
}
@Override
public ExceptionHandler getExceptionHandler() {
ExceptionHandler eh = parent.getExceptionHandler();
return new TwoExceptionHandler(eh);
}
}
webapp/WEB-INF/faces-config.xml
<factory>
<exception-handler-factory>
org.cy.training.web.TwoExceptionHandlerFactory
</exception-handler-factory>
</factory>
webapp/sessionExpired.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>SessionExpired</title>
</head>
<body>
<H1>Session Expired,sir</H1>
</body>
</html>