基于MVC架构,JavaFX与Spring整合
探究了几天JavaFX,,因为它自身的一些优点,觉得JavaFX在将来的开发中会发展起来的。选择JavaFX因为自己本身Javaer,JavaFX的学习成本不高。而JavaFX跟MVC的开发有点像,同样可以将视图、模型、和控制器分开。对于JavaFX的UI表现我觉得算是Java里面自由性最好的。
JavaFX从08年到现在也差不多10年,虽然2.0版本后有很大的变化,在国内的教程更新地慢。找了几天JavaFX的资料,国内的资料真的少,而且大多是翻译官方的。
JavaFX可以整合spring,而spring可以整合数据库的操作,并且可以使用spring实现一些基础功能。现在将工程目录架构整理如下:
使用maven管理,
java文件夹的包有controller、dao、entity、service、还有一个util工具包和Main.java作为程序主入口。
resources文件夹中有config(spring配置文件)、css(样式文件)、fxml(场景的fxml文件)、i18n(国际化资源文件)
util工具包包含一些工具类,在这里主要实现的功能是FXML加载,JSR303验证和获取国际化资源。
下面来说说功能的实现,首先看看spring的配置文件spring-config.xml
classpath:/i18n/validation_messages
classpath:/i18n/ui_main
classpath:/i18n/ui_login
classpath:/i18n/ui_register
i18n类的实现,主要是在spring配置实现对资源文件的引用,可以通过getMessage(String s)获取资源信息
package com.cjx913.al.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.stereotype.Component;
import java.util.Locale;
import java.util.ResourceBundle;
@Component
public class I18n {
@Autowired
private ResourceBundle resourceBundle;
public ResourceBundle getResourceBundle() {
return resourceBundle;
}
public String getMessage(String s){
return this.resourceBundle.getString(s);
}
}
Jsr303Validation类的实现,依赖于spring配置的validator,重写了验证方法,返回字段名和错误信息映射的Map
package com.cjx913.al.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@Component
public class Jsr303Validator {
@Autowired
private Validator validator;
public Validator getValidator() {
return validator;
}
/**
* @param t 需要校检的对象
* @param
* @return 错误字段和信息的映射
*/
public Map validated(T t, Class >... groups) {
// t爲空,返回null
if (t == null) {
return null;
}
// 对t进行校验
Set > violations = validator.validate(t, groups);
// 校检内有错误
return getFieldErrorMap(violations);
}
public Map validated(T t, String propertyName, Class >... groups) {
// t爲空,返回null
if (propertyName == null || t == null) {
return null;
}
// 对t进行校验
Set > violations = validator.validateProperty(t, propertyName, groups);
return getFieldErrorMap(violations);
}
public Map validated(Class beanType, String propertyName, Object value, Class >... groups) {
// t爲空,返回null
if (propertyName == null || value == null) {
return null;
}
// 对t进行校验
Set > violations = validator.validateValue(beanType, propertyName, value, groups);
return getFieldErrorMap(violations);
}
private Map getFieldErrorMap(Set > violations) {
Map map = null;
// 校检内有错误
if (violations.size() == 0) {
return null;
} else {
map = new HashMap <>();
// 保存错误信息:Map
Iterator > iterator = violations.iterator();
ConstraintViolation violation = null;
// 遍历校验信息
while (iterator.hasNext()) {
violation = iterator.next();
String field = violation.getPropertyPath().toString();
String message = violation.getMessage();
map.put(field, message);
}
return map;
}
}
}
重点是SpringFXMLLoader的实现
package com.cjx913.al.util;
import com.cjx913.al.Main;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.util.BuilderFactory;
import javafx.util.Callback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.MessageSourceResourceBundle;
import org.springframework.stereotype.Component;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.LinkedList;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
@Component
public class SpringFxmlLoader extends FXMLLoader {
@Autowired
private ResourceBundle resourceBundle;
public T load(String url) {
try (InputStream fxmlStream = getClass().getResourceAsStream(url)) {
super.setLocation(this.getClass().getClassLoader().getResource("/"));
super.setResources(resourceBundle);
super.setControllerFactory(new Callback , Object>() {
@Override
public Object call(Class > clazz) {
return Main.APPLICATION_CONTEXT.getBean(clazz);
} }); return this.load(fxmlStream); } catch (IOException ioException) { throw new RuntimeException(ioException); } }}
FXMLLoader对象的需要调用setResource()绑定资源,可以在fxml使用%实现国际化的目的,而参数可以通过spring注解注入、setLocation()设至基本路径,方便fxml中css和fxml和其他文件导入、setControllerFactory()使用spring管理的controller。
这是一个普通的Main类用于启动JavaFX程序和spring
package com.cjx913.al;
import com.cjx913.al.util.SpringFxmlLoader;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main extends Application {
public static final ApplicationContext APPLICATION_CONTEXT
= new ClassPathXmlApplicationContext("/config/spring-config.xml");
public static void main(String[] args){
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
SpringFxmlLoader springFxmlLoader = Main.APPLICATION_CONTEXT.getBean(SpringFxmlLoader.class);
BorderPane root = springFxmlLoader.load("/fxml/main.fxml");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
}
public static final ApplicationContext APPLICATION_CONTEXT
= new ClassPathXmlApplicationContext("/config/spring-config.xml");
public static void main(String[] args){
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
SpringFxmlLoader springFxmlLoader = Main.APPLICATION_CONTEXT.getBean(SpringFxmlLoader.class);
BorderPane root = springFxmlLoader.load("/fxml/main.fxml");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
}
BaseController的实现,用于被其他controller类继承,获取一些公共的方法,在controller类中使用@Controller注解
package com.cjx913.al.controller;
import com.cjx913.al.util.I18n;
import com.cjx913.al.util.Jsr303Validator;
import com.cjx913.al.util.SpringFxmlLoader;
import javafx.fxml.Initializable;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class BaseController implements Initializable {
@Autowired
private SpringFxmlLoader springFxmlLoader;
@Autowired
private I18n i18n;
@Autowired
private Jsr303Validator jsr303Validator;
public SpringFxmlLoader getSpringFxmlLoader() {
return springFxmlLoader;
}
public I18n getI18n() {
return i18n;
}
public Jsr303Validator getJsr303Validator() {
return jsr303Validator;
}
}
尽可能减少java代码创建容器、控件等,应该使用fxml创建用户界面
关于fxml的使用,还有数据绑定下次再写