0%

用Maven管理JavaFX项目

JavaFX是Java的新兴GUI框架,界面比Swing更加友好一些,语法也很简单。软件工程大作业非常推荐用JavaFX换掉Swing,写起来会容易一点。

Maven管理Java项目,尤其是Spring项目,非常好用,可惜自己在上完Java课之后没好好学习这个重要的项目管理工具。之前在软工写大作业的时候用的是IDEA自带的项目结构,配置JavaFX非常复杂,用Maven的包也很麻烦,现在把之前的大作业升级成了Maven框架,编译、运行乃至Junit测试,都是一行简单的命令都可以完成的。在介绍JavaFX和Maven这对绝配组合之前,我先说一下我们组怎么编译JavaFX项目的。

命令行编译运行

JavaFX在JDK11之后就不属于JDK的一部分了,单独由开源社区进行维护。JDK11引入了module的概念,而JavaFX的SDK就是以module的形式提供了Jar包和JMod(用来生成自定义的JRE环境),具体可以查看廖雪峰的这篇

JavaFX lib

所以简单版本的编译命令根据JavaFX的教程,长这个样子:

1
2
3
4
5
// 编译
javac --module-path "C:\Program Files\Java\javafx-sdk-11.0.2\lib" --add-modules javafx.controls HelloFX.java

// 运行
java --module-path "C:\Program Files\Java\javafx-sdk-11.0.2\lib" --add-modules javafx.controls HelloFX

这里的JavaFX SDK的路径是根据我自己电脑来指定的,因为路径中有空格所以加上了双引号,后面加入了javafx.controls的模块。如果要用fxml的话要加入javafx.fxml的模块;要放视频的话要加入javafx.media的模块。

如果不用第三方库的话手写命令行也无妨,但一旦引入第三方库,比如fasterxml,得在classpath中加入,很麻烦,包多了容易错。

Maven来救命

Maven管理第三方包多的项目很方便。 如果是新项目可以直接按照上面IDEA的JavaFX教程,一口气能把下面的工作做完。

由于我们之前用的不是Maven,就只能手动配置了。先点击项目,add framework升级为Maven,可以参考这篇。然后根据JavaFX的官方Maven教程,首先在项目的pom.xml中加入JavaFX的Maven插件,这个负责的是编译和运行部分,它帮我们配置好了路径,后面我们一句简单的命令就可以直接运行。

1
2
3
4
5
6
7
8
9
10
11
12
<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version>
<configuration>
<mainClass>ui.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>

然后我们需要加入JavaFX的组件,也就是上面我们提到的module。这里我加入了javafx.controls和javafx.media两个组件,在maven中是依赖(dependency)。这里要注意的是,Windows和Linux可以用LTS的11版本,macOS请用17版本,不然字体会乱码。还有一个比较有意思的是Ubuntu视频会放不出来,这个Bug被吐槽了很久还是没修好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>compile</scope>
</dependency>
</dependencies>

最后我们只需要一行mvn clean javafx:run就可以运行了。如果是IDEA的话在maven配置中去掉mvn就行。

IDEA加入Maven运行

JUnit测试

如果是手动写命令行的话,JUnit测试也是非常麻烦,如果有很多测试的话手写命令行基本上没法弄。但是对于maven这实在是太简单了,把JUnit测试放在test/java文件夹,输入mvn test,一口气跑完所有的测试。

静态资源

JavaFX有css或者fxml文件,这些文件不能直接放在Java文件夹下,编译时会被忽略掉。要放在Resources文件夹下,编译时会被复制到classpath的根目录。这里我在resources文件夹下放了两个文件夹,一个放css,一个放图片。

静态资源位置

写路径的时候,比如在resources下面的css文件夹中新建了一个hello.css文件,那导入时路径写成:”/css/hello.css”。因为这个时候java下面的包和resources下面的文件夹会被放到classpath路径中。

classpath

JavaFX读取静态资源范例如下。Main.class也可以换成getClass()。

1
2
ImageView backgroundImage = new ImageView(
new Image(Objects.requireNonNull(Main.class.getResourceAsStream("/source/user/login.jpg"))));

视频有一点特殊,JavaFX的Media库只支持输入URL路径(本地或者网络),不支持输入流,所以不能放resources文件夹下。我们放项目项目目录data文件夹。

json和txt等文件也不能放resources文件夹,放在代码外面,我们同样放置在项目目录的data文件夹。

数据文件夹

发布

JavaFX的发布有一点麻烦。问题出在开头说的,现在的JRE缺少JavaFX的运行时,直接打一个Jar包发给别人,是不能运行的,会出现以下的提示。

错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序

一个解决方案就是自己打包一个JRE,然后和jar包一起发布。

自定义JRE

利用jlink我们可以自定义一个JRE,让其中拥有JavaFX的运行时。

首先去下载JavaFX的jmod。下载页面默认只提供最新的支持版本的包。点选Include older versions的选择框,然后翻到下面选择JavaFX 11或者JavaFX 17的jmod压缩包下载。JavaFX现在只有最新版提供免费的支持,像11或者17现在的LTS包得掏钱买支持,不过对于写大作业的大学生来说是不是最新版没差。

压缩包解压后把jmod包放到Java文件夹下的jmods文件夹。拿Java 11举例子。

jmods

然后在JavaFX的项目目录运行以下的命令。%JAVA_HOME%指的是Java的安装文件夹路径,可能需要在Windows环境变量中设置。Linux和macOS改为$JAVA_HOME或者直接替换为绝对路径。add-modules根据自己的项目需要增减。output表示输出的文件夹名称。

jlink --module-path "%JAVA_HOME%\jmods" --add-modules java.base,java.desktop,java.xml,javafx.base,javafx.graphics,javafx.media,jdk.jsobject,jdk.xml.dom,javafx.controls --output jre

运行之后会在项目目录新增一个名为jre的自定义jre环境。记得在gitignore中加入这个文件夹。

打包jar

直接打包mvn clean package打包是不行的,因为第一没有指定主类,第二是没有打包依赖。

对上面的的maven配置进行修改,增加以下plugin标签,参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>some.package.YourClass</mainClass> <!-- 指定程序入口点所在类 -->
</manifest>
</archive>
</configuration>
</plugin>

然后运行mvn clean package即可同时在target文件夹下得到主程序jar包和lib文件夹。lib文件夹里的是依赖jar包。

在项目目录输入以下命令即可运行jar包,jar包名字自行修改。

jre/bin/java.exe -jar target/your-application.jar

如果嫌开命令行麻烦的话可以写个脚本,或者拿C语言写个启动程序。

发布和压缩

target文件夹下可以只保留主程序jar包和lib文件夹,其他都可以删掉。然后拷贝target, jre和data文件夹到一个单独的文件夹,然后压缩这个文件夹即可。用户收到压缩包后解压,然后在文件夹运行上述命令即可运行。我们组的程序连带JRE压缩后为75M。

小结

Maven还是挺好用的,能够工程化地去编译、测试和打包Java程序,而不用手写命令,好评。

JavaFX框架实话说,已经脱离时代了。桌面端软件现在很多拿网页框架来做,比如flutter或者electron,JavaFX这种玩具未来注定会被淘汰。