在理想的情况下,您可以将GWT应用程序编译为javascript,将其作为静态资源,并在后台将后端代码运行在JVM上,生活会很顺利。但这个理想的世界被称为运行时的生产。
然而,在开发期间,当您希望使用gwt代码服务器时。。。
您的GWT编译时依赖关系在运行时(源代码+类)是必需的,用于调试和重新编译GWT模块。
同时,您可能希望后端得到类似spring-boot1.3.5.RELEASE.的支持
在这种情况下,经历了多次频繁发布的spring-boot此时希望添加为托管依赖项,例如:
<hibernate-validator.version>5.2.4.Final</hibernate-validator.version>
当然,这是一件非常好的事情。事实上,这是春天的许多优点之一。
Gwt,另一方面,参见下面的链接,http://www.gwtproject.org/doc/latest/DevGuideValidation.html
仍然需要您使用:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.1.0.Final</version>
<scope>runtime</scope>
</dependency>
现在,如果你说:我不关心生产性开发,只要给我编译一些在生产中正常工作的东西就行了。
事实上,你可以通过以下方式构建你的项目来琐碎地解决上述问题:
ROOT
--- Backend-api
--- Backend-Impl
--- Gwt-Front-end
---- War or stand alone Spring jar module to glue it all together
对于某些RPC服务和DTO,Gwt前端依赖于后端API。pom.xml依赖项在很大程度上只能在前端模块中管理,与后端的依赖项无关。最终,您将创建一个war或spring-boot可运行jar,它将您的gwt代码作为静态资源,并将您的后端代码及其所有依赖项,即Hirbernate验证器的最新版本。
然而,当你试图获得一个适用于开发目的的pom时,据我所见,你不得不全局管理ROOT pom.xml中后端和前端层之间的通用依赖关系,并将依赖关系降级到gwt所需的版本。
也就是说,在理想的世界场景中。ROOTpom.xml只是简单地声明模块和它们的构建顺序。您可以让您的后端impl能够声明它希望从spring-boot-starter pom.xml等继承依赖项…
与理想的场景相反,在pom.xml配置上,它实际上在开发过程中帮助了您。。。好吧,您可能需要重新访问Root-pom.xml。您必须在这个根pom.xml上添加托管依赖项,这样,对于GWT前端和spring-boot后端之间所有常见的冲突依赖项,您总是必须敲定GWT的版本并进行降级。
这将确保在执行gwt:run、dev-mode重新编译等操作时,gwt编译器不会试图用javascript编译Hibernate版本5,而是GWT4.1最终支持的版本。当然,你可能会在后端代码中遇到一个惊喜,总有一天,你会发现这样一个黑客。。。
有人知道如何正确组织一个多模块项目吗?在这个项目中,后端和基于gwt的前端可以有相互冲突的depency需求?
最终,如果答案是否定的,我相信我更愿意通过拥有一个与纯gwt独立码头集成的纯独立春季启动后端来减少网络浪费和增加通信延迟,而这个码头上的后端只会愚蠢地将请求踢到实际的春季启动后端。让gwt-jetty后端被UI调用进行1+1,并将计算转发给第二个运行sprin boot的后端,这个后端实际上知道如何进行1+1……这有点可悲……但如果这是最高效的工作方式,确保开发富有成效,生产运行不会有意外,那就顺其自然吧。
感谢您的反馈,理想情况下,我希望看到一个多pom项目,您可以将其作为现有的maven项目导入eclipse,并演示如何实现这一点。
找出编译GWT代码时要排除的可传递依赖项的位置。
<dependency>
<groupId>spring-dependency-with-hibernate</groupId>
<artifactId>some-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</exclusion>
</exclusions>
</dependency>
这样,只有GWT提供的hibernate
版本在运行时才可用。
是的,我想做的事情实际上可以做到,尽管不是微不足道的。。。一点也不。
为了设置一个可以有效使用的maven多模块pom,即您可以在不需要选择gwt验证器依赖项或springboot验证器依赖项的情况下进行后端和前端代码的代码交换,我基本上按照以下方式组织我的项目。
您有:
LEVEL 1: myproject-root
----- LEVEL 2: myproject-backend
---------- LEVEL 3: myproject-backend-api
---------- LEVEL 3: myproject-backend-impl
------ LEVEL 2: myproject-frontend
------ LEVEL 2: myproject-runner
-----------LEVEL 3: myproject-runner-jar
-----------LEVEL 3: myproject-runner-war
在myprojectroot中,您可以自然地声明子模块。你可以对一些不相干的插件进行依赖管理,比如surefire插件。您可以控制java源代码和目标编译语言。你只做了很少的事。如果你有一些插件可以交叉配置,你也可以把它们放在插件管理中。
在myproject后端,通过在依赖项管理中添加,您基本上可以将springboot依赖项继承到依赖项管理
<dependencyManagement>
<dependencies>
<!-- Inherit dependencies from spring boot dependency management pom -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${version.spring.boot}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
你声明了这两个子模块,就出局了。您没有在此处声明任何交叉切割依赖项。您只使用依赖关系管理。前端组件将触及api子模块,并且您不希望在后端pom中创建依赖磁铁,因此在这里您尽可能保守。
在myproject后端api中,首先让这个子模块成为jar子模块。接下来,您将希望通过按入口点性质细分api-s来进一步分支api组件。首先,-api组件将具有服务器和前端之间通信所需的api,有点像文档中常见的"共享"。在这里,您要尽可能小心地在dependencies元素中尽可能少地使用元素。前端将使用这些api,并且您不希望您的api包依赖于任何spring-boot api。
在后端impl中,您可以编写实际的业务逻辑,并且可以自由地依赖于完整的spring引导堆栈。规则是,确保没有人指向这个依赖磁铁,尤其是永远不要让gwt组件嗅到springboot库的存在。永远不要提及它。
在myproject前端,您不会像使用api组件那样将其分支到不同的子模块中。在这里,您为gwt代码制作了一个单一的组件,这样您就可以更容易地让gwt-maven插件为您重新编译热代码。在这个组件中,您依赖于myprojectapi,以及任何相关的gwt库,如gwt用户、gwt所需的旧版本的hibernate验证器等。。。myproject前端的规则是将组件中的每个依赖项声明为可选项。您不希望对组件采取任何传递依赖性。在生产中,您只需要myprojectfrontend.jar/META-INF/resources/MyProjectModule.html。。。以及springboot必须检测和服务的所有这些静态资源。然而,当您处于开发模式时,您希望在此前端组件中执行的操作是:(a) 调整您的gwt插件,使其不运行jetty服务器
<noServer>true</noServer>
关键是,如果运行这个jetty服务器,它类路径中唯一的东西就是前端代码和api,而绝对不是impl代码。第二,你不想使用gwt码头,你要么想使用springboot tomcat,要么想使用spring boot码头。将springboot的嵌入式容器与适当的websocket库等一起使用要好得多。
(b) 使用springboot,您希望从META-INF/resources/或公用文件夹中为静态资源提供服务器。我更喜欢资源,因为它通常也会放在JSF组件的地方。在任何情况下,因为静态资源的来源是特殊的,所以您需要调整您的gwt插件,以便将您的java源代码编译到write文件夹中。
<webappDirectory>${project.build.directory}/classes/META-INF/resources</webappDirectory>
就像上面一样。
最后,这是我的主要错误,您没有从编写前端代码的地方运行代码。这是错误的,因为这会迫使前端代码需要springboot依赖性,这会因为库冲突而给您带来极大的痛苦。
因此,为了避免这个问题,你创建了myprojectrunner组件,如果你想非常详细,你可以将其作为pom父组件,这样你就可以将你的包装分成jar或war。我个人更喜欢可执行jar,而不是war选项。我永远不想在像一个重量级的weblogic中部署sprinboot应用程序。。。但不管是什么让你的船摇晃。
在任何情况下,spring-bootrunner都是您的最终依赖magenet。这个组件将依赖于您拥有的几乎每个模块及其可传递的依赖关系。但是,因为您将runner组件与前端代码分离,并且您使前端代码中的所有依赖项都是可选的。。。实际上,您只绑定了springboot和您的gwt静态资源。
当你在发展的时候,你所做的就是。。。。一旦你知道了。。。易于理解的(A) 您可以通过触发主文件来启动spring-boot-jar应用程序。如果你真的想部署一个war文件,这是你的选择,你也可以构建一个war文件并将其部署到tomcat或其他什么。。。
(b) 转到前端组件,点击它,选择run as Maven Build,然后选择gwt:run。gwt运行将启动gwt代码服务器,它将对您的后端代码完全视而不见,它眼前唯一看到的是您在前端组件中的代码,以及您作为optinal添加的所有gwt依赖项。
如果您使用的是springboot dev,那么您最终可以在后端热交换代码。一旦你启动了gwt插件,你就可以在这个单一系统的前端组件中热交换代码了。
结论,这是可能的,但它是地狱般的混乱。很高兴这个问题解决了。
我相信我在使用Eclipse IDE、GWT Google Plugin、SpringBoot和Maven时也遇到了类似的问题,并发现了以下问题。食谱并不简单,但它对我的团队很有效。
GWT-dev和Jetty服务器不适用于SpringBoot。由于Jetty和gwt-dev的硬编码依赖关系,您必须修复类路径,只有针对gwt-dev和Jetty构建的依赖关系才能工作。
我不得不将GWTUI项目拆分为两个Maven工件。一个工件是WebApp,它只能在Eclipse中运行,所有SpringBoot库都被排除在类路径之外。另一个工件是一个可部署的SpringBootJAR,它具有"war"maven封装类型和Eclipse专用工件的war覆盖,只包括GWT特定内容。
我希望这能帮助
只需为运行GWT代码服务器创建专用的maven配置文件,并在中添加"GWT-dev"依赖项
<profiles>
<profile>
<id>gwt-dev</id>
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-dev</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>${gwt.version}</version>
<executions>
<execution>
<id>run-codeserver</id>
<goals>
<goal>run-codeserver</goal>
</goals>
</execution>
</executions>
<configuration>
<sourceLevel>${java.version}</sourceLevel>
<module>kn.iopm.documentserver.IDocServer</module>
<extraJvmArgs>-Xmx1G -Xms512M -Xss1G -Dlog.root=${project.build.directory}/log
</extraJvmArgs>
<runTarget>index.html</runTarget>
<persistentunitcachedir>${project.build.directory}</persistentunitcachedir>
<webappDirectory>${project.build.outputDirectory}/public</webappDirectory>
<deploy>${project.build.directory}/gwt-deploy</deploy>
<codeServerWorkDir>${project.build.directory}/gwt</codeServerWorkDir>
<launcherDir>${project.build.outputDirectory}/static</launcherDir>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>