如何使用 Errai 将 GWT 与 JAX-RS/RESTEasy 服务器集成?

2024-03-29

我想从 GWT 客户端应用程序调用使用 RESTEasy 和 JAX-RS 创建的 REST 服务。使用 Errai 为服务器和客户端使用单一代码库的最佳流程是什么?


我们都喜欢休息。它与供应商、平台和语言无关;调试、实施和访问都很简单;它为您的云、浏览器、移动和桌面应用程序提供了可靠的后端。

Java 开发人员可以使用支持的库JAX-RS http://docs.oracle.com/javaee/6/tutorial/doc/giepu.html, like RESTEasy http://www.jboss.org/resteasy,只需几分钟即可启动并运行 REST 服务器。然后,使用 JAX-RS 客户端 http://docs.jboss.org/resteasy/docs/2.3.4.Final/userguide/html_single/#RESTEasy_Client_Framework,只需几行代码即可从 Java 客户端应用程序调用这些 JAX-RS REST 服务器。

尽管 GWT 与 Java 有很多共同点,但从 GWT 调用 REST 服务可能是一种痛苦的经历。使用请求生成器 https://developers.google.com/web-toolkit/doc/1.6/DevGuideServerCommunication#DevGuideHttpRequests类涉及指定正确的 HTTP 方法、对 URL 进行编码,然后解码响应或创建Overlay http://code.google.com/p/google-web-toolkit/wiki/OverlayTypes对象来表示 REST 服务器发回的数据。对于调用一两个 REST 方法来说,这可能不是一个很大的开销,但在将 GWT 与更复杂的 REST 服务集成时,它确实意味着大量的工作。

这是哪里Errai http://www.jboss.org/errai.htmlErrai 是一个 JBoss 项目,除其他外,在 GWT 中实现 JAX-RS 标准 http://docs.jboss.org/errai/2.0.CR2/errai/reference/html_single/#sid-19398997。理论上,这意味着您可以在 Java 和 GWT 项目之间共享 JAX-RS 接口,从而提供定义 REST 服务器功能的单一源。

从 Errai 调用 REST 服务器仅涉及几个简单的步骤。首先,您需要 REST JAX-RS 接口。这是一个带有 JAX-RS 注释的 Java 接口,它定义了 REST 服务器将提供的方法。该接口可以在 Java 和 GWT 项目之间共享。

@Path("customers")
public interface CustomerService {
  @GET
  @Produces("application/json")
  public List<Customer> listAllCustomers();

  @POST
  @Consumes("application/json")
  @Produces("text/plain")

  public long createCustomer(Customer customer);
}

然后将 REST 接口注入到您的 GWT 客户端类中。

@Inject
private Caller<CustomerService> customerService;

定义了响应处理程序。

RemoteCallback<Long> callback = new RemoteCallback<Long>() {
  public void callback(Long id) {
    Window.alert("Customer created with ID: " + id);
  }
};

最后调用 REST 方法。

customerService.call(callback).listAllCustomers();

很简单吧?

您可能会从此示例中相信 Errai 将为您当前的 JAX-RS 基础设施提供一个简单的解决方案,但不幸的是,这个简单的示例并没有涉及您在尝试结合您的系统时可能会遇到的一些复杂情况。 GWT 和 Java REST 代码库。以下是使用 Errai 和 JAX-RS 时需要注意的一些问题。

您需要实施 CORS

通常,在实现 GWT JAX-RS 客户端时,您将针对外部 REST 服务器调试 GWT 应用程序。除非你实现,否则这不会起作用CORS http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/,因为默认情况下托管 GWT 应用程序的浏览器不允许您的 JavaScript 代码联系不在同一域中运行的服务器。事实上,您甚至可以在本地开发 PC 上运行 REST 服务器,但仍然会遇到这些跨域问题,因为不同端口之间的调用也受到限制。

如果您使用 RESTEasy,可以通过两种方法实现 CORS。第一个是使用消息体拦截器 http://docs.jboss.org/resteasy/docs/2.3.4.Final/userguide/html_single/#MessageBodyInterceptors界面。您提供 write() 方法,并使用 @Provider 和 @ServerInterceptor 注释来注释您的类。然后使用 write() 方法将“Access-Control-Allow-Origin”标头添加到对任何简单请求的响应中(“简单”请求不设置自定义标头,并且请求正文仅使用纯文本)。

第二种方法处理 CORS 预检请求(对于可能对用户数据产生副作用的 HTTP 请求方法 - 特别是对于除 GET 之外的 HTTP 方法,或者对于某些 MIME 类型的 POST 使用)。这些请求使用 HTTP OPTIONS 方法,并期望在回复中收到“Access-Control-Allow-Origin”、“Access-Control-Allow-Methods”和“Access-Control-Allow-Headers”标头。下面的handleCORSRequest() 方法对此进行了演示。

Note

下面的 REST 接口允许任何和所有 CORS 请求,从安全角度来看这可能不合适。然而,假设在此级别阻止或限制 CORS 将提供任何程度的安全性是不明智的,因为设置代理 http://developer.yahoo.com/javascript/howto-proxy.html代表客户提出这些请求是非常简单的。

@Path("/1")
@Provider
@ServerInterceptor
public class RESTv1 implements RESTInterfaceV1, MessageBodyWriterInterceptor
{
    @Override
    public void write(final MessageBodyWriterContext context) throws IOException, WebApplicationException
    {   context.getHeaders().add(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
        context.proceed();      
    }

    @OPTIONS
    @Path("/{path:.*}")
    public Response handleCORSRequest(@HeaderParam(RESTInterfaceV1.ACCESS_CONTROL_REQUEST_METHOD) final String requestMethod, @HeaderParam(RESTInterfaceV1.ACCESS_CONTROL_REQUEST_HEADERS) final String requestHeaders)
    {
        final ResponseBuilder retValue = Response.ok();

        if (requestHeaders != null)
            retValue.header(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders);

        if (requestMethod != null)
            retValue.header(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_METHODS, requestMethod);

        retValue.header(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");

        return retValue.build();
    }

}

有了这两种方法,对 REST 服务器的任何调用都将提供适当的响应以允许跨源请求。

您需要接受并使用简单的 POJO 进行响应

简介说明了一个使用 Long 响应的简单 REST 接口。 JAX-RS 的 Java 和 GWT 实现都知道如何序列化和反序列化基元和简单类(例如 java.util 集合)。

在现实世界的示例中,您的 REST 接口将使用更复杂的对象进行响应。这是不同的实现可能发生冲突的地方。

首先,JAX-RS 和 Errai 使用不同的注释来自定义 JSON 和 Java 对象之间的对象编组。 Errai 有 @MapsTo 和 @Portable 等注释,而 RESTEasy(或 Jackson,JSON 编组器 http://docs.jboss.org/resteasy/docs/2.0.0.GA/userguide/html_single/index.html#json)使用 @JsonIgnore 和 @JsonSerialize 等注释。这些注释是相互排斥的:GWT 会抱怨 Jackson 注释,而 Jackson 不能使用 Errai 注释。

简单的解决方案是在其余接口中使用一组简单的 POJO。简单地说,我的意思是具有无参数构造函数的类,并且仅具有与 JSON 对象通过网络传输时出现在其中的属性直接相关的 getter 和 setter 方法。简单的 POJO 可以由 Errai 和 Jackson 使用默认设置进行编组,从而无需处理不兼容的注释。

Errai 和 Jackson 还从不同的地方获取 JSON 字符串中生成的属性的名称。 Jackson 将使用 getter 和 setter 方法的名称,而 Errai 将使用实例变量的名称。因此,请确保您的实例变量和 getter/setter 方法名称完全相同。还行吧:

public class Test
{
    private int count;
    public int getCount() {return count;}
    public void setCount(int count) {this.count = count;}
}

这会导致问题:

public class Test
{
    private int myCount;
    public int getCount() {return myCount;}
    public void setCount(int count) {this.myCount = count;}
}

其次,人们很容易向这些 REST 数据对象添加额外的方法来实现某些业务功能。然而,如果您这样做,不久之后您就会尝试使用 GWT 不支持的类,并且您可能会惊讶地发现:GWT 不支持 https://developers.google.com/web-toolkit/doc/latest/DevGuideCodingBasicsCompatibility:日期格式化、克隆数组、将字符串转换为字节[]...这样的例子不胜枚举。因此,最好坚持 REST 数据对象的基础知识,并使用组合或基于组件的设计等完全在 REST 数据对象继承树之外实现任何业务逻辑。

Note

如果没有 @Portable 注释,您将需要在 ErraiApp.properties 文件中调用 REST 接口时手动列出 Errai 所使用的所有类 http://docs.jboss.org/errai/2.0.CR2/errai/reference/html_single/#sid-5931328_Marshalling-AliasedMappingsofExistingInterfaceContracts.

Note

您还需要远离地图。看this bug https://issues.jboss.org/browse/ERRAI-295了解详情。

Note

您不能在 JSON 服务器返回的对象层次结构中使用嵌套参数化类型。看this bug https://issues.jboss.org/browse/ERRAI-319 and 这个论坛帖子 https://community.jboss.org/thread/200995了解详情。

Note

Errai 对 byte[] 有问题。请改用列表。看这个论坛帖子 https://community.jboss.org/message/742912更多细节。

您需要使用 Firefox 进行调试

当使用 GWT 通过 REST 接口发送大量数据时,您必须使用 Firefox 调试应用程序。根据我自己的经验,将一个小文件编码为 byte[] 并通过网络发送它会导致 Chrome 中出现各种错误。当 JSON 编码器尝试处理损坏的数据时,会抛出各种不同的异常;在 GWT 应用程序的编译版本中或在 Firefox 上调试时未看到的异常。

不幸的是,Google 未能使其 Firefox GWT 插件与 Mozilla 的新发布周期保持同步,但您经常可以在 GWT Google Groups 论坛中找到 Alan Leung 发布的非官方版本。这个链接 https://groups.google.com/forum/#!starred/google-web-toolkit/7OR5LM1POzI有一个适用于 Firefox 12 的 GWT 插件版本,并且这个链接 https://groups.google.com/forum/?fromgroups#!topic/google-web-toolkit/EoTbKTvJRyk有适用于 Firefox 13 的版本。

您需要使用 Errai 2.1 或更高版本

只有 Errai 2.1 或更高版本才会生成与 Jackson 兼容的 JSON https://issues.jboss.org/browse/ERRAI-295,如果您尝试将 GWT 与 RESTEasy 集成,这是必须的。杰克逊编组可以使用启用

RestClient.setJacksonMarshallingActive(true);

or

<script type="text/javascript">
  erraiJaxRsJacksonMarshallingActive = true;
</script>

您需要为高级功能创建单独的 JAX-RS 接口

如果您的 JAX-RS REST 接口返回高级对象,例如ATOM http://docs.jboss.org/resteasy/docs/2.0.0.GA/userguide/html_single/index.html#Atom(或者更重要的是,导入像 org.jboss.resteasy.plugins.providers.atom.Feed 这样的类),您需要将 REST 接口拆分为两个 Java 接口,因为 Errai 不知道这些对象,并且这些类可能不处于可以轻松导入到 GWT 中的状态。

一个接口可以保存普通的旧式 JSON 和 XML 方法,而另一个接口可以保存 ATOM 方法。这样您就可以避免在 GWT 应用程序中引用未知类的接口。

Note

Errai 目前仅支持 JSON 编组 http://docs.jboss.org/errai/2.0.0.Final/errai/reference/html_single/#sid-9470133,尽管将来您可能能够定义自定义编组器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Errai 将 GWT 与 JAX-RS/RESTEasy 服务器集成? 的相关文章

  • 如何在我的 Maven 项目中正确包含“org.apache.catalina.filters.SetCharacterEncodingFilter”过滤器?

    我使用 Maven 3 3 和 JBoss 7 1 3 Final Java 6 我想在我的 Web 应用程序中包含一个过滤器 以便所有传入请求数据都将编码为 UTF 8 所以我将其添加到我的 web xml 文件中
  • 正则表达式和 GWT

    我的问题是 在GWT中使用正则表达式有没有好的解决方案 例如 我对 String split regex 的使用不满意 GWT 将代码翻译为 JS 然后将正则表达式用作 JS 正则表达式 但我无法使用 Java Matcher 或 Java
  • 生产中的 GWT 源映射

    GWT 支持超级开发模式下的源映射 不幸的是 尽管我在 gwt xml 文件中添加了源映射选项 但它们似乎无法在生产模式下工作 如何在那里启用它们 看看 GWT 自己的网站是如何做到这一点的 https gwt googlesource c
  • 带下拉箭头的 GWT 文本框

    我想在文本框中有一个下拉箭头 在我的例子中实际上是 SuggestBox GMail 执行此操作是为了实现高级搜索功能 打开高级搜索对话框 要使该箭头显示在 TextBox 的右侧并可单击 正确的 GWT 布局是什么 看看 GMail 我发
  • 当 ExceptionMapper 创建响应时,未遍历 RestEasy 后处理拦截器链

    我正在使用 RestEasy 构建我的 Restful Web 服务 我已经实现了 ExceptionMappers 来准备特定的异常响应 我还实现了 MessageBodyWriterInterceptors 和几个 PostProces
  • 如何使用 Eclipse 的 google 插件使用经过精心编译的 HTML 来部署 GWT 应用程序

    我使用 eclipse 的 google 插件来部署我的 GWT 应用程序 到目前为止它运行良好 部署操作首先使用 混淆 输出样式编译我的 GWT 项目 现在我希望它更改为 漂亮 因为我必须调试客户端在运行中 我只是看不到混淆的堆栈 Tha
  • JBoss 7 MySQL 数据源问题

    我正在尝试在 JBOSS 7 中创建数据源 我的standalone xml摘录
  • 架构问题:GWT 还是 Vaadin 创建桌面应用程序?

    我们计划创建一个提要阅读器 as a Windows 桌面和 iPad 应用程序 正如我们希望能够显示网站 AND 运行 我们自己的 JavaScript在此应用程序中 我们考虑将应用程序作为 HTML CSS JavaScript 交付
  • 在哪里可以找到用于 EJB 测试的完整 Maven Cargo 插件示例?

    对于一些小型 JBoss 企业应用程序的测试 我想使用 JUnit 并且Maven 货物插件 http cargo codehaus org Maven2 plugin 我知道还有 JSFUnit 但首先我想仔细看看 Cargo 网上是否有
  • 如何在 GWT 中取消转义字符串

    我使用了 SafeHtmlUtils htmlEscape text 并且我想使用相反的功能 你能告诉我 gwt 中是否有像 unescapeHtml 这样的函数 如果 并且仅当 您可以相信文本不包含恶意内容 您可以使用 import co
  • 带有编辑器框架的 GWT 验证器

    有没有人意识到编辑器和 jsr 303 验证如何与 GWT 2 3 一起工作 未来 验证 API 已添加到 gwt sdk 但我无法使用编辑器框架验证实体 无论 我确实从来没有从客户端或服务器端抛出错误 这是一个代码片段 public cl
  • java.lang.ClassNotFoundException:com.google.gwt.user.client.rpc.RemoteService

    在 Tomcat 6 中部署 war 文件时出现以下异常 java lang ClassNotFoundException com google gwt user client rpc RemoteService 所以我尝试通过 webAp
  • 如何使用 Ant 配置惰性或增量构建?

    Java编译器提供增量构建 所以javac蚂蚁任务也是如此 但大多数其他进程则不然 考虑到构建过程 它们将一组文件 源 转换为另一组文件 目标 我在这里可以区分两种情况 变压器cannot获取源文件的子集 仅获取整个集合 这里我们只能做懒惰
  • 在 Servlet 2.4 容器上运行 JSF 2.0

    据我所知 JSF 2 需要 servlet 2 5 因此它不能在 JBOSS 4 05 Tomcat 5 5 上运行 不幸的是 我必须在该环境中部署一个使用 JSF 2 0 和 Primefaces 的应用程序 有什么黑客可以使用它吗 JS
  • 如何使用 GWT 2.4 在服务器端动态创建 UI

    我正在尝试使用 Google Web Toolkit v2 4 创建用户界面 由于多种原因 我需要在运行时指定服务器上接口的内容 我的意思不仅仅是按钮需要动态标签等 而是整个 UI 需要在运行时创建 我的大部分 UI 都可以指定为直接的 H
  • 如何清除gwt中的缓存?

    我怎样才能清除缓存gwt 或者有什么方法可以阻止浏览器保留缓存gwt 当您部署 GWT 应用程序时 避免代理和浏览器缓存 GWT 生成的 nocache js 文件非常重要 一种解决方案是实现一个 Servlet 过滤器 添加控制缓存行为的
  • 如何在Windows上启动JBoss AS 7.1.1?

    我是新来的JBOSS 我下载了jboss as 7 1 1 Final zip并解压缩该 zip 文件 然后我转到 bin 文件夹并双击standalone bat 但新的 cmd 窗口在 2 3 秒内打开和关闭 我尝试通过cmd启动服务器
  • GWT:将自定义小部件添加到单元格丢失自定义小部件的事件

    我们的要求是使用以下命令制作一个可编辑的网格CellTable在其单元格中包含自定义小部件 自定义小部件具有文本框和与文本框关联的搜索按钮 要将自定义小部件添加为单元格 请创建以下子类AbstractEditableCell类 由 GWT
  • Jboss 7战争部署失败

    Jboss 7 war 部署失败 我在日志中收到以下错误消息 ERROR org jboss as server deployment scanner DeploymentScanner threads 1 JBAS015052 Did n
  • 为什么我们在同一台服务器上使用多个应用程序服务器实例

    我想这是有充分理由的 但我不明白为什么有时我们会在同一物理服务器上放置例如 5 个具有相同 Web 应用程序的实例 这与多处理器架构的优化有关吗 JVM 或其他允许的最大内存限制 嗯 过了很长一段时间我又看到这个问题了 一台机器上的多个 J

随机推荐

  • 使用 Vue.Js / Inertia.js 和 Laravel 对结果进行分页

    我正在尝试在 Vue Js 中对来自 Laravel 的数据进行分页 我也在使用 Inertia js 在我的 Laravel 控制器中 我有 data participants User with groups gt select id
  • Javascript:将值返回给回调函数外部的变量[重复]

    这个问题在这里已经有答案了 我有一个非常具体的问题 希望有人可以帮助我 我对 Javascript 很陌生 对 NodeJS 则更陌生 我在用lodash s forIn遍历并添加到数组内的对象的功能 整个事情看起来是这样的 id 20 k
  • Visual Studio 2022 无法构建任何项目

    每次我在 Visual Studio 2022 中构建任何项目时 我在构建输出中得到的都是 Build started 1 gt Build started Project ConsoleApp7 Configuration Debug A
  • 使用 socket.io 处理超大消息

    我有一个 nodejs 项目 它生成多个与套接字 io 通信的进程 该进程既发送数据又接收数据 有时在功能开发过程中 其他程序员可能会犯错误 导致我的套接字基础结构代码发送超过大小 X 例如 超过 500MB 的大消息 我正在寻找一种方法来
  • 如果超过一组特定的行发生更改,如何让 git 仅识别文件已更改?

    在我当前的项目中 我尝试使用 git 来版本控制文本文件 这些文件由生成代码的软件使用 这本身不是问题 问题是每次我生成代码时 它都会自动更新此文件的属性 例如代码生成的日期以及我的名字 你可以想象它看起来像这样 SomeHeader So
  • 将列引导至相同高度并让子列匹配高度

    正如标题所暗示的 我正在努力获得正常的均匀性和干净的线条 table 提供 但具有 Bootstrap 网格系统的响应能力 我用过部分解决方案在这里找到 http www minimit com articles solutions tut
  • Facebook Connect 使用 ASP.NET 会员提供程序与网站集成

    是否有任何最佳实践或示例来说明如何使用会员提供程序 或类似的东西 将 Facebook connect 与现有 ASP NET 应用程序最好地集成 我确信我可以做一些事情 但是 如果有一些关于这方面的信息和最佳实践来减轻任何安全问题 那就太
  • SourceTree 将拉取的文件视为未提交的更改

    在某些未知的情况下 当我使用 SourceTree 拉取时 它会将所有拉取的文件视为未提交的更改 并且不允许再拉 推 除非重新提交或放弃这些更改 如果我丢弃未提交的文件 它将丢弃我的队友应用的所有更改 这有什么问题吗 是否存在已知的错误或其
  • graph6 格式如何工作?

    我一直在到处寻找 g6 或 graph6 格式的工作原理 但我不知道它是如何工作的 我发誓它就像魔法一样 F B w 这是一个以 ASCII 形式表示的图表 它可以由 Wolfram Mathematica Sage 和 Maple 等进行
  • Angular 错误:PostCSS 收到未定义而不是 CSS 字符串

    尝试构建 Angular 项目 但出现以下错误 这个项目上周建得很好 我对使用此项目中的 Dll 的其他项目进行了一些更改 但没有对此项目进行任何更改 我已经花了很多时间来排除故障 但没有运气 感谢任何帮助 错误 PostCSS 收到未定义
  • Facebook SDK 和通过 ShareDialog 问题共享 Play 商店应用程序链接

    我正在尝试使用 Facebook SDK 中的 ShareDialog 共享链接 我的 Google Play 应用程序链接 但问题是 当 URL 是我的应用程序的 Google Play 链接时 其他信息无法正确显示 实际上它只显示链接来
  • 如何让shell脚本在Mac中双击运行?

    我创建了一个 shell 脚本来在 Mac 中运行 jar 文件 bin sh java Xmx512m jar test jar 我已将此脚本重命名为 应用程序命令 双击就可以直接运行 我已经应用了 chmod x 命令使其具有可执行权限
  • PHP header() 不会重定向问题

    我的 header Location index php action messagesent 有问题 在用户按下提交并且 php 运行后 它不会重定向 通常它会重定向 但由于某种原因它不起作用 它只是在点击提交后重新加载页面 但它确实在标
  • 如何删除联系人?

    我正在使用 android 2 1 ContactContract 当我没有将帐户 例如 gmail 帐户 设置为 android 模拟器时 新建一个联系人 但无法在数据库中删除该联系人 ArrayList
  • 添加包含订单计数的列

    如何向数据框中添加一列来说明另一列中某个值出现的顺序计数 这就是我想要的结果 Fruit orderCount 1 Orange 1 2 Banana 1 3 Orange 2 4 Apple 1 5 Orange 3 6 Banana 2
  • 将文本渲染到 kivy 画布

    我正在尝试在奇异的 画布 中绘制自己的图形 现在我有一个红色或绿色的矩形 每秒改变一次颜色 但我想添加一个变化的文本标签 经过一番搜索后 似乎没有可以添加到画布的 文本 指令 我发现了一些关于使用 Label 小部件以及画布说明的参考 但这
  • 有没有替代 imread 命令来减少 matlab 程序中的延迟?

    我在此路径 G newdatabase 中有 2900 个图像 读取图像花费了太多时间 对于点积 它也花费了太多时间 问题 1 是否有任何替代 imread 命令来提高性能 2 是否有任何替代点命令可以提高性能 我尝试过的源代码 srcFi
  • 为什么windows第一次打开文件那么慢,有没有更快的方法

    这是 Windows 7 64 位 专业版使用 考虑一个非常简单的循环 for i 0 i lt names gt size i std string Name names gt at i HANDLE fileHandle CreateF
  • 使用 MAMP 在 Mac 上出现“db: SQLSTATE[HY000] [2002] 连接被拒绝”错误

    我正在尝试运行此 PHP 数据库的 CLI 版本搜索和替换脚本 https github com interconnectit Search Replace DB 但我认为这是一个与 Mac OS X 和 MAMP 相关的更常见的 MySQ
  • 如何使用 Errai 将 GWT 与 JAX-RS/RESTEasy 服务器集成?

    我想从 GWT 客户端应用程序调用使用 RESTEasy 和 JAX RS 创建的 REST 服务 使用 Errai 为服务器和客户端使用单一代码库的最佳流程是什么 我们都喜欢休息 它与供应商 平台和语言无关 调试 实施和访问都很简单 它为