JavaFXおよびSpring。 一緒にもっと楽しく





この記事では、JavaFXやSpringなどを統合した経験についてお話したいと思います。 また、DerbyおよびMavenデータベースを使用してアプリケーションを構築します。



はじめに



JavaFXは、Javaプラットフォームにデスクトップソリューションを実装するための非常に便利で魅力的なテクノロジーのようです。 Java SE 7 Update 6以降、JavaFXはOracle Java SE実装の一部です。 ユーザー側で追加のインストールは必要ありません。



Springは、IoC、トランザクション管理などの形で便利な機能を提供しますが、これらは自分で実装したくないものです。





ハローワールド



FXMLを使用した簡単なアプリケーションから始めましょう。



アプリケーションクラス:

package ru.todolist; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; public class TodoApplication extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { Parent root = FXMLLoader.load(getClass().getResource("/fxml/main.fxml")); Scene scene = new Scene(root, 300, 275); primaryStage.setTitle("Todolist"); primaryStage.setScene(scene); primaryStage.show(); } }
      
      







このコードには、JavaFXアプリケーションのエントリポイントであるTodoApplicationクラスがあります。 FXMLLoaderを使用して、リソースから必要なビューを読み込みます。 ローダーは、Viewとともにコントローラーも初期化します。



main.fxml:

 <?xml version="1.0" encoding="UTF-8"?> <?import java.net.*?> <?import javafx.geometry.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.text.*?> <GridPane fx:controller="ru.todolist.controller.MainController" xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10" styleClass="root"> <Text id="welcome-text" text="Hello world!" GridPane.columnIndex="0" GridPane.rowIndex="0" GridPane.columnSpan="2"/> </GridPane>
      
      







一般的に、特別なことは何もありません。



Mavenでビルドする



アセンブリには、 Zen Javaの特別なプラグインを使用できます 。 JavaFXアプリケーションの構築に加えて、彼はJREとともにそのネイティブインストーラー(MSI、EXE、DMG、RPM)を構築できます。



pom.xmlの例:

 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ru.todolist</groupId> <artifactId>application</artifactId> <packaging>jar</packaging> <version>1.0.0</version> <properties> <log4j.version>1.2.17</log4j.version> </properties> <dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>com.zenjava</groupId> <artifactId>javafx-maven-plugin</artifactId> <version>2.0</version> <configuration> <mainClass>ru.todolist.TodoApplication</mainClass> </configuration> </plugin> </plugins> </build> </project>
      
      





ご覧のとおり、プラグインの設定で、アプリケーションのメインクラスへのパスを指定する必要があります。 しかし、これだけではありません。アプリケーションを起動する前に次のコマンドを実行する必要もあります。

 mvn com.zenjava:javafx-maven-plugin:2.0:fix-classpath
      
      





これがプラグインのドキュメントにある理由の詳細。



ダービーをつなぐ



完全な幸福のために、アプリケーションには本格的なデータベースがありません。



Derbyサービスを管理するための依存関係と、データベースにアクセスするためのドライバーを追加する必要があります。

 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ru.todolist</groupId> <artifactId>application</artifactId> <packaging>jar</packaging> <version>1.0.0</version> <properties> <derby.version>10.10.1.1</derby.version> ... </properties> <dependencies> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derbynet</artifactId> <version>${derby.version}</version> </dependency> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derbyclient</artifactId> <version>${derby.version}</version> </dependency> ... </dependencies> <build> ... </build> </project>
      
      







TodoApplicationクラスを少し変更して、データベースを起動および停止します。

 public class TodoApplication extends Application { private static Logger LOG = Logger.getLogger(TodoApplication.class); ... @Override public void init() { try { DbUtils.startDB(); } catch (Exception e) { LOG.error("Problem with start DB", e); } } @Override public void stop() { try { DbUtils.stopDB(); } catch (Exception e) { LOG.error("Problem with stop DB", e); } } }
      
      







DbUtilsクラス自体:

 package ru.todolist.utils; import org.apache.derby.drda.NetworkServerControl; import org.apache.log4j.Logger; import java.net.InetAddress; public class DbUtils { private static Logger LOG = Logger.getLogger(DbUtils.class); private static NetworkServerControl server; public static void startDB() throws Exception { LOG.info("Start DB"); server = new NetworkServerControl(InetAddress.getByName("localhost"), 1527); server.start(null); } public static void stopDB() throws Exception { LOG.info("Stop DB"); server.shutdown(); } }
      
      







春を追加



次に、Springに必要な依存関係を追加すると同時に、pom.xmlにHibernateを追加します。

 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ru.todolist</groupId> <artifactId>application</artifactId> <packaging>jar</packaging> <version>1.0.0</version> <properties> ... <spring.version>3.2.4.RELEASE</spring.version> <hibernate.version>4.2.6.Final</hibernate.version> </properties> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> ... </dependencies> <build> ... </build> </project>
      
      







ローダーを実装する必要があります。ローダーは、コントローラーとそれらのViewコンポーネントの読み込みを担当します。

 package ru.todolist.utils; import javafx.fxml.FXMLLoader; import javafx.scene.Node; import javafx.util.Callback; import org.apache.log4j.Logger; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import ru.todolist.config.AppConfig; import ru.todolist.controller.Controller; import java.io.IOException; import java.io.InputStream; public class SpringFXMLLoader { private static Logger LOG = Logger.getLogger(SpringFXMLLoader.class); private static final ApplicationContext APPLICATION_CONTEXT = new AnnotationConfigApplicationContext(AppConfig.class); public static Controller load(String url) { InputStream fxmlStream = null; try { fxmlStream = SpringFXMLLoader.class.getResourceAsStream(url); FXMLLoader loader = new FXMLLoader(); loader.setControllerFactory(new Callback<Class<?>, Object>() { @Override public Object call(Class<?> aClass) { return APPLICATION_CONTEXT.getBean(aClass); } }); Node view = (Node) loader.load(fxmlStream); Controller controller = loader.getController(); controller.setView(view); return controller; } catch (IOException e) { LOG.error("Can't load resource", e); throw new RuntimeException(e); } finally { if (fxmlStream != null) { try { fxmlStream.close(); } catch (IOException e) { LOG.error("Can't close stream", e); } } } } }
      
      







ご覧のとおり、Springアプリケーションコンテキストはコントローラーファクトリとして使用されます。 まず、必要なビューをURLからロードし、次に対応するコントローラーをロードします。



AppConfig.javaの例
 package ru.todolist.config; import org.hibernate.ejb.HibernatePersistence; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import java.util.Properties; @Configuration @ComponentScan("ru.todolist") public class AppConfig { @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.apache.derby.jdbc.ClientDriver"); dataSource.setUrl("jdbc:derby://localhost:1527/todo;create=true"); //Create DB if not exist dataSource.setUsername("user"); dataSource.setPassword("password"); return dataSource; } @Autowired @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource) { LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean(); Properties properties = new Properties(); properties.put("hibernate.dialect", "org.hibernate.dialect.DerbyDialect"); properties.put("hibernate.hbm2ddl.auto", "create"); bean.setPersistenceProviderClass(HibernatePersistence.class); bean.setDataSource(dataSource); bean.setJpaProperties(properties); bean.setPackagesToScan("ru.todolist.model"); return bean; } @Autowired @Bean public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory, DataSource dataSource) { JpaTransactionManager bean = new JpaTransactionManager(entityManagerFactory); bean.setDataSource(dataSource); return bean; } }
      
      









コントローラーには、コントローラーとビューをバインドできる次のインターフェイスを使用します。

 package ru.todolist.controller; import javafx.scene.Node; public interface Controller { Node getView(); void setView (Node view); }
      
      







抽象クラスAbstractController.javaでこれらのメソッドの実装を取り出します。

 package ru.todolist.controller; import javafx.scene.Node; public abstract class AbstractController implements Controller { private Node view; public Node getView() { return view; } public void setView (Node view){ this.view = view; } }
      
      







最後の仕上げとして、TodoApplicationクラスの標準ローダーの代わりにSprinFXMLLoaderを使用します。

 public class TodoApplication extends Application { ... @Override public void start(Stage primaryStage) throws Exception { MainController controller = (MainController) SpringFXMLLoader.load("/fxml/main.fxml"); Scene scene = new Scene((Parent) controller.getView(), 300, 275); primaryStage.setTitle("Todolist"); primaryStage.setScene(scene); primaryStage.show(); } ... }
      
      







まとめ



コードは非常に単純で、多くの倒錯はありませんでした。 その結果、JavaFXを使い慣れたテクノロジースタック(Java EE用)で使用し、使い慣れたパターンを使用してアプリケーションアーキテクチャを設計できます。



さらに、このアプローチをGuiceとの統合に使用できると言いたいです。



資源






All Articles