GWT 和 Google Cloud Endpoints

Posted

技术标签:

【中文标题】GWT 和 Google Cloud Endpoints【英文标题】:GWT and Google Cloud Endpoints 【发布时间】:2013-05-23 02:32:33 【问题描述】:

几天前,我开始使用 Google App Engine 和 Google Cloud Endpoints 开发移动应用程序后端。 This tutorial 展示了端点是如何自动生成的,以及适用于 android 的客户端库。

所以我们有我们的实体:

@Entity
public class Person implements IsSerializable

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key key;

    private String name;
//...
 

还有这个类的端点:

@Api(name = "personendpoint")
public class PersonEndpoint 

    @ApiMethod(name = "getPerson")
    public Person getPerson(@Named("id") Long id) 
...

此外,使用生成的 Android 端点库(使用 REST API)我想在服务器上添加一个用户界面,使用 Google Web Toolkit (GWT) 构建强>。但是我应该如何操作服务器端的日期呢?我可以看到不同的方法...

选项 A1:在 GWT 中添加 RPC 服务

public interface PersonServiceAsync 

    void insertPerson(Person person, AsyncCallback<Person> callback);



@RemoteServiceRelativePath("api")
public interface PersonService extends RemoteService 

    public Person insertPerson(Person person);


public class PersonServiceImpl extends RemoteServiceServlet implements PersonService
    public Person insertPerson(Person person) 
        EntityManager mgr = getEntityManager();
        try 
            if (containsPerson(person)) 
                throw new EntityExistsException("Object already exists");
            
            mgr.persist(person);
         finally 
            mgr.close();
        
        return person;
    

        //...

但现在我的PersonServiceImplPersonEndpoint 做的大致相同。所以我们没有关注DRY :) 此外,不允许那个人有com.google.appengine.api.datastore.Key,所以我们必须改变我们的实体。

选项 A2:服务调用端点类

@Override
public Person insertPerson(Person person) 
    return new PersonEndpoint().insertPerson(person);

应该可以工作,但仍然没有com.google.appengine.api.datastore.Key 在实体中键入,并且由于端点使用CollectionResponse&lt;Person&gt;,我们必须将其转换为Collection&lt;Person&gt;,以防listPerson()

选项 B1:使用 Java 端点客户端库

我们可以将 GWT 客户端从我们的 App Engine API 后端中分离出来,并使用生成的 Java 端点客户端库。所以我们从RemoteServiceServlet 中调用REST/Endpoint-API。但是,即使 GWT 客户端和 Endpoints 在同一台服务器上或什至在同一项目中,这不会以两个请求结束吗?

GWT 客户端 --(RPC)--> GWT 服务器 --(HTTP 请求)--> App Engine 后端服务器

选项 B2:使用 JavaScript 端点客户端库

可能是最好的方法,但最终会导致大量 JSNI。


那么最佳做法是什么?我在一个项目中找不到任何使用 Google Cloud Endpoints 和 GWT 的示例项目 :)

【问题讨论】:

你见过code.google.com/p/gwt-google-apis 是的,但它们处于早期的 Alpha 版本并用于 Google API。我说的是您自己的 API/端点,由 GAE 生成。 该库适用于任何基于发现的 API,而您的 API/端点恰好是(即基于发现的)。 我也有同样的困境。我们希望使用 Endpoint API,但开发 GWT 前端。我有一种感觉,它可能必须是一个或另一个...... 也在寻找解决方案。暂时使用 JSNI。 【参考方案1】:

旧的 DTO 困境。没有对与错,只有对你来说足够好的。

重复自己可能是一件好事。现在您正在通过端点公开您的数据模型,这意味着您的实体的任何更改都会影响您的移动应用程序用户。假设您在服务器端重命名了一个属性 -> 每个未更新应用程序的客户端都会关闭。

安全性也是一个问题:如果您的 User 实体具有“email”属性,通过 GWT RPC 对其进行序列化将使您的用户的电子邮件几乎可用于任何 javascript 调试器。

真的是你想要的吗?

不要误会我的意思,我不喜欢那些“洋葱层”怪物应用程序,其中 80% 的代码似乎用于将对象转换为具有几乎相同属性的其他对象。

我认为正确的解决方案介于两者之间:拥有一个“客户端”模型 (DTO),由您通过 GWT RPC 和客户端端点公开的可序列化 POJO(没有数据存储、ORM、JAXB 或任何注释)组成。 您的 GWT servlet 实现和端点服务器将调用相同的服务,将您的客户端模型转换为实体并处理/保留它们。

通过这种方式,您可以重复使用您的代码,仍然保持简单,在您的 API 中拥有统一的接口,并允许您的内部管道在不改变客户端接口的情况下发展。

【讨论】:

尽管我很长时间没有使用 GWT,但我经常遇到类似的困境(商业模式与 DTO)。早在 2014 年,这个答案并没有真正让我满意。但经过多年的高级 Java 开发经验和数千行代码之后,我必须说您当时的评论完全符合您的观点,我完全同意您的看法。【参考方案2】:

也许我不明白什么。 但一切似乎(对我来说)都很容易。

    GWT(客户端!)不在服务器上。它是在客户端浏览器中执行的编译 Javascript。

    Google 插件生成 Javascript 客户端代码,使用合适的 JSON 调用 Endpoint。

    可以从 GWT 调用以上代码。

瞧?

【讨论】:

是的,所以这将是选项 B2。但正如我提到的那样,它会起作用,但最终会出现很多 JSNI。因为客户端的大部分是用 Java (GWT) 编写/定义的,但调用端点的逻辑是生成的 Javascript 代码。工作,但不是很好。

以上是关于GWT 和 Google Cloud Endpoints的主要内容,如果未能解决你的问题,请参考以下文章

在 Google Web Toolkit (GWT) 中实现页眉、页脚和菜单栏

GWT Servlet 错误 com.google.gwt.user.client.rpc .StatusCodeException: Tomcat 服务器上的 404

GWT - 偶尔出现 com.google.gwt.user.client.rpc.SerializationException

GWT与Google App Engine-上传文件

com.google.gwt.view.client.Range 的 GWT SerializationException

尽早避免 GWT 的 com.google.gwt.user.client.rpc.SerializationException 的最佳实践