基于MVC架构,JavaFX与Spring整合

基于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

 
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/data/jpa
       http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!--包扫描-->
    <context:component-scan base-package="com.cjx913.al.controller"/>
    <context:component-scan base-package="com.cjx913.al.service"/>
    <context:component-scan base-package="com.cjx913.al.util"/>

    <!-- 数据库连接配置 -->
    <context:property-placeholder location="classpath:/config/database.properties"/>
    <!-- 数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${mysql.driver}"/>
        <property name="jdbcUrl" value="${mysql.url}"/>
        <property name="user" value="${mysql.username}"/>
        <property name="password" value="${mysql.password}"/>
        <property name="initialPoolSize" value="${connection_pools.initial_pool_size}"/>
        <property name="minPoolSize" value="${connection_pools.min_pool_size}"/>
        <property name="maxPoolSize" value="${connection_pools.max_pool_size}"/>
        <property name="maxIdleTime" value="${connection_pools.max_idle_time}"/>
        <property name="acquireIncrement" value="${connection_pools.acquire_increment}"/>
        <property name="checkoutTimeout" value="${connection_pools.checkout_timeout}"/>
    </bean>



    <!--JPA-->
    <!-- 实体管理器 -->
    <bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--实体类-->
        <property name="packagesToScan" value="com.cjx913.al.entity"/>
        <!--JPA实现厂商-->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
        </property>
        <!--JPA实现厂商的特定属性-->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!--数据库类型-->
                <property name="database" value="MYSQL"/>
                <property name="generateDdl" value="false"/>
                <property name="databasePlatform" value="${hibernate.dialect}"/>
                <property name="showSql" value="true"/>
                <property name="prepareConnection" value="true"/>
            </bean>
        </property>
        <!--指定一些高级特性-->
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
        </property>
        <!--指定JPA属性-->
        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.show_sql" value="${hibernate.show_sql}"/>
                <entry key="hibernate.format_sql" value="${hibernate.format_sql}"/>
                <entry key="hibernate.hbm2ddl.auto" value="${hibernate.hbm2ddl.auto}"/>
                <entry key="hibernate.query.substitutions" value="${hibernate.query.substitutions}"/>
                <entry key="hibernate.default_batch_fetch_size" value="${hibernate.default_batch_fetch_size}"/>
                <entry key="hibernate.max_fetch_depth" value="${hibernate.max_fetch_depth}"/>
                <entry key="hibernate.generate_statistics" value="${hibernate.generate_statistics}"/>
                <entry key="hibernate.bytecode.use_reflection_optimizer"
                       value="${hibernate.bytecode.use_reflection_optimizer}"/>
                <entry key="hibernate.cache.use_second_level_cache" value="${hibernate.cache.use_second_level_cache}"/>
                <entry key="hibernate.cache.use_query_cache" value="${hibernate.cache.use_query_cache}"/>
                <entry key="hibernate.current_session_context_class"
                       value="${hibernate.current_session_context_class}"/>
                <entry key="javax.persistence.validation.mode" value="${javax.persistence.validation.mode}"/>
            </map>
        </property>
    </bean>

    <!-- dao -->
    <jpa:repositories base-package="com.cjx913.al.dao"
                      repository-impl-postfix="Impl"
                      entity-manager-factory-ref="entityManagerFactory"
                      transaction-manager-ref="transactionManager"/>

    <!-- 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

    <!-- 支持注解方式声明式事务 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!--i18n-->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <!--引用资源文件-->
                <value>classpath:/i18n/validation_messages</value>
                <value>classpath:/i18n/ui_main</value>
                <value>classpath:/i18n/ui_login</value>
                <value>classpath:/i18n/ui_register</value>
            </list>
        </property>
        <property name="fileEncodings" value="utf-8"/>
    </bean>
    <bean id="resourceBundle" class="org.springframework.context.support.MessageSourceResourceBundle" >
        <constructor-arg name="source" ref="messageSource"/>
        <constructor-arg name="locale" >
            <bean class="java.util.Locale" factory-method="getDefault"/>
        </constructor-arg>
    </bean>


    <!--检验器-->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <!--由HibernateValidator提供实现-->
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
        <!--指定校验使用的资源文件,在文件中配置校验错误信息,如果不指定则默认使用classpath下的ValidationMessages.properties -->
        <property name="validationMessageSource" ref="messageSource"/>
    </bean>

</beans>

 

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 <T>
     * @return 错误字段和信息的映射
     */
    public <T> Map <String, String> validated(T t, Class <?>... groups) {
//        t爲空,返回null
        if (t == null) {
            return null;
        }
//        对t进行校验
        Set <ConstraintViolation <T>> violations = validator.validate(t, groups);
//        校检内有错误
        return getFieldErrorMap(violations);
    }

    public <T> Map <String, String> validated(T t, String propertyName, Class <?>... groups) {
//        t爲空,返回null
        if (propertyName == null || t == null) {
            return null;
        }
//        对t进行校验
        Set <ConstraintViolation <T>> violations = validator.validateProperty(t, propertyName, groups);

        return getFieldErrorMap(violations);
    }

    public <T> Map <String, String> validated(Class <T> beanType, String propertyName, Object value, Class <?>... groups) {
//        t爲空,返回null
        if (propertyName == null || value == null) {
            return null;
        }
//        对t进行校验
        Set <ConstraintViolation <T>> violations = validator.validateValue(beanType, propertyName, value, groups);

        return getFieldErrorMap(violations);
    }

    private <T> Map <String, String> getFieldErrorMap(Set <ConstraintViolation <T>> violations) {

        Map <String, String> map = null;
        //        校检内有错误
        if (violations.size() == 0) {
            return null;
        } else {
            map = new HashMap <>();
//        保存错误信息:Map<Field,Message>
            Iterator <ConstraintViolation <T>> iterator = violations.iterator();
            ConstraintViolation <T> 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 extends Node> T load(String url) {
        try (InputStream fxmlStream = getClass().getResourceAsStream(url)) {
            super.setLocation(this.getClass().getClassLoader().getResource("/"));
            super.setResources(resourceBundle);
            super.setControllerFactory(new Callback <Class <?>, 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的使用,还有数据绑定下次再写

 

 

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值