会话在GWT RPC调用中到期后如何重定向到登录页面

时间:2010-09-07 09:55:28

标签: gwt rpc

我在我的应用中使用GWT和RPC。会话到期后,当我进行RPC调用时,由于我的登录过滤请求重定向到login.jsp,但我的问题是客户端没有显示login.jsp而不是RPC的onFailure引发。

这意味着我应该处理所有rpc的onFailure事件,以便重定向到登录页面?!!!!

由于

8 个答案:

答案 0 :(得分:21)

我同意pathed您应该在AsyncCallback中重定向。但是,您无需明确使用自定义MyAsyncCallback回调而非标准GWT AsyncCallback。这很重要,例如,当您已经有很多使用标准回调的代码时。

当您调用GWT.create(MyService.class)时,GWT会为您的MyServiceAsync服务接口生成代理。此代理负责与服务器通信,并在从服务器获取数据时调用您的回调。使用GWT code generators mechanism生成代理,默认情况下,GWT使用ServiceInterfaceProxyGenerator类生成这些代理。

您可以扩展此默认生成器(ServiceInterfaceProxyGenerator类),以在所有回调调用中自动使用自定义MyAsyncCallbacks 。我们最近在一个项目中做到了这一点。下面是我们使用的源代码。

MyAsyncCallback的代码,与pathed提供的代码相同:

package my.package.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public class MyAsyncCallback<T> implements AsyncCallback<T> {

    private final AsyncCallback<T> asyncCallback;

    public MyAsyncCallback(AsyncCallback<T> asyncCallback) {
        this.asyncCallback = asyncCallback;
    }

    @Override
    public void onFailure(Throwable caught) {
        if (caught instanceof SessionTimeoutException) {
            // redirect
            return;
        }

        asyncCallback.onFailure(caught);
    }

    @Override
    public void onSuccess(T result) {
        asyncCallback.onSuccess(result);
    }

}

GWT代码生成器代码(MyRpcRemoteProxyGenerator):

package my.package.server;

import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.user.rebind.rpc.ProxyCreator;
import com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator;

public class MyRpcRemoteProxyGenerator extends ServiceInterfaceProxyGenerator {

    @Override
    protected ProxyCreator createProxyCreator(JClassType remoteService) {
        return new MyProxyCreator(remoteService);
    }
}

生成器助手类(MyProxyCreator):

package my.package.server;

import java.util.Map;

import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.user.rebind.SourceWriter;
import com.google.gwt.user.rebind.rpc.ProxyCreator;
import com.google.gwt.user.rebind.rpc.SerializableTypeOracle;


public class MyProxyCreator extends ProxyCreator {

    private final String methodStrTemplate = "@Override\n"
            + "protected <T> com.google.gwt.http.client.Request doInvoke(ResponseReader responseReader, "
            + "String methodName, int invocationCount, String requestData, "
            + "com.google.gwt.user.client.rpc.AsyncCallback<T> callback) {\n"
            + "${method-body}" + "}\n";

    public MyProxyCreator(JClassType serviceIntf) {
        super(serviceIntf);
    }

    @Override
    protected void generateProxyMethods(SourceWriter w,
            SerializableTypeOracle serializableTypeOracle,
            Map<JMethod, JMethod> syncMethToAsyncMethMap) {
        // generate standard proxy methods
        super.generateProxyMethods(w, serializableTypeOracle,
                syncMethToAsyncMethMap);

        // generate additional method
        overrideDoInvokeMethod(w);
    }

    private void overrideDoInvokeMethod(SourceWriter w) {
        StringBuilder methodBody = new StringBuilder();
        methodBody
                .append("final com.google.gwt.user.client.rpc.AsyncCallback newAsyncCallback = new my.package.client.MyAsyncCallback(callback);\n");
        methodBody
                .append("return super.doInvoke(responseReader, methodName, invocationCount, requestData, newAsyncCallback);\n");

        String methodStr = methodStrTemplate.replace("${method-body}",
                methodBody);
        w.print(methodStr);
    }

}

最后,您需要注册新代码生成器,以用于生成异步服务的代理。这可以通过将其添加到GWT配置文件(gwt.xml文件)来完成:

<generate-with
    class="my.package.server.MyRpcRemoteProxyGenerator">
    <when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService" />
</generate-with>

一开始看起来似乎是一个非常复杂的解决方案:)但它有其优势:

  • 您仍然可以使用标准GWT AsyncCallback s
  • 您可以强制重新定向会话超时全局为您的应用程序
  • 您可以轻松地打开和关闭它(通过在GWT配置文件中添加或删除generate-with

答案 1 :(得分:5)

是的,您应该在onFailure中处理会话超时(在我看来)。但有一些简单的方法可以做到这一点。

  1. 实现您自己的异步回调。

    public abstract class MyAsyncCallback<T> implements AsyncCallback<T> {
    
    @Override
    public void onFailure(Throwable arg0) {
        if arg0 is SessionTimeout
            redirect to loginpage
        else
            failure(Throwable ar0)
    }
    
    @Override
    public void onSuccess(T arg0) {
        success(arg0);
    }
    
    public abstract void success(T arg0);
    
    public abstract void failure(Throwable arg0);
    

    }

  2. 使用像gwt-dispatcher这样的库,其中所有rpc调用都通过相同的serviceasync并给你一个地方来处理onFailures。

答案 2 :(得分:2)

我对MyProxyCreator的@Piotr版本进行了一些修改,并加入了GWT 2.5

package my.package.server;

import java.util.Map;

import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.SourceWriter;
import com.google.gwt.user.rebind.rpc.ProxyCreator;
import com.google.gwt.user.rebind.rpc.SerializableTypeOracle;


public class MyProxyCreator extends ProxyCreator {

    private final String methodStrTemplate = "@Override\n"
            + "protected <T> com.google.gwt.http.client.Request doInvoke(ResponseReader responseReader, "
            + "String methodName, RpcStatsContext statsContext, String requestData, "
            + "com.google.gwt.user.client.rpc.AsyncCallback<T> callback) {\n"
            + "${method-body}" + "}\n";

    public MyProxyCreator(JClassType serviceIntf) {
        super(serviceIntf);
    }

    @Override
    protected void generateProxyMethods(SourceWriter w, SerializableTypeOracle serializableTypeOracle, TypeOracle typeOracle, Map<JMethod, JMethod> syncMethToAsyncMethMap) {
        // generate standard proxy methods
        super.generateProxyMethods(w, serializableTypeOracle, typeOracle, syncMethToAsyncMethMap);

        // generate additional method
        overrideDoInvokeMethod(w);
    }

    private void overrideDoInvokeMethod(SourceWriter w) {
        StringBuilder methodBody = new StringBuilder();
        methodBody.append("final com.google.gwt.user.client.rpc.AsyncCallback newAsyncCallback = new my.package.client.MyAsyncCallback(callback);\n");
        methodBody.append("return super.doInvoke(responseReader, methodName, statsContext, requestData, newAsyncCallback);\n");

        String methodStr = methodStrTemplate.replace("${method-body}",methodBody);
        w.print(methodStr);
    }

}

它改变了 generateProxyMethods doInvoke 的方法标志。

最诚挚的问候。

iVieL

答案 3 :(得分:2)

为什么不运行GWT计时器(http://google-web-toolkit.googlecode.com/svn/javadoc/2.4/com/google/gwt/user/client/Timer.html)来检查会话是否处于活动/已过期状态,然后提示用户扩展会话或继续注销页面。你为什么只在RPC调用上这样做?

答案 4 :(得分:1)

客户端:所有回调都会扩展一个抽象回调,您可以在其中实现onFailur()

public abstract class AbstrCallback<T> implements AsyncCallback<T> {

  @Override
  public void onFailure(Throwable caught) {
    //SessionData Expired Redirect
    if (caught.getMessage().equals("500 " + YourConfig.ERROR_MESSAGE_NOT_LOGGED_IN)) {
      Window.Location.assign(ConfigStatic.LOGIN_PAGE);
    }
    // else{}: Other Error, if you want you could log it on the client
  }
}

服务器:所有ServiceImplementations都扩展了AbstractServicesImpl,您可以访问SessionData。覆盖onBeforeRequestDeserialized(String serializedRequest)并检查那里的SessionData。如果SessionData已过期,则将空间错误消息写入客户端。此错误消息在您的AbstrCallback中获取checkt并重定向到登录页面。

public abstract class AbstractServicesImpl extends RemoteServiceServlet {

  protected ServerSessionData sessionData;

  @Override
  protected void onBeforeRequestDeserialized(String serializedRequest) {

    sessionData = getYourSessionDataHere()

    if (this.sessionData == null){ 
      // Write error to the client, just copy paste
      this.getThreadLocalResponse().reset();
      ServletContext servletContext = this.getServletContext();
      HttpServletResponse response = this.getThreadLocalResponse();
      try {
        response.setContentType("text/plain");
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        try {
          response.getOutputStream().write(
            ConfigStatic.ERROR_MESSAGE_NOT_LOGGED_IN.getBytes("UTF-8"));
          response.flushBuffer();
        } catch (IllegalStateException e) {
          // Handle the (unexpected) case where getWriter() was previously used
          response.getWriter().write(YourConfig.ERROR_MESSAGE_NOT_LOGGED_IN);
          response.flushBuffer();
        }
      } catch (IOException ex) {
        servletContext.log(
          "respondWithUnexpectedFailure failed while sending the previous failure to the client",
          ex);
      }
      //Throw Exception to stop the execution of the Servlet
      throw new NullPointerException();
    }
  }

}

另外,您还可以覆盖doUnexpectedFailure(Throwable t)以避免记录抛出的NullPointerException。

@Override
protected void doUnexpectedFailure(Throwable t) {
  if (this.sessionData != null) {
    super.doUnexpectedFailure(t);
  }
}

答案 5 :(得分:0)

我在GWT 2.2中使用以下内容来处理新的doInvoke方法:

public class MyProxyCreator extends ProxyCreator {

    private final String methodStrTemplate = "@Override\n"
            + "protected <T> com.google.gwt.http.client.Request doInvoke(ResponseReader responseReader, "
            + "String methodName, com.google.gwt.user.client.rpc.impl.RpcStatsContext statsContext, String requestData, "
            + "com.google.gwt.user.client.rpc.AsyncCallback<T> callback) {\n"
            + "${method-body}" + "}\n";

    public MyProxyCreator(JClassType serviceIntf) {
        super(serviceIntf);
    }

    @Override
    protected void generateProxyMethods(SourceWriter w, 
            SerializableTypeOracle serializableTypeOracle,
            TypeOracle typeOracle,
            Map<JMethod, JMethod> syncMethToAsyncMethMap) {
        // generate standard proxy methods
        super.generateProxyMethods(w, serializableTypeOracle, typeOracle, syncMethToAsyncMethMap);

        // generate additional method
        overrideDoInvokeMethod(w);
    }

    private void overrideDoInvokeMethod(SourceWriter w) {
        StringBuilder methodBody = new StringBuilder();
        methodBody
                .append("final com.google.gwt.user.client.rpc.AsyncCallback newAsyncCallback = new com.mydomain.client.MyAsyncCallback(callback);\n");
        methodBody
                .append("return super.doInvoke(responseReader, methodName, statsContext, requestData, newAsyncCallback);\n");

        String methodStr = methodStrTemplate.replace("${method-body}", methodBody);
        w.print(methodStr);
    }

}

答案 6 :(得分:0)

当由于会话过期而未调用服务方法时,您将获得com.google.gwt.user.client.client.rpc.InvocationException。您可以使用onFailure方法进行检查,只需将用户重定向到登录页面即可。


    public void onFailure(Throwable caught) {
    if (caught instanceof InvocationException) {
                            SC.warn("Your session has expired, Please login again.",
                                    value -> com.google.gwt.user.client.Window.Location.replace("/login.jsp"));
    }else{...
    }
    }

答案 7 :(得分:0)

@Vielinko的更新对于MyProxyCreator的@Piotr的解决方案很有用。

对于多样性,这是@Piotr提供的解决方案的替代解决方案,但它也非常相似。我发现从@Piotr的解决方案开始以

开始,这也起作用

注意:根据需要更新软件包名称。

package com.google.gwt.sample.stockwatcher.server;

import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.sample.stockwatcher.client.MyRemoteServiceProxy;
import com.google.gwt.user.client.rpc.impl.RemoteServiceProxy;
import com.google.gwt.user.rebind.rpc.ProxyCreator;


public class MyProxyCreator extends ProxyCreator {

    public MyProxyCreator(JClassType serviceIntf) {
        super(serviceIntf);
    }

    /**
     * This proxy creator extends the default GWT {@link ProxyCreator} and replaces {@link RemoteServiceProxy} as base class
     * of proxies with {@link MyRemoteServiceProxy}.
     */
    @Override
    protected Class<? extends RemoteServiceProxy> getProxySupertype() {
        return MyRemoteServiceProxy.class;
    }

}

在客户端程序包中创建MyRemoteServiceProxy.java类:

package com.google.gwt.sample.stockwatcher.client;

import com.google.gwt.user.client.rpc.impl.Serializer;

import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.impl.RemoteServiceProxy;
import com.google.gwt.user.client.rpc.impl.RequestCallbackAdapter;
import com.google.gwt.user.client.rpc.impl.RpcStatsContext;

/**
 * The remote service proxy extends default GWT {@link RemoteServiceProxy} and
 * proxies the {@link AsyncCallback} with the {@link AsyncCallbackProxy}.
 */
public class MyRemoteServiceProxy extends RemoteServiceProxy {

    public MyRemoteServiceProxy(String moduleBaseURL, String remoteServiceRelativePath, String serializationPolicyName,
            Serializer serializer) {
        super(moduleBaseURL, remoteServiceRelativePath, serializationPolicyName, serializer);
    }

    @Override
    protected <T> RequestCallback doCreateRequestCallback(RequestCallbackAdapter.ResponseReader responseReader,
            String methodName, RpcStatsContext statsContext, AsyncCallback<T> callback) {
        return super.doCreateRequestCallback(responseReader, methodName, statsContext,
                new MyAsyncCallback<T>(callback));
    }
}

这是在@Piotr的解决方案中具有MyProxyCreator和MyRpcRemoteProxyGenerator的替代解决方案。我已经测试过了。 RPC调用在被调用之前先重新路由到该函数。保留MyAsyncCallback以处理会话超时。 :)