GWT RF:如何在客户端和服务器中共享相同的代码

时间:2013-04-06 10:11:52

标签: java gwt javabeans requestfactory

我想使用相同的代码来对客户端和服务器端的对象进行排序和操作。

但是我遇到了一个问题,因为在客户端我们需要一个代表服务器类的代理接口。

有没有办法在两者中使用相同的接口?我知道RF有一种机制,可以通过网络将bean属性从服务器实例复制到客户端实例。

3 个答案:

答案 0 :(得分:1)

使用相同API的一种方法是使用代理扩展和域对象实现的接口。

// common interfaces
interface Foo { … }
interface Bar<T extends Foo> {
  int getX();
  void setX(int x);

  // setters need to use generics
  List<T> getFoos();
  void setFoos(List<T> foos);

  // with only a getter, things get easier:
  Bar getParent();
}

// domain objects
class RealFoo implements Foo { … }
class RealBar implements Bar<RealFoo> {
  int x;
  List<RealFoo> foos;
  RealBar parent;

  @Override
  public RealBar getParent() { return parent; }

  // other getters and setters
}

// proxy interfaces
@ProxyFor(RealFoo.class)
interface FooProxy extends Foo { … }

@ProxyFor(RealBar.class)
interface BarProxy extends Bar<FooProxy> {
  @Override
  BarProxy getParent();

  // other getters and setters
}

然后,您可以在客户端和服务器端使用Comparator<Foo>Comparator<Bar>

我通常只会实现 traits aspect facets ,以你喜欢的方式调用它们)(HasIdHasLabelHasPosition等),而不是完整的域对象的API。然后,我可以使用HasId获取任何对象的键以将它们放入映射中或比较相等性,HasLabel用于显示(客户端的自定义Cell},错误消息在服务器端发送到客户端等),HasPosition进行排序等。

答案 1 :(得分:0)

RequestFactory的意思是使用相同的类型。每个请求上下文都描述了当调用到达服务器时要执行的一组操作(创建和查找内容,然后应用setter,然后运行服务方法)。由于调用被描述为服务器上真实事物的代理,因此您需要一个'假'模型对象,如EntityProxyValueProxy,以确保可以进行的唯一调用是getter和setter - 有时,设置者不允许(当从服务器读取对象但在编辑对象之前)。

如果模型很简单,即不保存其他对象,只有字符串,日期和基元,则可以让实体和代理实现相同的接口。但是,如果模型包含子对象,那么这就更难了 - 唯一可行的方法就是省去那些getter和setter。否则,您无法覆盖代理类型中的这些方法以指定该嵌套对象的代理版本。

如果您真的想在客户端和服务器上重用相同的类型,请考虑使用RPC isntead。

答案 2 :(得分:0)

正如托马斯在他的answer中所说,当前GWT在客户端和服务器中共享代码的唯一方法是在双方实现相同的接口并在共享代码中使用它。

由于RF在您的查询中将属性从服务器复制到客户端,理论上我们可以在两侧使用相同的接口(代理一个)(更简单的代码),将@ValueFor值设置为指向自身。

让我们看一个例子:

 // Shared interface in client and server sides
 @ProxyFor(Foo.class)
 interface Foo extends ValueProxy {
    String getBar();
 }

 // Server side implementation
 class FooImpl implements Foo {
    String getBar(){return "bar";};
 }

作为信息,我们在产品中使用这种方法,因此我们可以销售2个后端解决方案(一个基于GAE,另一个基于couchdb)。

上面的代码适用于不创建新值的客户端代码,但如果要创建它们,则定义值定位器就足够了:

 // Say RF which locator to use to create classes in server side
 @ProxyFor(value = Foo.class, locator ALocator.class)
 interface Foo extends ValueProxy {
 }

 public class ALocator extends Locator<Foo, String>  {
   public Foo create(Class<? extends Foo> clazz) {
    return new FooImpl();
   }
   ...
 }

不幸的是,RF不处理服务器端的接口,请看问题:75095762

但是,正如您可以在问题评论中阅读的那样,已经有fix(待审核)。希望它将包含在GWT的下一个版本中。

同时,您可以使用此方法,只需复制src文件夹中的文件ResolverServiceLayer.java并将此patch应用于该文件夹。