在GWT应用程序中,我提供了可由用户编辑的项目。通过使用GWT请求工厂来加载和保存项目。我现在想要实现的是,如果两个用户同时编辑一个项目,保存的用户首先以乐观并发控制的方式获胜。这意味着当第二个用户保存他的更改时,请求工厂后端会识别存储在后端的项目的版本或存在已经更改,因为它已经转移到客户端,然后请求工厂/后端以某种方式阻止更新项目/保存。
我尝试在用于保存项目的服务方法中实现此功能,但这不起作用,因为请求工厂提交刚刚从后端检索到的应用用户更改的项目意味着这些项目的版本是当前版本从后端和比较毫无意义。
请求工厂处理中是否有任何钩子我可以利用它来实现所请求的行为?还有其他想法吗?或者我必须使用GWT-RPC ......
答案 0 :(得分:3)
否:http://code.google.com/p/google-web-toolkit/issues/detail?id=6046
在提议的API实施之前(EntityLocator
,在评论#1中,但我不清楚如何从序列化形式重建版本信息),你将会必须以某种方式将版本发送回服务器
正如我在问题中所说的那样,只需在代理中设置版本属性并进行设置即可完成此操作;但你可以添加另一个属性:获取它将始终返回null
(或类似的不存在的值),以便在客户端将其设置为“true”版本属性的值总会产生一个变化,保证价值将作为“财产差异”的一部分发送到服务器;在服务器端,你可以在setter中处理事情(当RequestFactory应用“属性diff”并调用setter时,如果值与“true”版本不同,则抛出异常)或在服务中方法(比较从客户端发送的版本 - 您从不同的getter获取的版本,而不是客户端上映射的版本,因为它必须始终返回null
- 到对象的“true”版本,并且如果它们不匹配则引发错误。)
类似的东西:
@ProxyFor(MyEntity.class)
interface MyEntityProxy extends EntityProxy {
String getServerVersion();
String getClientVersion();
void setClientVersion(String clientVersion);
…
}
@Entity
class MyEntity {
private String clientVersion;
@Version private String serverVersion;
public String getServerVersion() { return serverVersion; }
public String getClientVersion() { return null; }
public void setClientVersion(String clientVersion) {
this.clientVersion = clientVersion;
}
public void checkVersion() {
if (Objects.equal(serverVersion, clientVersion)) {
throw new OptimisticConcurrencyException();
}
}
}
请注意,我没有测试过这个,这是纯理论。
答案 1 :(得分:2)
我们在应用程序中提出了另一种乐观锁定的解决方法。由于版本无法与代理本身(as Thomas explained)一起传递,因此我们通过 HTTP GET 参数将其传递给请求工厂。
在客户端:
MyRequestFactory factory = GWT.create( MyRequestFactory.class );
RequestTransport transport = new DefaultRequestTransport() {
@Override
public String getRequestUrl() {
return super.getRequestUrl() + "?version=" + getMyVersion();
}
};
factory.initialize(new SimpleEventBus(), transport);
在服务器上,我们创建一个ServiceLayerDecorator并从RequestFactoryServlet.getThreadLocalRequest()
读取版本:
public static class MyServiceLayerDecorator extends ServiceLayerDecorator {
@Override
public final <T> T loadDomainObject(final Class<T> clazz, final Object domainId) {
HttpServletRequest threadLocalRequest = RequestFactoryServlet.getThreadLocalRequest();
String clientVersion = threadLocalRequest.getParameter("version") );
T domainObject = super.loadDomainObject(clazz, domainId);
String serverVersion = ((HasVersion)domainObject).getVersion();
if ( versionMismatch(serverVersion, clientVersion) )
report("Version error!");
return domainObject;
}
}
优点是在通过RF将任何更改应用于域对象之前调用loadDomainObject()
。
在我们的案例中,我们只是跟踪一个实体,因此我们使用的是一个版本,但方法可以扩展到多个实体。