Session Bean在使用JSF和Primefaces的GAE中丢失

时间:2013-02-06 23:26:52

标签: google-app-engine jsf-2 primefaces

请注意,在文件appengine-web.xml中有所需的:

<sessions-enabled>true</sessions-enabled>

我一直在挖掘如何使jsf和会话bean在谷歌应用引擎上运行很长一段时间。问题是如果我在web.xml文件中使用,那么bean会在每次请求时丢失:

<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>

这使得在本地开发中在客户端的页面中创建一个隐藏字段,该字段在base64中对视图状态进行编码。

<input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState"
value="H4sIAAAAAAAAAE1QO0sDQRAe73LxLTGClelsLDwQLEQLDWjwMD4QFMFCN3drcmHv9txHcmcRSKOFjYUWFqKFZf6EWNgJWlqJvbWtuyEmDuwwuzPzPbb1DVbEGYxXUQ3ZUvjEXke8sokiq//j6Xny+M0EowBDhCKvgFxBmQODosIwr1DixdHyCugYqQ+onFHHFDDl0sDmMrRPkIu5vZqEKPDdvCt8GnLFNdHjyjOGkqLPRdx8z92+oDsT+hxIcf8Mx5EGrqd0jgWMVo98T8wvKmZJhFQoh8U2DkFh2d4uVbErlq5eD+4zfIYYakWvpyIVAiy9OydPoQFp9Wp0K0v3uzezwWBWY8Yd5cpHREMcCnvP2fdxfZdSMb3DaISZSDZwwqETWcXHYKynZy2Uwf+mEpEmiAvH6/51e84JBS5jlv16ePxpXiwY2r1VQ0RihZfpzW3JoITZeesmN3z9eflnT8mPfwGGpwEXwQEAAA==" autocomplete="off" />

据说在谷歌服务器上会是一样的。但结果似乎很奇怪。

<input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState"
value="-7485706817535542099:-1131777842892951150" autocomplete="off" />

如果我使用:

<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>

谷歌应用引擎产生一个字符串出界错误不知道为什么。这是:

/Trainer.jsf
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
    at java.lang.String.substring(String.java:1949)
    at com.sun.faces.renderkit.ServerSideStateHelper.getState(ServerSideStateHelper.java:277)
    at com.sun.faces.renderkit.ResponseStateManagerImpl.getState(ResponseStateManagerImpl.java:100)
    at com.sun.faces.application.view.FaceletPartialStateManagementStrategy.restoreView(FaceletPartialStateManagementStrategy.java:352)
    at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:138)
    at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:123)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:518)
    at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:142)
    at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:192)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:116)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.google.apphosting.utils.servlet.ParseBlobUploadFilter.doFilter(ParseBlobUploadFilter.java:125)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:35)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:266)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
    at com.google.apphosting.runtime.jetty.RpcRequestParser.parseAvailable(RpcRequestParser.java:76)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:146)
    at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:447)
    at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:454)
    at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:461)
    at com.google.tracing.TraceContext.runInContext(TraceContext.java:703)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:338)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:330)
    at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:458)
    at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:251)
    at java.lang.Thread.run(Thread.java:679)

问题是该应用程序在本地开发服务器中运行良好。

我正在使用GAE-1.7.4。

以下是我到目前为止所阅读的一些内容,并没有得到确凿的答案:

  1. http://consultingblogs.emc.com/jaddy/archive/2009/11/20/jsf2-in-google-app-engine.aspx
  2. JSF2 with GAE and ViewScoped ManagedBean
  3. Session Bean being lost?
  4. 希望这不是一些愚蠢的情况。 提前谢谢。

    更新1: 我得出结论,使用:

    FacesContext context = FacesContext.getCurrentInstance();
    context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, "Warning building CardController", null));
    

    没有在每个单页请求中创建会话bean,但由于某些未知原因,这些值被设置为默认值。我开始认为最好使用cookie并将它们重新加载到bean中,作为每个页面请求的修复。我没有看到任何其他方法。可能是我会使用AES来加密一些cookie以获得额外的安全性。

    更新2: 再次尝试以下内容:

    import java.io.Serializable;
    import java.util.Arrays;
    import java.util.List;
    
    import javax.faces.context.FacesContext;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.collections.Predicate;
    
    import com.google.gson.Gson;
    
    @SuppressWarnings("serial")
    public class Counter implements Serializable{
    
    public int counter;
    
    public Counter() {
        counter = -1;
    }
    
    public String getCounter(){
        counter++;
        return counter+"";
    }
    
    
    
    
    public String getSetCounter(){
        Gson gson = new Gson();
        HttpServletResponse res = (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
        Cookie cookie = new Cookie(this.hashCode()+"",gson.toJson(this));
        cookie.setMaxAge(60*60); //1 hour
        res.addCookie(cookie);
        return "Write Counter";
    }
    
    public String getReadCounter(){
        Gson gson = new Gson();
        Cookie cookieJSON = getCookie();
        if(cookieJSON!=null){
            Counter counter = gson.fromJson(cookieJSON.getValue(), Counter.class);
            this.counter = counter.counter;
        }
        return "Read Counter";
    }
    
    private Cookie getCookie(){
        HttpServletRequest req = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
        Cookie[] cookies = req.getCookies();
        Cookie cookieJSON = null;
        if(cookies!=null){
            List<Cookie> cookiesList = Arrays.asList();
            cookieJSON = (Cookie) CollectionUtils.find(cookiesList, new Predicate() {
                @Override
                public boolean evaluate(Object cookie) {
                    return ((Cookie)cookie).getName().equals(Counter.this.hashCode()+"");
                }
            });
        }
        return cookieJSON;
    }
    
    }
    

    在facelet的.xhtml中

    <h:outputText value="#{counter.readCounter}"/>
    <br />
    <h:outputText value="#{counter.counter}"/>
    <br />
    <h:outputText value="#{counter.setCounter}"/>
    

    没有结果,数据将无法通过会话或cookie保存。

    更新3:

    “不支持 由于各种原因,App Engine目前不支持各种API和技术。其中包括:

    Enterprise Java Beans(EJB)“

    http://code.google.com/p/googleappengine/wiki/WillItPlayInJava

    使用java bean测试会话变量,它可以正常工作。

    更新4:

    你不能在GAE中只是将一个对象写入会话,因为它的属性值会丢失。我怀疑EJB是这样做的。也许他们可以使用我不知道的JSON序列化对象。我相信这是一个解决方法。我在:

    中添加了一个询问此功能的主题
    https://community.jboss.org/thread/221125?tstart=0
    

    不确定这是否是负责为jboss开发EJB的小组,但是......如果你想要这个功能,你可能会在该主题中产生一些噪音。

0 个答案:

没有答案