在 JavaFX 2.0 中构建 Java EE 应用程序

作者:Daniel Zwolenski

在一系列创新性博客文章中,Downstream 高级 Java 架构师 Daniel Zwolenski 介绍了在 JavaFX 2.0 中构建 Java EE 应用程序的方法 — 从 Spring 到控制器注入到客户端服务器。

2012 年 2 月发布

下载:
下载Java EE
下载JavaFX 2.0
下载JFX Flow

注:JFX Flow 是免费的开源框架,用于使用 JavaFX(2.0 及更高版本)为桌面开发丰富的、交互式和用户友好的 Web 风格的 GUI。JFX Flow 将 JavaFX 的强大特性集(样式、动画、FXML 等)与简单、易于使用的“Web 流”式框架相结合,这种框架有助于架构模式整洁,尤其是在开发 Java EE 应用程序时。JFX Flow 目前处于 Alpha 版阶段,可能还有一些错误。 不过核心框架已经可以使用,且 API 相当稳定。

简介

本文是我介绍在 JavaFX 2.0 中构建 Java EE 应用程序的各种可选方法的系列文章中的第一篇。在本文中,我将 Richard Bair 的 FXML+Guice 依赖注入示例直接移植到了 Spring。(Richard Bair 是 Oracle 的客户端 Java 平台首席架构师。)许多开发人员仍然认为 Spring 是完全围绕 XML 配置文件的,但与早期相比,它已有很多发展。我将使用 Spring 基于批注的配置来创建一个纯 Java 示例(即零 Spring XML),它与那个 Guice 示例几乎一模一样。

第 1 步:创建 Person Bean

public class Person
{
    private String firstName;
 
    public Person(String firstName)
    {
        this.firstName = firstName;
    }
 
    public String getFirstName()
    {
        return firstName;
    }
}

清单 1. 创建 Person Bean

第 2 步:创建 SampleController

这与 Richard Bair 的示例类似,但我们用的不是 Guice 的 @Inject 批注,而是 Spring 的 @Autowire 批注(我对参数进行了批注,但如果需要,您可以使用构造器注入):

import org.springframework.beans.factory.annotation.Autowired;
 
public class SampleController
{
    @Autowired
    private Person person;
 
    public Person getPerson()
    {
        return person;
    }
 
    public void print()
    {
        System.out.println("Well done, " + person.getFirstName() + "!");
    }
} 

清单 2. 创建 SampleController

第 3 步:创建 FXML 文件

这与 Bair 的示例相同,只不过我使用的是 getPerson().getFirstName() 而不是 getPersonName() — 他也可以采用同样的办法,这一点上没有实质区别。

<?xml version="1.0" encoding="UTF-8"?>
 
<?language javascript?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
 
<StackPane fx:id="root" xmlns:fx="http://javafx.com/fxml">
    <children>
        <Button fx:id="printBtn" onAction="controller.print()" />
        <fx:script>printBtn.text = 'Click Me ' + controller.getPerson().getFirstName() + '!';</fx:script>
    </children>
</StackPane>

清单 3. 创建 FXML 文件

第 4 步:创建 Spring 应用程序上下文

事情从这里开始变得有趣起来。我们需要定义一个与 Guice 中的“Module”对应的 Spring 对应物。在本例中,我定义了一个名为 SampleAppFactory 的类(对此您可以任意命名),重要的是要用 Spring 的 @Configuration 对其进行批注。随后使用 @Bean 批注的每个方法均属于该上下文且 Spring 可替我们执行神奇的连接。在本例中,SampleController 将与 Person 连接,因为其中有 @Autowired 批注。

对于任何习惯用 Spring XML 的人来说,此类基本上就是直接替代 XML 配置文件:

import org.springframework.context.annotation.Configuration;
 
@Configuration
public class SampleAppFactory
{
    @Bean
    public Person person()
    {
        return new Person("Richard");
    }
 
    @Bean
    public SampleController sampleController()
    {
        return new SampleController();
    }
}

清单 4:创建 Spring 应用程序上下文

第 5 步:构建自定义 FXML 加载器

我们可以轻松构建 Bair 的 GuiceFXMLLoader 在 Swing 中的对应物。只需要从应用程序上下文而不是 Guice Injector 加载控制器。在另一篇博客文章中,我介绍了如何简化这一步。

import javafx.fxml.FXMLLoader;
import org.springframework.context.ApplicationContext;
 
import java.io.IOException;
import java.io.InputStream;
 
public class SpringFxmlLoader
{
    private ApplicationContext context;
 
    public SpringFxmlLoader(ApplicationContext context)
    {
        this.context = context;
    }
 
    public Object load(String url, Class<?> controllerClass) throws IOException
    {
        InputStream fxmlStream = null;
        try
        {
            fxmlStream = controllerClass.getResourceAsStream(url);
            Object instance = context.getBean(controllerClass);
            FXMLLoader loader = new FXMLLoader();
            loader.getNamespace().put("controller", instance);
            return loader.load(fxmlStream);
        }
        finally
        {
            if (fxmlStream != null)
            {
                fxmlStream.close();
            }
        }
    }
}

清单 5:构建自定义 FXML 加载器

第 6 步:创建“Application”以启动全部功能

这与 Guice 的方法很相似,只是我们加载的是应用程序上下文而不是 Guice 注入器:

import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
public class SampleApp extends Application
{
    public static void main(String[] args)
    {
        launch(args);
    }
 
    public void start(Stage stage) throws Exception
    {
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(SampleAppFactory.class);
        SpringFxmlLoader loader = new SpringFxmlLoader(context);
 
        Parent root = (Parent) loader.load("/sample.fxml", SampleController.class);
        Scene scene = new Scene(root, 320, 240);
        scene.getStylesheets().add("/fxmlapp.css");
        stage.setScene(scene);
        stage.setTitle("JFX2.0 Sprung");
        stage.show();
    }
}

清单 6:创建“Application”以启动全部功能

就是这样了!可以看到,该代码与 Guice 很相似,因此是选择 Guice 还是 Spring 应取决于两者各自提供的其他特性以及这些特性使您受益的程度。在后面的几篇文章中,我继续使用 Spring,但我所讲的内容大多可以轻松改编还原成 Guice。

另请参见

关于作者

Daniel Zwolenski(即“Zonski”)是澳大利亚布里斯班的一位软件架构师,他热衷于使用 Java 开发用户友好的图形应用程序。他认为对于应用程序而言,构建美观、简捷的用户界面与代码无差错和优化数据库查询同样重要。目前,他效力于一家名为 Downstream 的小型但富于创新精神的新公司,为重工业(能源、采矿、化工等)开发前沿安全系统。他开发的系统将挽救许多生命并减少由于大型工地上的事故对环境的破坏。