让我们使用JavaFX 8和FXML创建最简单的Hello World应用程序:
文件src/application/Main.java
:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
@Override
public void start(Stage stage) {
try {
System.out.println("Main.start()");
FXMLLoader fxml_loader = new FXMLLoader();
fxml_loader.setLocation(getClass().getResource("Sample.fxml"));
System.out.println("FXML resource URL = " + getClass().getResource("Sample.fxml"));
Parent root = fxml_loader.load();
Scene scene = new Scene(root, 300, 200);
stage.setScene(scene);
stage.setTitle("JFX HW");
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
src/application/Sample.fxml
:<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.StackPane?>
<StackPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
<children>
<Label text="Hello World" />
</children>
</StackPane>
工作流程
使用您最喜欢的IDE,将所有内容编译到
bin
文件夹中:$ find bin
bin
bin/application
bin/application/Main.class
bin/application/Sample.fxml
然后创建一个罐子:
$ javapackager -createjar -appclass application.Main -srcdir bin -outdir compiled -outfile jfxhw -v -manifestAttrs "Application-Name=JFXHW,Permissions=sandbox,Codebase=*"
可以在此处验证jar文件与
java -jar jfxhw.jar
一起正常工作。让我们签名:
$ jarsigner compiled/jfxhw.jar MYALIAS
部署:
$ javapackager -deploy -appclass application.Main -srcdir compiled -outdir deployed -outfile index -width 300 -height 200 -name JFXHW -v
$ find deployed
deployed/
deployed/jfxhw.jar
deployed/index.jnlp
deployed/index.html
结果
命令:
javaws index.jnlp
失败(您需要启用控制台才能看到此信息):
Main.start()
FXML resource URL = null
java.lang.IllegalStateException: Location is not set.
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2438)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2413)
at application.Main.start(Main.java:18)
:
我究竟做错了什么?
最佳答案
问题
该应用程序需要足够的权限才能调用fxml文件。您没有在部署步骤中设置任何权限,因此在生成的jnlp文件中,省略了安全性部分。
有一个已知的错误,已计划在Java 9中修复。该错误与您的问题有关,但与根本原因无关。
https://bugs.openjdk.java.net/browse/JDK-8088866
用于jarsign和javapackager -signjar的不一致。
我试图摆脱它的尝试:
javapackager解决方案
将 -allpermissions 参数添加到命令行:
javapackager -deploy -allpermissions -appclass application.Main -srcdir compiled -outdir deployed -outfile index -width 300 -height 200 -name JFXHW -v
但是有一个小问题:您的manifest.mf将不包含空的Class-Path标记,因为它是由ant脚本添加的。将弹出Java安全提示,直到您将证书添加到操作系统中的受信任的根证书存储中后,您才能运行该应用程序。
蚂蚁脚本解决方案
首先我更改了deploy任务中的权限以将其设置为提升:
<fx:permissions elevated="true" cacheCertificates="true"/>
第二个我创建了以下build.xml文件,并将其放在项目的根目录中。您的jnlp将在文件夹dist中创建。而且,您必须为密钥库设置storepass。以及正确的别名和密钥库文件名。
如果您不在Windows上,则“env”可能无法工作。很难设置您的jdk。
只需在项目的根目录中使用“ant default”进行调用即可。
build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="App" default="default" basedir="."
xmlns:fx="javafx:com.sun.javafx.tools.ant">
<property environment="env"/>
<property name="build.src.dir" value="src"/>
<!-- <property name="build.resources.dir" value="${build.src.dir}/resources"/> -->
<property name="build.classes.dir" value="classes"/>
<property name="build.dist.dir" value="dist"/>
<target name="default" depends="clean,compile">
<!-- defines the classpath -->
<path id="cp">
<filelist>
<file name="${env.JAVA_HOME}/lib/ant-javafx.jar"/>
<file name="${basedir}" />
</filelist>
</path>
<!-- defines the task with a reference to classpath -->
<taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
uri="javafx:com.sun.javafx.tools.ant"
classpathref="cp"/>
<fx:application id="appId"
name="jfxHw"
mainClass="application.Main"/>
<!-- Defines the resources needed by the application -->
<fx:resources id="appRes">
<fx:fileset dir="${build.dist.dir}" includes="jfxHw.jar"/>
<!-- <fx:fileset dir="${build.dist.dir}" includes="bsigned_jfxHw.jar"/> -->
</fx:resources>
<!-- Create a jar file -->
<fx:jar destfile="${build.dist.dir}/jfxHw.jar">
<fx:application refid="appId"/>
<fx:resources refid="appRes"/>
<fileset dir="${build.classes.dir}"/>
<fileset dir="${build.src.dir}">
<exclude name="**/*.java"/>
</fileset>
<manifest>
<attribute name="Permission" value="all-permissions"/>
</manifest>
</fx:jar>
<signjar alias="myAlias" keystore="myKeystore.jks"
storepass="******"
preservelastmodified="true">
<path>
<fileset dir="${build.dist.dir}" includes="**/*.jar" />
</path>
</signjar>
<fx:deploy width="600" height="400" outdir="${basedir}//${build.dist.dir}/"
outfile="jfxhw" verbose="true">
<fx:info title="jfxHw"/>
<fx:application refid="appId"/>
<fx:resources refid="appRes"/>
<fx:permissions elevated="true" cacheCertificates="true"/>
</fx:deploy>
</target>
<!-- Removes the folders of previous runs -->
<target name="clean">
<mkdir dir="${build.classes.dir}"/>
<mkdir dir="${build.dist.dir}"/>
<delete>
<fileset dir="${build.classes.dir}" includes="**/*"/>
<fileset dir="${build.dist.dir}" includes="**/*"/>
</delete>
</target>
<!-- Compiles the sources -->
<target name="compile" depends="clean">
<javac includeantruntime="false"
srcdir="${build.src.dir}"
destdir="${build.classes.dir}"
fork="yes"
executable="${env.JAVA_HOME}/bin/javac"
source="1.8"
debug="on">
</javac>
</target>
</project>
清单文件
一切完成后创建。请注意,出于调试目的,我将清单权限设置为all-permissios。您可以安全地将其设置为沙箱。
Manifest-Version: 1.0
JavaFX-Version: 8.0
Permission: all-permissions
Class-Path:
Created-By: JavaFX Packager
Main-Class: application.Main
Name: application/Sample.fxml
SHA-256-Digest: eT8+7c2XeVhURexj5X9Y1xAP2H8YIMcieeySOmgOPZw=
Name: application/Main.class
SHA-256-Digest: Md+alMOmoQpslZIgLwbmPFAI8axSKBVvReXZFgoKJ6A=
jfxhw.jnlp
观看安全性部分:
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0" xmlns:jfx="http://javafx.com" href="jfxhw.jnlp">
<information>
<title>jfxHw</title>
<vendor>Unknown vendor</vendor>
<description>Sample JavaFX 2.0 application.</description>
<offline-allowed/>
</information>
<resources>
<j2se version="1.6+" href="http://java.sun.com/products/autodl/j2se"/>
<jar href="jfxHw.jar" size="3089" download="eager" />
</resources>
<security>
<all-permissions/>
</security>
<jfx:javafx-desc width="600" height="400" main-class="application.Main" name="jfxHw" />
<update check="background"/>
</jnlp>