1

我有以下 Java servlet,它执行我所谓的“添加服务”:

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

我正在尝试使用 and 让 GWT 的 RequestFactory 做同样的事情(在应用服务器上添加两个数字并返回总和作为响应)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(in shared) referencesDefaultAdditionService位于服务器上,它不应该这样做。共享类型应该能够同时存在于客户端和服务器上,但不依赖于任何一个......
  2. 应该ServiceProvider是实现的类RequestFactory,还是扩展它的接口?如果是后者,我在哪里定义ServiceProviderimpl,以及如何将它链接回所有这些其他类?
  3. ServiceProvider和中的所有这些方法DefaultAdditionService呢?我是否需要实现所有 20 多种核心 GWT 方法?或者我是否错误地使用了 API,或者没有尽可能简单地使用它?
  4. 服务定位器在哪里起作用?如何?
4

1 回答 1

6

如果您想将 RF 用作简单的 RPC 机制 [*],您可以(而且您是对的:只有ValueProxys),但您需要更多的东西:ServiceLocators(即 GWT 2.1.1)。

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

AServiceLocator看起来像(取自官方文档):

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你会得到一个错误。

要实例化s ,RequestContext您需要扩展RequestFactory接口,使用com.myapp.shared.AdditionService. 就像是:

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

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

现在,RF 通过将您想要传递的对象与客户端(使用EntityProxyand ValueProxy)和服务器(真实对象,Entity值或简单DTO类)完全分开来工作。您将在客户端/共享层的任何地方使用代理类型(即自动生成实现的接口),并且@ProxyFor仅在服务器端使用相关域对象(用 引用的对象)。RF 将负责其余的工作。因此,您AdditionRequest将在服务器端,而AdditionRequestProxy在客户端(请参阅 中的注释RequestContext)。另请注意,如果您只是使用原始/盒装类型作为RequestContext参数或返回类型,您甚至根本不需要创建ValueProxys,因为它们是默认可传输的.

您需要的最后一点是RequestFactoryServlet在您的web.xml. 请参阅此处的文档。请注意,如果您想使用 customExceptionHandlerServiceLayerDecorators,您可以扩展它,但您不需要这样做。

谈到把所有东西放在哪里:

  • Locators、ServiceLocators、服务实例、域对象和RequestFactoryServlet扩展,将在您的服务器端;
  • ,扩展和你所有RequestContextRequestFactory代理类型将在共享端;
  • 客户端将初始化RequestFactory扩展并使用它来获取您的服务请求的工厂实例。

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

  • 一起创建您的服务ServiceLocator
  • 为您的请求创建一个RequestContext(用服务和定位器值注释);
  • 创建一个RequestFactory扩展来返回你的RequestContext;
  • 如果你想在你的RequestContext(比如 simple DTOs)中使用更多的原始类型,只需为它们创建客户端代理接口,用 注释@ProxyFor,并记住在哪里使用每种类型;
  • 连接一切。

很像这样。好吧,我写得太多了,可能忘记了什么:)

供参考,请参阅:

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

于 2013-12-05T12:21:55.147 回答