目前正在研究primefaces推送功能。实际上,推送功能正常工作。
这是我的推送流程: 我有两个应用程序共享相同的数据库,管理仪表板(primefaces + spring)和webapi(spring mvc)。当通过webapi将数据插入数据库时,web api将调用将触发所有登录用户的推送通知的管理URL。及其工作正常,如预期的那样。
我的问题是,当有推送通知,然后用户同时注销时(至少通知咆哮没有消失),它将抛出java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
,有时Cannot create a session after the response has been committed
。
我尝试将Login Controller更改为ViewScope,并将此context-param放到web xml中,但仍然无效。
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
请帮助,
这是完整的堆栈跟踪:
SEVERE: Servlet.service() for servlet [facesServlet] in context with path [/WebAdmin] threw exception [java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed] with root cause java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:482) at com.sun.faces.context.ExternalContextImpl.redirect(ExternalContextImpl.java:678) at org.omnifaces.util.FacesLocal.redirect(FacesLocal.java:882) at org.omnifaces.util.Faces.redirect(Faces.java:1170) at com.sepakbole.web.controller.LoginController.doLogout(LoginController.java:84) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.el.parser.AstValue.invoke(AstValue.java:279) at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:273) at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87) at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) at javax.faces.component.UICommand.broadcast(UICommand.java:315) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at com.sepakbole.web.filter.AuthorizationFilter.doFilter(AuthorizationFilter.java:51) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745)
更新 这是我的控制器:
import java.io.Serializable;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import org.primefaces.push.EventBus;
import org.primefaces.push.EventBusFactory;
@ManagedBean
@ApplicationScoped
public class PushMessageController implements Serializable {
private static final long serialVersionUID = 1L;
private String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public void execute(){
EventBus eventBus = EventBusFactory.getDefault().eventBus();
eventBus.publish("/receive-message", data);
}
}
以下是PushEndPoint: import org.primefaces.push.annotation.OnMessage; import org.primefaces.push.annotation.PushEndpoint; import org.primefaces.push.annotation.Singleton; import org.primefaces.push.impl.JSONEncoder;
@PushEndpoint("/receive-message")
@Singleton
public class MessageResource {
@OnMessage(encoders = {JSONEncoder.class})
public String onMessage(String data) {
return data;
}
}
这个放在我的模板上:
<p:socket channel="/receive-message" onMessage="handleMessage"></p:socket>
<p:growl widgetVar="growl-msg" globalOnly="true" id="growl-msg" life="2000" />
<script type="text/javascript">
function handleMessage(facesmessage) {
PF('growl-msg').renderMessage({"summary":"New Message",
"detail":facesmessage,
"severity":"info"})
}
</script>
触发通知,我称之为网址。其中data参数是动态消息,将显示为growl。
http://localhost:5050/WebAdmin/primepushpage/receive-message.jsf?data=Testing123
这是我的receive-message.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="../pages/template.xhtml">
<ui:define name="content">
<f:metadata>
<f:viewParam name="data" value="#{pushMessageController.data}" />
</f:metadata>
<h:form>
<p:remoteCommand name="remoteCommand" actionListener="#{pushMessageController.execute}" autoRun="true" />
</h:form>
</ui:define>
</ui:composition>
这是我的授权过滤器上的doFilter方法:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String loginURL = request.getContextPath() + "/pages/index.jsf";
boolean loggedIn = (session != null) && (session.getAttribute("user") != null);
boolean loginRequest = request.getRequestURI().equals(loginURL);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER + "/");
boolean ajaxRequest = "partial/ajax".equals(request.getHeader("Faces-Request"));
boolean pushRequest = request.getRequestURI().contains("primepush");
if (loggedIn || loginRequest || resourceRequest || pushRequest) {
if (!resourceRequest) { // Prevent browser from caching restricted resources. See also http://stackoverflow.com/q/4194207/157882
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response); // So, just continue request.
}
else if (ajaxRequest) {
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.getWriter().printf(AJAX_REDIRECT_XML, loginURL); // So, return special XML response instructing JSF ajax to send a redirect.
}
else {
if(!response.isCommitted()){
response.sendRedirect(loginURL); // So, just perform standard synchronous redirect.
return;
}
}
}
我在我的web.xml上添加了push servlet映射,我的pom.xml也已经有了大气运行时依赖。我使用Tomcat 7作为容器。
答案 0 :(得分:3)
我有同样的问题。在通过ajax和用户手动刷新页面刷新页面后,我从ocpsoft重写后得到警告:
已提交响应,并且不允许进一步的写入操作。这可能导致底层应用程序触发IllegalStateException。
之后页面处于无效状态,需要第二次刷新。我花了很多时间试图解决这个问题,最后我尝试使用不同版本的氛围运行时(起初我使用了最新的2.4.9)并发现它可以正常使用版本2.4.0直到2.4。 2。
Primefaces手册说你可以使用版本2.3.RC6和最新版本,但版本低于2.4.0我在应用程序启动时遇到了令人讨厌的异常。
我使用Primefaces 6.0,应用程序部署在Tomcat 8.0.39
上