我在我的应用中使用GWT和RPC。会话到期后,当我进行RPC调用时,由于我的登录过滤请求重定向到login.jsp,但我的问题是客户端没有显示login.jsp而不是RPC的onFailure引发。
这意味着我应该处理所有rpc的onFailure事件,以便重定向到登录页面?!!!!
由于
答案 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>
一开始看起来似乎是一个非常复杂的解决方案:)但它有其优势:
AsyncCallback
s generate-with
)答案 1 :(得分:5)
是的,您应该在onFailure中处理会话超时(在我看来)。但有一些简单的方法可以做到这一点。
实现您自己的异步回调。
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);
}
使用像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以处理会话超时。 :)