Как перенаправить на страницу входа после истечения сеанса в вызове GWT RPC

Я использую GWT и RPC в моем приложении. после окончания сеанса, когда я выполняю вызов RPC, из-за моего фильтра входа в систему запрос перенаправляет на login.jsp, но моя проблема в том, что клиент не показывает мне login.jsp вместо вызова onFailure RPC.

Это означает, что я должен обработать все события onFailure моего rpc для перенаправления на страницу входа в систему?!!!!

Спасибо

7 ответов

Решение

Я согласен с pathed, что вы должны сделать перенаправление в вашем AsyncCallbacks. Тем не менее, вам не нужно явно использовать свой пользовательский MyAsyncCallback обратные вызовы вместо стандартного GWT AsyncCallback, Это важно, например, когда у вас уже есть много кода, который использует стандартные обратные вызовы.

Когда вы вызываете GWT.create(MyService.class) GWT генерирует прокси для вашего MyServiceAsync Сервисный интерфейс. Этот прокси-сервер отвечает за связь с сервером и вызов ваших обратных вызовов при получении данных с сервера. Прокси генерируются с использованием механизма генераторов кода GWT и по умолчанию использует 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 AsyncCallbacks
  • Вы можете принудительно перенаправить, когда время ожидания сеанса глобально для вашего приложения
  • Вы можете легко включить и выключить его (добавив или удалив generate-with в ваших конфигурационных файлах GWT)

Да, вы должны обрабатывать тайм-аут сеанса в 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.

Я немного исправил версию 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

Почему у вас не работает таймер GWT ( http://google-web-toolkit.googlecode.com/svn/javadoc/2.4/com/google/gwt/user/client/Timer.html), который проверяет, сеанс активен / истек, а затем либо предложите пользователю продлить сеанс, либо перейдите на страницу выхода из системы. Почему вы делаете это только на вызовах RPC?

Клиент: Все обратные вызовы расширяют абстрактный обратный вызов, где вы реализуете 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 и перенаправляет на страницу входа.

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);
  }
}

Обновление @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));
    }
}

Это альтернативное решение для MyProxyCreator и MyRpcRemoteProxyGenerator в решении @Piotr. Я проверил, что это работает. Перед вызовом RPC-вызовы перенаправляются к этой функции. Сохраните MyAsyncCallback для обработки тайм-аута сеанса.:)

Я использовал следующее с 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);
    }

}

Вы получите com.google.gwt.user.client.rpc.InvocationException, если метод службы не вызывается из-за истечения сеанса. Вы можете проверить это в методе onFailure и просто перенаправить пользователя на страницу входа.

    public void onFailure (Throwable catch) {
    if (поймал экземпляр InvocationException) {
                            SC.warn("Ваш сеанс истек, пожалуйста, войдите снова.",
                                    значение -> com.google.gwt.user.client.Window.Location.replace("/login.jsp"));
    } Еще {...
    }
    }
Другие вопросы по тегам