【发布时间】:2017-03-15 04:16:07
【问题描述】:
目前我正在研究 primefaces 推送功能。实际上,推送功能工作正常。
这是我的推送流程: 我有两个共享相同数据库的应用程序,管理仪表板(primefaces + spring)和 webapi(spring mvc)。当有数据通过 webapi 插入数据库时,web api 将调用管理 url,该 url 将触发为所有登录用户推送通知。正如预期的那样,它的工作正常。
我的问题是,当有推送通知时,然后用户同时注销(至少通知咆哮没有消失)它会抛出java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed,有时会抛出Cannot create a session after the response has been committed。
我尝试将登录控制器更改为 ViewScope,并将此上下文参数放入 web xml,但仍然无法正常工作。
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
请帮忙,
这是完整的堆栈跟踪:
严重:servlet [facesServlet] 的 Servlet.service() 在路径 [/WebAdmin] 的上下文中抛出异常 [java.lang.IllegalStateException:在响应提交后无法调用 sendRedirect()],根本原因 java.lang.IllegalStateException:提交响应后无法调用 sendRedirect() 在 org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:482) 在 com.sun.faces.context.ExternalContextImpl.redirect(ExternalContextImpl.java:678) 在 org.omnifaces.util.FacesLocal.redirect(FacesLocal.java:882) 在 org.omnifaces.util.Faces.redirect(Faces.java:1170) 在 com.sepakbole.web.controller.LoginController.doLogout(LoginController.java:84) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:606) 在 org.apache.el.parser.AstValue.invoke(AstValue.java:279) 在 org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:273) 在 com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) 在 javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87) 在 com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) 在 javax.faces.component.UICommand.broadcast(UICommand.java:315) 在 javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790) 在 javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282) 在 com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) 在 com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) 在 com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198) 在 javax.faces.webapp.FacesServlet.service(FacesServlet.java:658) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 com.sepakbole.web.filter.AuthorizationFilter.doFilter(AuthorizationFilter.java:51) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) 在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) 在 org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442) 在 org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082) 在 org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623) 在 org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 在 org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 在 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: 导入 org.primefaces.push.annotation.OnMessage; 导入 org.primefaces.push.annotation.PushEndpoint; 导入 org.primefaces.push.annotation.Singleton; 导入 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>
为了触发通知,我调用了这个 url。其中data参数为动态消息,会显示为咆哮声。
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 上添加了推送 servlet 映射,我的 pom.xml 也已经具有大气运行时依赖项。我使用 Tomcat 7 作为容器。
【问题讨论】:
-
您的通知代码在哪里?
-
嗨@javaguy 感谢您的回复。通知代码在我上面的帖子中更新。请帮忙
标签: jsf primefaces push