当前位置: 首页 > 工具软件 > Spring4GWT > 使用案例 >

带Spring Boot的GWT

汝楷
2023-12-01

介绍

我最近一直在研究用Java编写UI代码的选项。 在我以前的文章中,我研究了Eclipse RAP,发现它可以与Spring Boot集成在一个可执行jar中。 这次我想对GWT做同样的技巧。

每个人都喜欢Spring Boot。 它使很多事情变得更加干净和容易。 但是从历史上看,用于在Web浏览器中创建UI的框架具有自己的方法来完成Spring Boot的某些工作。 不幸的是,在许多情况下,它们的方法看起来过时且过时。 因此,目标是尽可能使用Spring Boot并将GWT仅用于UI。

我必须警告读者,这篇文章实际上是TL; DR :-)的经典示例。

GWT方法

GWT使用特殊的编译器从Java代码生成Javascript代码。 该方法是创建一个模块描述文件.gwt.xml,用它导入其他模块,并使用GWT小部件用Java编写代码。 然后,他们的编译器将生成许多javascript代码,这些代码需要包含在html页面中。 他们在www.gwtproject.org上有一个讲解基本知识的教程

他们使用GWT RPC在后端调用方法。 这种方法需要在客户端和服务器之间共享一个接口。 客户端使用该接口来调用RPC方法。 该方法的服务器端实现在web.xml中注册为具有适当URL模式的Servlet。

我认为一个主要问题是调试。 最新版本的GWT采用了一种彻底的源地图方法。 这意味着Java代码调试在启用了源映射的浏览器中进行 ,而不是在Eclipse中进行(或者也许我无法使其在Eclipse中工作)。 我在Chrome浏览器中进行了尝试,它确实可以工作,但看起来有点麻烦。 默认情况下,GWT甚至不生成源映射。 为了使用它们,必须启动代码服务器并从此代码服务器在html页面中加载不同的javascript。 在这种情况下,大多数人都会向编译器添加一个选项。

我的意思是对GWT团队和这项技术的支持者没有冒犯,但总体而言,它看起来有些过时了。 他们不会花费太多时间来开发新功能。 甚至构建插件也由发烧友维护。

目标

这是我在调查中想要实现的目标:

  1. 仅将GWT用于生成将与其他所有内容一起归档到可执行jar中的Javascript代码。
  2. 将Spring Boot用于REST端点并完全避免GWT RPC
  3. 使用Spring Boot的可执行jar启动应用程序,并使用嵌入式Tomcat服务GWT html文件。 这也意味着可以使用所有其他出色的Spring Boot功能。

制作工具

为了实现目标1,我们需要一个好的构建工具。 我已经使用Maven插件从教程中创建了示例项目。 这是对我有用的完整配置:

<plugin>
<groupId>net.ltgt.gwt.maven</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.0-rc-6</version>
<executions>
<execution>
<goals>
<goal>import-sources</goal>
<goal>compile</goal>
<goal>import-test-sources</goal>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<moduleName>org.example.gwt.StockWatcher</moduleName>
<moduleShortName>StockWatcher</moduleShortName>
<failOnError>true</failOnError>
<!-- GWT compiler 2.8 requires 1.8, hence define sourceLevel here if you use
a different source language for java compilation -->
<sourceLevel>1.8</sourceLevel>
<!-- Compiler configuration -->
<compilerArgs>
<!-- Ask GWT to create the Story of Your Compile (SOYC) (gwt:compile) -->
<arg>-compileReport</arg>
<arg>-XcompilerMetrics</arg>
</compilerArgs>
<!-- DevMode configuration -->
<warDir>${project.build.directory}/${project.build.finalName}</warDir>
<classpathScope>compile+runtime</classpathScope>
<!-- URL(s) that should be opened by DevMode (gwt:devmode). -->
<startupUrls>
<startupUrl>StockWatcher.html</startupUrl>
</startupUrls>
</configuration>
</plugin>

使用GWT Eclipse插件,我可以使其工作,甚至调试也可以在Chrome中进行,因为Eclipse的GWT插件会自动启动代码服务器,并以某种方式更新html文件以从代码服务器加载javascript。

最重要的是:GWT Maven插件有效:-))。 但是,将Spring Boot和GWT集成起来将是一项复杂的任务。 我需要先运行GWT编译,然后将结果javascript添加到可执行文件Jar中。 也许可以用Maven做到这一点,但是对于这个任务,我决定使用Gradle

Gradle是一种快速发展的构建工具。 DSL和API尚不稳定,但提供了很大的灵活性。 虽然Maven的构建阶段相当直线,但是Gradle可以按任何顺序执行任务。 我需要这种灵活性。

经过一番挖掘,我发现了一个适用于GWT的Gradle插件: de.esoco.gwt 。 它是Putnami插件的分支。 该文档足以使该插件正常工作。 我没有发现任何重大问题。 build.gradle中的配置位于gwt块内:

gwt {
 gwtVersion = gwtVersion

 module("org.example.gwt.StockWatcher2", "de.richsource.gradle.plugins.gwt.example.Example")
        // other configuration options
}

该插件将一些任务添加到了gradle构建中。 其中最重要的是gwtCompile 。 该任务实际上生成了javascript代码,并将其放入${buildDir}/gwt/out 。 这些值(gwt和out)都在Gradle GWT插件中进行了硬编码。

重要的是要记住,编译成javascript的代码是在GWT模块文件中指定的,如下所示:

<source path='client'/>
<source path='shared'/>

休息和休息

下一个目标是使用Spring Boot的REST端点。 我发现RestyGWT可以帮助我做到这一点。 他们在首页上有一个简单的方法。

我将所需的依赖项添加到build.gradle中:

implementation("javax.ws.rs:javax.ws.rs-api:2.0.1")
compileOnly group: "org.fusesource.restygwt", name: "restygwt", version: "2.2.0"
implementation group: "com.fasterxml.jackson.jaxrs", name: "jackson-jaxrs-json-provider", version: "2.8.9"

JAX-RS依赖关系是必需的,因为RestyGWT使用JAX-RS的注释来声明端点。 据我了解,Jackson也有必要解析JSON。

我也在GWT模块中添加了依赖项:

<inherits name="org.fusesource.restygwt.RestyGWT"/>

这是我用RestyGWT创建的服务:

public interface TestService extends RestService {

    @GET
    @Path("test") void test1(@QueryParam("input") String inp,    
        MethodCallback<TestResult> callback);
}

我在ClickHandler中调用此服务(我主要使用了原始GWT教程中的代码):

private final TestService testSrv = GWT.create(TestService.class);
btnCallServer.addClickHandler(clkEvent -> {
    testSrv.test1("TestString", new MethodCallback<TestResult>() {

        @Override
        public void onSuccess(Method method, TestResult response) {
            testLabel.setText("Srv success " + response.getStr1());
        }

        @Override
        public void onFailure(Method method, Throwable exception) {
            testLabel.setText("Srv failure " + exception.getMessage());
        }
    });
});

该服务在Spring Boot控制器中调用此简单方法:

@GetMapping("/test")
public TestResult test1(@RequestParam(name="input", required=false) String inp) {
return new TestResult(inp + " qqq");
}

好消息是所有这些代码都是一个可执行jar的一部分。

可执行罐

第三个目标是将所有内容实际捆绑到一个可执行文件胖子中。 在本部分中,我最终可以利用Gradle的灵活性。

首先,我将html文件放在/src/main/resources/static

我创建了一个任务,用于在生成过程中将生成的javascript复制到$ {buildDir}中的静态文件夹中:

task copyGWTCode(dependsOn: ["gwtCompile"], type: Copy) {
    from file("${buildDir}/gwt/out")
    into file("${buildDir}/resources/main/static")
}

接下来,我使bootJar任务依赖于此任务,并将jar复制到更传统的目标目录中:

bootJar {
    dependsOn copyGWTCode
    doLast {
        mkdir "${buildDir}/target"
        setDestinationDir(file("${buildDir}/target"))
        copy()
    }
}

在GWT中进行调试

关于GWT调试的另一章。

我找到了一种在Chrome中调试GWT UI的相当简单的方法(Chrome可以比Firefox更好地处理它)。 以下是使其工作的步骤。 我使用了GWT教程中的项目,但将其重命名为“ stockwatcher2”。

1.src/main/resources/static添加一个新的html文件进行调试。 例如,如果原始文件为StockWatcher2.html,则新文件应为StockWatcher2debug.html。 在这个新文件中,替换该行

<script type="text/javascript" src="stockwatcher2/stockwatcher2.nocache.js"></script>

这行代码(来自代码服务器的javascript):

<script src="http://localhost:9876/recompile-requester/stockwatcher2"></script>

2.执行任务bootJar并运行它。
3.使用“ gradle gwtCodeServer”从项目文件夹启动代码服务器。
4.在Chrome中打开http://<host>:<port>/<somepath>/StockWatcher2debug.html 5.现在,您可以在Developer Tools-> Sources下的127.0.0.1:9876下找到源映射。 可以设置断点并直接在Chrome中点击。

使用单独文件的想法是将其从生产版本中排除,但将其保留在开发人员版本中。 使用Gradle很容易。 这种方法只有一个问题,那就是从调试源调用的REST端点与从“正常”源调用的REST端点不同。 再添加一个映射即可解决该问题。

结论

我祝贺已经得出这一结论的英雄人物! 你是真正的程序员,而那些放弃的人却是胆小鬼!

但最重要的是,与GWT合作非常困难。 生成工具非常笨拙,缺少重要功能。 实际上没有集成(例如与Spring Boot集成)。 调试是不必要的复杂操作。

如果有人要在GWT和Eclipse RAP之间进行选择,我会推荐Eclipse RAP。

没有幸福的结局:-(。

翻译自: https://www.javacodegeeks.com/2018/11/gwt-spring-boot.html

 类似资料: