使用Gradle构建JavaFX应用JAR时遇到三类问题求助
IntelliJ + Gradle构建JavaFX JAR问题解决方案
问题1:创建JavaFX应用类型JAR时提示“无法构建Artifact - 此JDK中无fx:deploy”(JDK 21)
原因
JDK 11起Oracle已移除fx:deploy工具,IntelliJ的JavaFX JAR Artifact模板依赖该废弃工具,因此报错。
解决方案
直接使用Gradle插件完成构建,无需依赖IntelliJ的旧模板:
- 你的
build.gradle已引入org.openjfx.javafxplugin和org.beryx.jlink插件,执行./gradlew jlinkZip即可构建模块化运行镜像压缩包,解压后直接运行启动脚本(Windows为app.exe)。 - 若需可执行JAR,可添加Shadow插件(见问题3解决方案)。
问题2:提取库到目标JAR后启动提示no main manifest attribute
原因
- 主类路径不匹配:
build.gradle中配置的主类是com.english.mobileexam.mobileexam.HelloApplication,但手动编写的manifest中Main-Class为com.english.mobileexam.mobileexam.Launch,路径不一致。 - manifest格式错误:
Class-Path字段换行后的缩进不符合规范,JVM无法正确解析manifest。
解决方案
- 修正
Main-Class为build.gradle中配置的正确主类,确保该类是项目的入口类(包含main方法)。 - 让Gradle自动生成manifest,避免手动编辑错误,在
build.gradle中添加jar任务配置:
jar { manifest { attributes( 'Main-Class': 'com.english.mobileexam.mobileexam.HelloApplication', 'Class-Path': configurations.runtimeClasspath.files.collect { it.name }.join(' ') ) } }
执行./gradlew jar即可生成正确配置的JAR文件。
问题3:复制库到输出目录并通过manifest链接时提示JAR损坏
原因
- manifest格式错误:手动编写的
Class-Path换行缩进不符合JAR规范,破坏了JAR文件结构。 - 模块化项目冲突:项目使用了
org.javamodularity.moduleplugin,传统可执行JAR方式与模块化机制不兼容,导致JAR无效。 - IntelliJ构建缓存问题:
out目录中的缓存文件导致打包异常。
解决方案
推荐使用Gradle插件完成构建,无需手动配置IntelliJ Artifact:
方式1:构建可执行JAR(Shadow插件)
在build.gradle中添加Shadow插件:
plugins { // 保留原有插件... id 'com.github.johnrengelman.shadow' version '8.1.1' } shadowJar { mergeServiceFiles() manifest { attributes 'Main-Class': 'com.english.mobileexam.mobileexam.HelloApplication' } }
执行./gradlew shadowJar,可执行JAR将生成在build/libs目录下。
方式2:构建模块化镜像(官方推荐)
直接使用已配置的jlink任务,执行./gradlew jlinkZip,生成的压缩包位于build/distributions,解压后运行对应平台的启动脚本即可。
若坚持使用IntelliJ Artifact
- 修正manifest格式:
Class-Path多行属性每行开头必须只有一个空格,且文件最后必须保留空行。 - 清理
out目录后重新构建,避免缓存干扰。
附用户提供的参考文件
Manifest文件内容
Main-Class: com.english.mobileexam.mobileexam.Launch Class-Path: junit-platform-engine-1.10.0.jar javafx-fxml-21-win.jar ikon li-javafx-12.3.1.jar ikonli-core-12.3.1.jar formsfx-core-11.6.0.jar jun it-platform-commons-1.10.0.jar javafx-swing-21-win.jar tilesfx-11.48.ja r javafx-controls-21.jar bootstrapfx-core-0.4.0.jar javafx-controls-21- win.jar javafx-base-21.jar javafx-base-21-win.jar javafx-graphics-21-wi n.jar validatorfx-0.4.0.jar javafx-web-21-win.jar junit-jupiter-api-5.1 0.0.jar javafx-media-21.jar controlsfx-11.1.2.jar junit-jupiter-engine- 5.10.0.jar opentest4j-1.3.0.jar javafx-graphics-21.jar javafx-media-21- win.jar
Build.gradle文件内容
plugins { id 'java' id 'application' id 'org.javamodularity.moduleplugin' version '1.8.12' id 'org.openjfx.javafxplugin' version '0.0.13' id 'org.beryx.jlink' version '2.25.0' } group 'com.english.mobileexam' version '1.0-SNAPSHOT' repositories { mavenCentral() } ext { junitVersion = '5.10.0' } sourceCompatibility = '21' targetCompatibility = '21' tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } application { mainModule = 'com.english.mobileexam.mobileexam' mainClass = 'com.english.mobileexam.mobileexam.HelloApplication' } javafx { version = '21' modules = ['javafx.controls', 'javafx.fxml', 'javafx.web', 'javafx.swing' ] } dependencies { implementation('org.controlsfx:controlsfx:11.1.2') implementation('com.dlsc.formsfx:formsfx-core:11.6.0') { exclude(group: 'org.openjfx') } implementation('net.synedra:validatorfx:0.4.0') { exclude(group: 'org.openjfx') } implementation('org.kordamp.ikonli:ikonli-javafx:12.3.1') implementation('org.kordamp.bootstrapfx:bootstrapfx-core:0.4.0') implementation('eu.hansolo:tilesfx:11.48') { exclude(group: 'org.openjfx') } testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}") } test { useJUnitPlatform()} jlink { imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip") options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages'] launcher { name = 'app' } } jlinkZip { group = 'distribution' }
内容的提问来源于stack exchange,提问作者Drained
相关产品推荐
相关产品推荐

