为非实体请求实现GWT RequestFactory服务

时间:2013-12-04 19:50:22

标签: java gwt requestfactory server-communication

我有以下Java servlet执行我所谓的“ Addition Service ”:

public class AdditionService extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        // The request will have 2 Integers inside its body that need to be
        // added together and returned in the response.
        Integer addend = extractAddendFromRequest(request);
        Integer augend = extractAugendFromRequest(request);

        Integer sum = addend + augend;

        PrintWriter writer = response.getWriter();
        writer.write(sum);
    }
}

我试图让GWT的RequestFactory做同样的事情(在app服务器上添加两个数字并将总和作为响应返回)使用ValueProxyAdditionService,并且遇到了几个问题。

这是AdditionRequest(客户端层),它是一个包含两个要添加的整数的值对象:

// Please note the "tier" (client, shared, server) I have placed all of my Java classes in
// as you read through the code.
public class com.myapp.client.AdditionRequest {
    private Integer addend;
    private Integer augend;

    public AdditionRequest() {
        super();

        this.addend = 0;
        this.augend = 0;
    }

    // Getters & setters for addend/augend.
}

接下来我的代理(客户端层):

@ProxyFor(value=AdditionRequest.class)
public interface com.myapp.client.AdditionRequestProxy extends ValueProxy {
    public Integer getAddend();
    public Integer getAugend();
    public void setAddend(Integer a);
    public void setAugend(Integer a);
}

接下来我的服务API(在共享层中):

@Service(value=DefaultAdditionService.class)
public interface com.myapp.shared.AdditionService extends RequestContext {
    Request<Integer> sum(AdditionRequest request);
}

接下来我的请求工厂(共享层):

public class com.myapp.shared.ServiceProvider implements RequestFactory {
    public AdditionService getAdditionService() {
        return new DefaultAdditionService();
    }

    // ... but since I'm implementing RequestFactory, there's about a dozen
    // other methods GWT is forcing me to implement: find, getEventBus, fire, etc.
    // Do I really need to implement all these?
}

最后魔术发生的地方(服务器层):

public class com.myapp.server.DefaultAdditionService implements AdditionService {
    @Override
    public Request<Integer> sum(AdditionRequest request) {
        Integer sum = request.getAddend() + request.getAugend();
        return sum;
    }

    // And because AdditionService extends RequestContext there's another bunch of
    // methods GWT is forcing me to implement here: append, create, isChanged, etc.
    // Do I really need to implement all these?
}

以下是我的问题:

  1. 我的“等级”策略是否正确?我是否已将所有类型打包在正确的客户端/共享/服务器包中?
    • 我不认为我的设置是正确的,因为AdditionService(在共享中)引用DefaultAdditionService,它位于服务器上,它不应该这样做。共享类型应该能够在客户端和服务器上同时存在,但不能依赖于...
  2. ServiceProvider应该是实现RequestFactory的类,还是应该是扩展的接口?如果是后者,我在哪里定义ServiceProvider impl,以及如何将其链接回所有其他类?
  3. ServiceProviderDefaultAdditionService中的所有这些方法怎么样?我是否需要实施所有20多种核心GWT方法?或者我是否错误地使用了API或者没有像我使用它那样简单?
  4. 服务定位器因素在哪里?怎么样?
  5. 我认为我很接近但需要帮助越过终点线。如果有人可以接受我的代码并进行调整以显示使用RF / ValueProxies的正确方法,我认为它会将整个框架与我联系在一起......提前感谢!

1 个答案:

答案 0 :(得分:6)

如果你想使用RF作为简单的RPC机制[*],你可以(而且你是对的:只有ValueProxy s),但你需要更多:ServiceLocator s(即GWT) 2.1.1)。

使用ServiceLocator,您只需将服务实现(如servlet)放入实际服务实例中,而不是放入实体对象(因为您只使用ValueProxy s,没有静态getXyz()方法),如RF协议所要求的那样。请注意Locator s的存在,用于从服务器端实体外部化所有这些方法:如果在任何地方使用ValueProxy则不需要。

ServiceLocator看起来像(取自official docs):

public class DefaultAdditionServiceLocator implements ServiceLocator {
  @Override
  public Object getInstance(Class<?> clazz) {
    try {
      return clazz.newInstance();
    } catch (InstantiationException e) {
      throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    }
  }
}

您还需要使用定位器参数注释您的DefaultAdditionService,以便RF知道在将您的请求发送到您的服务时应该依赖什么。类似的东西:

@Service(value = DefaultAdditionService.class, locator = DefaultAdditionServiceLocator.class)
public interface com.myapp.shared.AdditionService extends RequestContext {
  // Note here, you need to use the proxy type of your AdditionRequest.
  Request<Integer> sum(AdditionRequestProxy request);
}

您的服务将是地球上最简单的事情(无需扩展/实施与RF相关的任何事情):

public class com.myapp.server.DefaultAdditionService {
  // The server-side AdditionRequest type.
  public Integer sum(AdditionRequest request) {
    Integer sum = request.getAddend() + request.getAugend();
    return sum;
  }
}

如果您错误地sum()或未实施RequestContext中声明的方法,则会收到错误。

要实例化RequestContext,您需要使用RequestFactory的公共工厂方法扩展 com.myapp.shared.AdditionService接口。类似的东西:

public interface AdditionServiceRequestFactory extends RequestFactory {
  public com.myapp.shared.AdditionService createAdditionServiceRequestContext();
}

您的所有客户电话都将从此开始。如果没有,请参阅文档。

现在,RF的工作原理是完全分离您想要从客户端传递的对象(使用EntityProxyValueProxy)和服务器(真实对象,{{1值或简单的Entity类)。您将在客户端/共享层中的任何位置使用代理类型(即,实现自动生成的接口),并且仅在服务器端使用相对域对象(使用DTO引用的对象)。 RF将负责其余部分。因此,@ProxyFor将位于您的服务器端,而AdditionRequest将位于您的客户端(请参阅AdditionRequestProxy中的注释)。另请注意,如果您只是使用原始/盒装类型作为RequestContext参数或返回类型,则根本不需要创建RequestContext,因为它们是默认transportable

您需要的最后一点是在ValueProxy上连接RequestFactoryServlet。请在此处查看docs。请注意,如果您想要使用自定义web.xmlExceptionHandler进行游戏,则可以对其进行扩展,但您并不需要这样做。

说到放置所有内容的地方:

  • ServiceLayerDecoratorLocator,服务实例,域对象和ServiceLocator扩展程序将位于您的服务器端;
  • RequestFactoryServletRequestContext扩展名和所有代理类型都在共享端;
  • 客户端将初始化RequestFactory扩展名并使用它来获取服务请求的工厂实例。

总而言之......用RF创建一个简单的RPC机制,只需:

  • RequestFactory;
  • 一起创建您的服务
  • 为您的请求创建ServiceLocator(使用服务和定位器值注释);
  • 创建RequestContext扩展程序以返回RequestFactory;
  • 如果你想在RequestContext中使用多个基本类型(比如简单的RequestContext),只需为它们创建客户端代理接口,用DTO注释,并记住在哪里使用每种类型;
  • 连线一切。

很像那样。好吧,我写了太多,可能忘记了一些事情:)

供参考,见:

[*]:在这种方法中,您将逻辑从面向数据的转移到面向服务的应用程序。当涉及@ProxyFor操作时,您放弃使用EntityIDversion,当然还有客户端和服务器之间的所有复杂差异逻辑。