update:调整项目结构,将example独立抽离module
This commit is contained in:
68
javafx-plus/pom.xml
Normal file
68
javafx-plus/pom.xml
Normal file
@@ -0,0 +1,68 @@
|
||||
<?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">
|
||||
<parent>
|
||||
<artifactId>javafx-plus-parent</artifactId>
|
||||
<groupId>com.gitee.Biubiuyuyu</groupId>
|
||||
<version>1.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>javafx-plus</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<!--配置Maven 对resource文件 过滤 -->
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
<include>**/*.xml</include>
|
||||
<include>**/*.fxml</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<compilerArgs>
|
||||
<!-- 过期的方法的警告-->
|
||||
<arg>-Xlint:deprecation</arg>
|
||||
</compilerArgs>
|
||||
<compilerArguments>
|
||||
<!-- 是否输出所有的编译信息(包括类的加载等)-->
|
||||
<!--<verbose />-->
|
||||
<!-- 解决maven命令编译报错,因为rt.jar 和jce.jar在jre的lib下面,不在jdk的lib下面,
|
||||
导致maven找不到(java7以后会出现这个问题),将这2个jar包拷贝到jdk的lib下面估计也好使-->
|
||||
<bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath>
|
||||
</compilerArguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Inherited
|
||||
public @interface FXBind {
|
||||
String[] value();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.entity.FXPlusLocale;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* This is use for marking A controller as FX-Plus Controller
|
||||
*
|
||||
* @author jack
|
||||
* @author suisui
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 1:34
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Inherited
|
||||
public @interface FXController {
|
||||
String path();
|
||||
|
||||
double preWidth() default 0.0;
|
||||
|
||||
double preHeight() default 0.0;
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @description 程序语言,默认不设置
|
||||
* @version 1.2
|
||||
*/
|
||||
FXPlusLocale locale() default FXPlusLocale.NONE;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 1:36
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Inherited
|
||||
public @interface FXData {
|
||||
String fx_id() default "";
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 1:35
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Inherited
|
||||
public @interface FXEntity {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/27 20:10
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface FXField {
|
||||
boolean readOnly() default false;
|
||||
|
||||
String setter() default "";
|
||||
|
||||
String add() default "";
|
||||
|
||||
String delete() default "";
|
||||
|
||||
String edit() default "";
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 13:06
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface FXReceiver {
|
||||
String name();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.1
|
||||
* @description 重定向的注解
|
||||
* @date 2019/12/3 12:53
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Inherited
|
||||
public @interface FXRedirect {
|
||||
boolean close() default true;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @date 2019/6/25 2:55
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface FXScan {
|
||||
String[] base() default ".";
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* This cn.edu.scau.biubiusuisui.annotation is used for a method which can send a signal to all consumer
|
||||
* And FXSender has a name which is used for identifying different method
|
||||
* It is legal to use same method which has same name because JavaFX-Plus will identify a method with its full class name
|
||||
* In addition ,name is optional , default name will be the class name and method name
|
||||
* you can use this cn.edu.scau.biubiusuisui.annotation as the following cn.edu.scau.biubiusuisui.example
|
||||
* <p>
|
||||
* \@FXSender
|
||||
* public class A{
|
||||
* public void test(){
|
||||
* <p>
|
||||
* }
|
||||
* }
|
||||
* name will be A.name(It will only contain base class name and this name)
|
||||
* or you can use
|
||||
*
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @FXSernder("testDemo") public class A{
|
||||
* public void test(){
|
||||
* <p>
|
||||
* }
|
||||
* }
|
||||
* name will be A.testDemo
|
||||
* @date 2019/6/25 13:02
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface FXSender {
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/27 3:06
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Inherited
|
||||
public @interface FXValue {
|
||||
String value();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package cn.edu.scau.biubiusuisui.annotation;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.entity.FXPlusLocale;
|
||||
import javafx.stage.StageStyle;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @author suisui
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 1:36
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Inherited
|
||||
public @interface FXWindow {
|
||||
double preWidth() default 0.0;
|
||||
|
||||
double preHeight() default 0.0;
|
||||
|
||||
double minWidth() default 0.0;
|
||||
|
||||
double minHeight() default 0.0;
|
||||
|
||||
boolean resizable() default false;
|
||||
|
||||
boolean draggable() default false;
|
||||
|
||||
boolean mainStage() default false;
|
||||
|
||||
StageStyle style() default StageStyle.DECORATED;
|
||||
|
||||
String title();
|
||||
|
||||
/**
|
||||
* @description 图标URL
|
||||
* @version 1.2
|
||||
*/
|
||||
String icon() default "";
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,90 @@
|
||||
package cn.edu.scau.biubiusuisui.config;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXScan;
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
|
||||
import cn.edu.scau.biubiusuisui.factory.BeanBuilder;
|
||||
import cn.edu.scau.biubiusuisui.factory.FXBuilder;
|
||||
import cn.edu.scau.biubiusuisui.factory.FXControllerFactory;
|
||||
import cn.edu.scau.biubiusuisui.function.FXWindowParser;
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLoggerFactory;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
import cn.edu.scau.biubiusuisui.utils.ClassUtil;
|
||||
import cn.edu.scau.biubiusuisui.utils.FileUtil;
|
||||
import cn.edu.scau.biubiusuisui.utils.LogUtil;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 2:54
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXPlusApplication {
|
||||
private static final IFXPlusLogger logger = FXPlusLoggerFactory.getLogger(FXPlusApplication.class);
|
||||
|
||||
private static FXWindowParser windowAnnotationParser = new FXWindowParser();
|
||||
|
||||
private static BeanBuilder DEFAULT_BEAN_FACTORY = new FXBuilder();
|
||||
|
||||
private static BeanBuilder beanBuilder;
|
||||
|
||||
public static boolean IS_SCENE_BUILDER = true;
|
||||
|
||||
public static void start(Class clazz, BeanBuilder beanBuilder) {
|
||||
logger.info("starting JavaFX-Plus Application");
|
||||
try {
|
||||
logger.info("\n" + FileUtil.readFileFromResources("banner.txt"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
logger.error("\n read classpath:banner.txt error, you can ignore it");
|
||||
}
|
||||
// 初始化日志路径
|
||||
LogUtil.initLog4jBase();
|
||||
|
||||
IS_SCENE_BUILDER = false;
|
||||
FXPlusApplication.beanBuilder = beanBuilder;
|
||||
Annotation[] annotations = clazz.getDeclaredAnnotations();
|
||||
logger.info("starting to scanning and registering controllers");
|
||||
for (Annotation annotation : annotations) {
|
||||
if (FXScan.class.equals(annotation.annotationType())) {
|
||||
String[] dirs = ((FXScan) annotation).base();
|
||||
Set<String> sets = new HashSet<>();
|
||||
for (String dir : dirs) {
|
||||
sets.add(dir);
|
||||
}
|
||||
Set<String> classNames = new HashSet<>();
|
||||
for (String dir : sets) {
|
||||
logger.info("scanning directory: " + dir);
|
||||
ClassUtil classUtil = new ClassUtil();
|
||||
List<String> temps = null;
|
||||
try {
|
||||
temps = classUtil.scanAllClassName(dir);
|
||||
for (String className : temps) {
|
||||
logger.info("loading class: " + className);
|
||||
loadFXPlusClass(className, beanBuilder);
|
||||
}
|
||||
} catch (UnsupportedEncodingException | ClassNotFoundException exception) {
|
||||
logger.error("{}", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void start(Class clazz) {
|
||||
start(clazz, DEFAULT_BEAN_FACTORY);
|
||||
}
|
||||
|
||||
private static void loadFXPlusClass(String className, BeanBuilder beanBuilder) throws ClassNotFoundException {
|
||||
Class clazz = Class.forName(className);
|
||||
// 是窗口,需要初始化Stage
|
||||
if (clazz.getAnnotation(FXWindow.class) != null) {
|
||||
logger.info("loading stage of class: " + className);
|
||||
FXControllerFactory.loadStage(clazz, beanBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
package cn.edu.scau.biubiusuisui.entity;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXController;
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
|
||||
import cn.edu.scau.biubiusuisui.config.FXMLLoaderPlus;
|
||||
import cn.edu.scau.biubiusuisui.config.FXPlusApplication;
|
||||
import cn.edu.scau.biubiusuisui.exception.ProtocolNotSupport;
|
||||
import cn.edu.scau.biubiusuisui.function.DragWindowHandlerImpl;
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLoggerFactory;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
import cn.edu.scau.biubiusuisui.utils.FileUtil;
|
||||
import cn.edu.scau.biubiusuisui.utils.IFxPlusConstants;
|
||||
import cn.edu.scau.biubiusuisui.utils.ResourceBundleUtil;
|
||||
import cn.edu.scau.biubiusuisui.utils.StringUtil;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
|
||||
/*
|
||||
* In JavaFX-Plus Framework Controller
|
||||
* We use MVC model
|
||||
* V means view which stand for fxml
|
||||
* C means controller which stand for FXBaseController instance
|
||||
* M means model which is base cn.edu.scau.biubiusuisui.entity in your program
|
||||
* Every BaseController has a name which is used for identifying different <strong>instance</strong>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @author suisui
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 5:51
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXBaseController extends Pane {
|
||||
private static final IFXPlusLogger logger = FXPlusLoggerFactory.getLogger(FXBaseController.class);
|
||||
|
||||
protected String name = "";
|
||||
private Stage stage;
|
||||
private boolean isController = false;
|
||||
private boolean isWindow = false;
|
||||
|
||||
|
||||
/**
|
||||
* <p>description 用于携带信息数据</p>
|
||||
*
|
||||
* @version 1.2
|
||||
*/
|
||||
private Map<String, Object> query = new HashMap<>();
|
||||
private Map<String, Object> param = new HashMap<>();
|
||||
|
||||
public FXBaseController(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public FXBaseController() {
|
||||
FXController fxController = null;
|
||||
FXWindow fxWindow = null;
|
||||
Annotation[] annotations = getClass().getAnnotations();
|
||||
// Find FXController cn.edu.scau.biubiusuisui.annotation
|
||||
for (Annotation annotation : annotations) {
|
||||
// 是否Controller
|
||||
if (annotation.annotationType().equals(FXController.class)) {
|
||||
fxController = (FXController) annotation;
|
||||
isController = true;
|
||||
}
|
||||
// 添加赋予是否为窗口的逻辑
|
||||
if (annotation.annotationType().equals(FXWindow.class)) {
|
||||
fxWindow = (FXWindow) annotation;
|
||||
this.isWindow = true;
|
||||
}
|
||||
}
|
||||
//load fxml file to show panel in scene builder
|
||||
if (isController && FXPlusApplication.IS_SCENE_BUILDER == true) {
|
||||
logger.info("loading the FXML file of " + this.getName());
|
||||
URL location = getClass().getClassLoader().getResource(fxController.path());
|
||||
String fxmlBaseName = StringUtil.getFilePathInResources(fxController.path());
|
||||
ResourceBundle resourceBundle = ResourceBundleUtil.getResourceBundle(fxmlBaseName, fxController.locale());
|
||||
FXMLLoaderPlus fxmlLoader = new FXMLLoaderPlus(location);
|
||||
fxmlLoader.setRoot(this);
|
||||
fxmlLoader.setController(this);
|
||||
fxmlLoader.setShow(true);
|
||||
fxmlLoader.setResources(resourceBundle);
|
||||
try {
|
||||
// 加载前
|
||||
onLoad();
|
||||
fxmlLoader.load();
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 相当于onReady, 页面渲染完后的操作
|
||||
* @version 1.2
|
||||
*/
|
||||
public void initialize() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 初始化onShow, onHide, onClose的生命周期
|
||||
* @version 1.2
|
||||
*/
|
||||
public final void initLifeCycle() {
|
||||
logger.info("init the life cycle of " + this.getName());
|
||||
this.stage.setOnShowing(event -> {
|
||||
try {
|
||||
onShow();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
this.stage.setOnCloseRequest(event -> {
|
||||
try {
|
||||
onClose();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
// 监听最小化窗口
|
||||
this.stage.iconifiedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
try {
|
||||
if (newValue) { //最小化
|
||||
onHide();
|
||||
} else {
|
||||
onShow(); //取消最小化
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 在加载页面之前的操作
|
||||
* @version 1.2
|
||||
*/
|
||||
public void onLoad() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 在显示页面之前的操作
|
||||
* @version 1.2
|
||||
*/
|
||||
public void onShow() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 在关闭窗口之前的操作
|
||||
* @version 1.2
|
||||
*/
|
||||
public void onClose() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 在隐藏窗口之前的操作
|
||||
* @version 1.2
|
||||
*/
|
||||
public void onHide() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* 唤起舞台
|
||||
*/
|
||||
public void showStage() {
|
||||
if (this.isWindow) {
|
||||
this.stage.show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示并等待
|
||||
*/
|
||||
public void showAndWait() {
|
||||
if (this.isWindow) {
|
||||
this.stage.showAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭舞台
|
||||
*/
|
||||
public void closeStage() {
|
||||
if (this.isWindow) {
|
||||
this.stage.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 最小化
|
||||
* @version 1.2
|
||||
*/
|
||||
public void hideStage() {
|
||||
if (this.isWindow) {
|
||||
this.stage.setIconified(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>description: 开放设置窗口标题 </p>
|
||||
*
|
||||
* @param title 标题
|
||||
* @return true--修改标题成功 false--修改失败
|
||||
* @version 1.3
|
||||
*/
|
||||
public final void setWindowTitle(String title) {
|
||||
if (this.isWindow) {
|
||||
this.stage.setTitle(title);
|
||||
logger.info("setting title of window");
|
||||
} else {
|
||||
logger.warn("the controller is not window");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>description: 开放设置窗口图标</p>
|
||||
*
|
||||
* @param icon String 图标URL地址,需要放在resources文件下或项目根目录下
|
||||
*/
|
||||
public final void setIcon(String icon) {
|
||||
if (this.isWindow) {
|
||||
if (!"".equals(icon)) {
|
||||
try {
|
||||
URL iconUrl = new FileUtil().getFilePathFromResources(icon);
|
||||
if (iconUrl != null) {
|
||||
if (new File(StringUtil.getRootPath(iconUrl)).exists()) {
|
||||
this.stage.getIcons().clear();
|
||||
this.stage.getIcons().add(new Image(icon));
|
||||
} else {
|
||||
logger.warn("the icon file has not existed");
|
||||
}
|
||||
} else {
|
||||
logger.warn("the icon file has not existed");
|
||||
}
|
||||
} catch (ProtocolNotSupport | UnsupportedEncodingException exception) {
|
||||
logger.error(exception.getMessage(), exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Description 开放是否允许窗口可拖拽和缩放的接口</p>
|
||||
*
|
||||
* @param draggable 可拖拽
|
||||
* @param resizable 可缩放
|
||||
*/
|
||||
public final void setDragAndResize(boolean draggable, boolean resizable) {
|
||||
this.stage.setResizable(resizable);
|
||||
if (draggable || resizable) {
|
||||
EventHandler dragWindowHandler = new DragWindowHandlerImpl(stage, this, draggable, resizable);
|
||||
this.setOnMousePressed(dragWindowHandler);
|
||||
this.setOnMouseDragged(dragWindowHandler);
|
||||
this.setOnMouseMoved(dragWindowHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Controller名字
|
||||
*
|
||||
* @return name
|
||||
*/
|
||||
public String getName() {
|
||||
if ("".equals(name) || name == null) { // 原本无“name == null”判断条件,会出错
|
||||
return StringUtil.getBaseClassName(getClass().getSimpleName());
|
||||
} else {
|
||||
return StringUtil.getBaseClassName(getClass().getSimpleName()) + IFxPlusConstants.CONTROLLER_NAME_SEPARATOR + name;
|
||||
}
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isController() {
|
||||
return isController;
|
||||
}
|
||||
|
||||
public void setController(boolean controller) {
|
||||
isController = controller;
|
||||
}
|
||||
|
||||
public boolean isWindow() {
|
||||
return this.isWindow;
|
||||
}
|
||||
|
||||
public void setWindow(boolean window) {
|
||||
this.isWindow = window;
|
||||
}
|
||||
|
||||
public Stage getStage() {
|
||||
return stage;
|
||||
}
|
||||
|
||||
public void setStage(Stage stage) {
|
||||
this.stage = stage;
|
||||
}
|
||||
|
||||
public Map<String, Object> getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
public Map<String, Object> getParam() {
|
||||
return param;
|
||||
}
|
||||
|
||||
public void setQuery(Map<String, Object> query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public void setParam(Map<String, Object> param) {
|
||||
this.param = param;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package cn.edu.scau.biubiusuisui.entity;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXField;
|
||||
import javafx.beans.property.Property;
|
||||
|
||||
/**
|
||||
* 将Controller中的JavaFX的field包装成FXFieldWrapper
|
||||
*
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/28 10:03
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXFieldWrapper {
|
||||
|
||||
private FXField fxField;
|
||||
private Class type;
|
||||
|
||||
private Property property;
|
||||
|
||||
public FXFieldWrapper() {
|
||||
}
|
||||
|
||||
public FXFieldWrapper(FXField fxField, Class type) {
|
||||
this.fxField = fxField;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Class getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Class type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public FXField getFxField() {
|
||||
return fxField;
|
||||
}
|
||||
|
||||
public void setFxField(FXField fxField) {
|
||||
this.fxField = fxField;
|
||||
}
|
||||
|
||||
public Property getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(Property property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package cn.edu.scau.biubiusuisui.entity;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* This class is base cn.edu.scau.biubiusuisui.entity for queue message(or signal)
|
||||
* you mush save the instance and method which means who will run this method
|
||||
*
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/26 15:39
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXMethodEntity {
|
||||
/**
|
||||
* 所属Controller
|
||||
*/
|
||||
private FXBaseController fxBaseController;
|
||||
/**
|
||||
* 实际方法
|
||||
*/
|
||||
private Method method;
|
||||
|
||||
public FXMethodEntity(FXBaseController fxBaseController, Method method) {
|
||||
this.fxBaseController = fxBaseController;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public FXBaseController getFxBaseController() {
|
||||
return fxBaseController;
|
||||
}
|
||||
|
||||
public void setFxBaseController(FXBaseController fxBaseController) {
|
||||
this.fxBaseController = fxBaseController;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(Method method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package cn.edu.scau.biubiusuisui.entity;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.proxy.FXEntityProxy;
|
||||
import javafx.beans.property.Property;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Context is use for storing Controller
|
||||
* In addition,you can store an instance into Session to use it everywhere
|
||||
*
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/26 12:28
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXPlusContext {
|
||||
|
||||
private FXPlusContext() {
|
||||
}
|
||||
|
||||
private static Map<String, List<FXBaseController>> controllerContext = new ConcurrentHashMap<>(); //FXController控制器注册表
|
||||
|
||||
private static Map<Object, FXEntityProxy> beanMap = new ConcurrentHashMap<>(); // Object注册为FXEntityObject
|
||||
|
||||
|
||||
public static void registerController(FXBaseController fxBaseController) {
|
||||
List<FXBaseController> controllers = controllerContext.get(fxBaseController.getName());
|
||||
if (controllers == null) {
|
||||
controllers = new LinkedList<>();
|
||||
}
|
||||
controllers.add(fxBaseController);
|
||||
// @since 1.2.1 fix: 没有将controller真正注册到context的异常
|
||||
controllerContext.put(fxBaseController.getName(), controllers);
|
||||
}
|
||||
|
||||
|
||||
public static FXEntityProxy getProxyByBeanObject(Object object) {
|
||||
return beanMap.get(object);
|
||||
}
|
||||
|
||||
public static void setProxyByBeanObject(Object object, FXEntityProxy fxEntityProxy) {
|
||||
beanMap.put(object, fxEntityProxy);
|
||||
}
|
||||
|
||||
public static List<FXBaseController> getControllers(String key) {
|
||||
return controllerContext.get(key);
|
||||
}
|
||||
|
||||
public static Property getEntityPropertyByName(Object object, String fieldName) {
|
||||
return getProxyByBeanObject(object).getPropertyByFieldName(fieldName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.edu.scau.biubiusuisui.entity;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description JavaFX的Locale枚举类型
|
||||
* @date 2020/5/3 10:47
|
||||
* @since JDK1.8 JavaFX2.0
|
||||
*/
|
||||
public enum FXPlusLocale {
|
||||
/**
|
||||
* 不设置
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* 简体中文
|
||||
*/
|
||||
SIMPLIFIED_CHINESE,
|
||||
|
||||
/**
|
||||
* 繁体中文
|
||||
*/
|
||||
TRADITIONAL_CHINESE,
|
||||
|
||||
|
||||
/**
|
||||
* English 英语
|
||||
*/
|
||||
ENGLISH,
|
||||
|
||||
|
||||
/**
|
||||
* American 美语
|
||||
*/
|
||||
AMERICAN,
|
||||
|
||||
|
||||
/**
|
||||
* Le français 法语
|
||||
*/
|
||||
FRANCE,
|
||||
|
||||
|
||||
/**
|
||||
* Deutsch 德语
|
||||
*/
|
||||
GERMANY,
|
||||
|
||||
|
||||
/**
|
||||
* lingua italiana 意大利语
|
||||
*/
|
||||
ITALIAN,
|
||||
|
||||
|
||||
/**
|
||||
* 日本人 日语
|
||||
*/
|
||||
JAPANESE,
|
||||
|
||||
|
||||
/**
|
||||
* 한국어 韩语
|
||||
*/
|
||||
KOREAN,
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package cn.edu.scau.biubiusuisui.entity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description 跳转窗口携带的参数
|
||||
* @date 2020/4/6 18:06
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXRedirectParam {
|
||||
/**
|
||||
* 跳转的目标Controller
|
||||
*/
|
||||
private String toController;
|
||||
/**
|
||||
* query方式的参数, like: helloController?name=JavaFx-Plus&msg=helloWorld
|
||||
* the map will store: { name -> JavaFx-Plus, msg -> helloWorld}
|
||||
*/
|
||||
private Map<String, Object> query = new HashMap<>();
|
||||
|
||||
/**
|
||||
* param方式的参数,会以map方式传递给目标Controller
|
||||
*/
|
||||
private Map<String, Object> params = new HashMap<>();
|
||||
|
||||
public FXRedirectParam(String toController) {
|
||||
this.toController = toController;
|
||||
}
|
||||
|
||||
public String getToController() {
|
||||
return toController;
|
||||
}
|
||||
|
||||
public void setToController(String toController) {
|
||||
this.toController = toController;
|
||||
}
|
||||
|
||||
public Map<String, Object> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public Map<String, Object> getQueryMap() {
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
public void addParam(String key, Object param) {
|
||||
this.params.put(key, param);
|
||||
}
|
||||
|
||||
public Object getParam(String key) {
|
||||
return this.params.get(key);
|
||||
}
|
||||
|
||||
public void addQuery(String key, Object param) {
|
||||
this.query.put(key, param);
|
||||
}
|
||||
|
||||
public Object getOneQuery(String key) {
|
||||
return this.query.get(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.edu.scau.biubiusuisui.exception;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description 不合法URL
|
||||
* @date 2020/4/6 15:59
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class InvalidURLException extends Exception {
|
||||
public InvalidURLException() {
|
||||
super("the url is invalid");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.edu.scau.biubiusuisui.exception;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/27 3:00
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class NoSuchChangeMethod extends Exception {
|
||||
|
||||
public NoSuchChangeMethod() {
|
||||
super("No such change method");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.edu.scau.biubiusuisui.exception;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description 某Controller不是窗口的错误
|
||||
* @date 2020/4/6 17:10
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class NotFXWindowException extends Exception {
|
||||
public NotFXWindowException() {
|
||||
super("the controller is not a window");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package cn.edu.scau.biubiusuisui.exception;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 7:23
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class ProtocolNotSupport extends Exception {
|
||||
public ProtocolNotSupport() {
|
||||
super("protocolNotSupport");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.edu.scau.biubiusuisui.expression;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/27 2:02
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public interface BindParser {
|
||||
public void parse(Object target, String expression);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.edu.scau.biubiusuisui.expression.action;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.expression.BindParser;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/27 2:03
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class ChangeParser implements BindParser {
|
||||
|
||||
@Override
|
||||
public void parse(Object target, String expression) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cn.edu.scau.biubiusuisui.expression.data;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/27 20:03
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ExpFunction<T, U, R> {
|
||||
R apply(T t, U u);
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package cn.edu.scau.biubiusuisui.expression.data;
|
||||
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXValue;
|
||||
import cn.edu.scau.biubiusuisui.exception.NoSuchChangeMethod;
|
||||
import com.sun.istack.internal.NotNull;
|
||||
import com.sun.javafx.fxml.expression.Expression;
|
||||
import javafx.beans.property.Property;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
/**
|
||||
* 将FXBind中表达式建立绑定
|
||||
* 格式如下
|
||||
* 语法如下:
|
||||
* FXBind("S")
|
||||
* S -> left=right
|
||||
* left -> property
|
||||
* right -> ${expression}
|
||||
* expression -> bean.field
|
||||
* <p>
|
||||
* FXBind("text=${bean.field})
|
||||
* textProperty 通过 adapter.getModelProperty --> textProperty实例
|
||||
* bean 通过namespace 获取,因为bean有FXEntity标签,所以返回包装过后的bean的property
|
||||
* 最后
|
||||
* left.bind(right)
|
||||
*
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/23 15:05
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class ExpressionParser {
|
||||
|
||||
private Object namespace;
|
||||
private Object targetController;
|
||||
private static final String BIND_PREFIX = "${";
|
||||
private static final String BIND_SUFIX = "}";
|
||||
private static final String PROEPRTY = "Property";
|
||||
|
||||
public enum ExpressionType {
|
||||
DataExpression,
|
||||
ActionExpression
|
||||
}
|
||||
|
||||
public ExpressionParser(Object namespace, Object targetController) {
|
||||
this.namespace = namespace;
|
||||
this.targetController = targetController;
|
||||
}
|
||||
|
||||
public ExpressionParser(Object namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
private Property getLeftProperty(MyBeanAdapter myBeanAdapter, String key) {
|
||||
return (Property) myBeanAdapter.getPropertyModel(key);
|
||||
}
|
||||
|
||||
private static final String FUNCTION_PREFIX = "@";
|
||||
|
||||
private MyExpressionValue getRightExpression(MyBeanAdapter myBeanAdapter, String key, String rightExpression) {
|
||||
Expression expression = null;
|
||||
if (rightExpression.startsWith(FUNCTION_PREFIX)) {
|
||||
expression = getFunctionExpression(rightExpression);
|
||||
} else {
|
||||
expression = Expression.valueOf(rightExpression);
|
||||
}
|
||||
Class clazz = myBeanAdapter.getType(key);
|
||||
MyExpressionValue myExpressionValue = new MyExpressionValue(namespace, expression, clazz);
|
||||
return myExpressionValue;
|
||||
}
|
||||
|
||||
private Expression getFunctionExpression(String rightExpression) {
|
||||
Expression expression = null;
|
||||
int indexLeft = rightExpression.indexOf("(");
|
||||
String methodName = rightExpression.substring(1, indexLeft);
|
||||
int indexRight = rightExpression.indexOf(")");
|
||||
String argString = rightExpression.substring(indexLeft + 1, indexRight);
|
||||
String[] args = null;
|
||||
if (!"".equals(argString.trim())) {
|
||||
args = argString.split(",");
|
||||
}
|
||||
Class targetClazz = targetController.getClass();
|
||||
Method[] methods = targetClazz.getMethods();
|
||||
Expression[] expressionArgs = null;
|
||||
if (args != null) {
|
||||
expressionArgs = new Expression[args.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (!"".equals(args[i].trim())) {
|
||||
expressionArgs[i] = Expression.valueOf(args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Method method : methods) {
|
||||
if (method.getName().equals(methodName)) {
|
||||
expression = new FunctionExpression(method, targetController, expressionArgs);
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
public void parse(Object object, @NotNull String expression) throws NoSuchChangeMethod {
|
||||
//check expression
|
||||
int index = expression.indexOf("=");
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
String[] items = expression.split("=");
|
||||
if (items.length != 2) {
|
||||
return;
|
||||
}
|
||||
String left = items[0];
|
||||
String right = items[1];
|
||||
if (left == null || right == null) {
|
||||
return;
|
||||
}
|
||||
right = right.trim();
|
||||
ExpressionType expressionType;
|
||||
if (right.startsWith(BIND_PREFIX) && right.endsWith(BIND_SUFIX)) {
|
||||
int length = right.length();
|
||||
right = right.substring(2, length - 1); //已经去掉“${”的表达式
|
||||
expressionType = ExpressionType.DataExpression;
|
||||
} else {
|
||||
right = right.substring(1); //#changeMethod -> changeMethod
|
||||
expressionType = ExpressionType.ActionExpression;
|
||||
}
|
||||
MyBeanAdapter myBeanAdapter = new MyBeanAdapter(object);
|
||||
Property leftProperty = getLeftProperty(myBeanAdapter, left);
|
||||
switch (expressionType) {
|
||||
case DataExpression:
|
||||
bindDataExpression(left, right, myBeanAdapter, leftProperty);
|
||||
break;
|
||||
case ActionExpression:
|
||||
bindActionExpression(right, leftProperty);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param right
|
||||
* @param leftProperty
|
||||
* @throws NoSuchChangeMethod
|
||||
* @Description 鼠标事件或键盘事件绑定
|
||||
*/
|
||||
private void bindActionExpression(String right, Property leftProperty) throws NoSuchChangeMethod {
|
||||
Class clazz = targetController.getClass();
|
||||
Method[] methods = clazz.getMethods();
|
||||
for (Method method : methods) {
|
||||
if (method.getName().equals(right)) {
|
||||
leftProperty.addListener((observable, oldValue, newValue) -> {
|
||||
try {
|
||||
Object[] objects = getArgs(method, observable, newValue, oldValue);
|
||||
method.invoke(targetController, objects);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param left
|
||||
* @param right
|
||||
* @param myBeanAdapter
|
||||
* @param leftProperty
|
||||
* @Description 数据绑定
|
||||
*/
|
||||
private void bindDataExpression(String left, String right, MyBeanAdapter myBeanAdapter, Property leftProperty) {
|
||||
MyExpressionValue rightProperty = getRightExpression(myBeanAdapter, left, right);
|
||||
leftProperty.bind(rightProperty);
|
||||
}
|
||||
|
||||
public Object[] getArgs(Method method, Object... args) {
|
||||
Parameter[] parameters = method.getParameters();
|
||||
Object[] objects = new Object[parameters.length];
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
FXValue annotation = parameters[i].getAnnotation(FXValue.class);
|
||||
switch (annotation.value()) {
|
||||
case "target":
|
||||
objects[i] = args[0];
|
||||
break;
|
||||
case "newValue":
|
||||
objects[i] = args[1];
|
||||
break;
|
||||
case "oldValue":
|
||||
objects[i] = args[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package cn.edu.scau.biubiusuisui.expression.data;
|
||||
|
||||
import com.sun.javafx.fxml.expression.Expression;
|
||||
import com.sun.javafx.fxml.expression.KeyPath;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/27 20:00
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FunctionExpression extends Expression {
|
||||
|
||||
private Method method;
|
||||
private Object target;
|
||||
private Expression[] args;
|
||||
|
||||
public FunctionExpression(Method method, Object target, Expression[] expressions) {
|
||||
this.method = method;
|
||||
this.target = target;
|
||||
this.args = expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyPath> getArguments() {
|
||||
List<KeyPath> list = new ArrayList<>();
|
||||
if (args != null) {
|
||||
for (Expression expression : args) {
|
||||
list.addAll(expression.getArguments());
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate(Object namespace) {
|
||||
Object result = null;
|
||||
if (args != null) {
|
||||
Object[] values = new Object[args.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
values[i] = args[i].evaluate(namespace);
|
||||
}
|
||||
try {
|
||||
result = method.invoke(target, values);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
try {
|
||||
result = method.invoke(target);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Object namespace, Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefined(Object namespace) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLValue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getArguments(List arguments) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package cn.edu.scau.biubiusuisui.expression.data;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXEntity;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXPlusContext;
|
||||
import cn.edu.scau.biubiusuisui.utils.BeanUtil;
|
||||
import com.sun.javafx.fxml.BeanAdapter;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/23 15:16
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class MyBeanAdapter extends BeanAdapter {
|
||||
|
||||
private Object object;
|
||||
|
||||
/**
|
||||
* Creates a new Bean adapter.
|
||||
*
|
||||
* @param bean The Bean object to wrap.
|
||||
*/
|
||||
public MyBeanAdapter(Object bean) {
|
||||
super(bean);
|
||||
this.object = bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ObservableValue<T> getPropertyModel(String key) {
|
||||
if (object.getClass().getAnnotation(FXEntity.class) == null) {
|
||||
return super.getPropertyModel(key);
|
||||
} else {
|
||||
return BeanUtil.getPropertyByName(object, key);
|
||||
}
|
||||
}
|
||||
|
||||
public String valueOf(String value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package cn.edu.scau.biubiusuisui.expression.data;
|
||||
|
||||
import com.sun.javafx.fxml.BeanAdapter;
|
||||
import com.sun.javafx.fxml.expression.Expression;
|
||||
import com.sun.javafx.fxml.expression.KeyPath;
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.beans.value.ObservableValueBase;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.MapChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.ObservableMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class MyExpressionValue extends ObservableValueBase<Object> {
|
||||
|
||||
// Monitors a namespace for changes along a key path
|
||||
private class KeyPathMonitor {
|
||||
private String key;
|
||||
private KeyPathMonitor next;
|
||||
|
||||
private Object namespace = null;
|
||||
|
||||
private ListChangeListener<Object> listChangeListener = new ListChangeListener<Object>() {
|
||||
@Override
|
||||
public void onChanged(Change<? extends Object> change) {
|
||||
while (change.next()) {
|
||||
int index = Integer.parseInt(key);
|
||||
|
||||
if (index >= change.getFrom() && index < change.getTo()) {
|
||||
fireValueChangedEvent();
|
||||
remonitor();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private MapChangeListener<String, Object> mapChangeListener = new MapChangeListener<String, Object>() {
|
||||
@Override
|
||||
public void onChanged(Change<? extends String, ? extends Object> change) {
|
||||
if (key.equals(change.getKey())) {
|
||||
fireValueChangedEvent();
|
||||
remonitor();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private ChangeListener<Object> propertyChangeListener = new ChangeListener<Object>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Object> observable, Object oldValue, Object newValue) {
|
||||
fireValueChangedEvent();
|
||||
remonitor();
|
||||
}
|
||||
};
|
||||
|
||||
public KeyPathMonitor(Iterator<String> keyPathIterator) {
|
||||
this.key = keyPathIterator.next();
|
||||
|
||||
if (keyPathIterator.hasNext()) {
|
||||
next = new KeyPathMonitor(keyPathIterator);
|
||||
} else {
|
||||
next = null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void monitor(Object namespace) {
|
||||
if (namespace instanceof ObservableList<?>) {
|
||||
((ObservableList<Object>) namespace).addListener(listChangeListener);
|
||||
} else if (namespace instanceof ObservableMap<?, ?>) {
|
||||
((ObservableMap<String, Object>) namespace).addListener(mapChangeListener);
|
||||
} else {
|
||||
|
||||
MyBeanAdapter namespaceAdapter = new MyBeanAdapter(namespace);
|
||||
ObservableValue<Object> propertyModel = namespaceAdapter.getPropertyModel(key);
|
||||
|
||||
if (propertyModel != null) {
|
||||
propertyModel.addListener(propertyChangeListener);
|
||||
}
|
||||
|
||||
namespace = namespaceAdapter;
|
||||
}
|
||||
|
||||
this.namespace = namespace;
|
||||
|
||||
if (next != null) {
|
||||
Object value = Expression.get(namespace, key);
|
||||
if (value != null) {
|
||||
next.monitor(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void unmonitor() {
|
||||
if (namespace instanceof ObservableList<?>) {
|
||||
((ObservableList<Object>) namespace).removeListener(listChangeListener);
|
||||
} else if (namespace instanceof ObservableMap<?, ?>) {
|
||||
((ObservableMap<String, Object>) namespace).removeListener(mapChangeListener);
|
||||
} else if (namespace != null) {
|
||||
MyBeanAdapter namespaceAdapter = (MyBeanAdapter) namespace;
|
||||
ObservableValue<Object> propertyModel = namespaceAdapter.getPropertyModel(key);
|
||||
|
||||
if (propertyModel != null) {
|
||||
propertyModel.removeListener(propertyChangeListener);
|
||||
}
|
||||
}
|
||||
|
||||
namespace = null;
|
||||
|
||||
if (next != null) {
|
||||
next.unmonitor();
|
||||
}
|
||||
}
|
||||
|
||||
public void remonitor() {
|
||||
if (next != null) {
|
||||
next.unmonitor();
|
||||
Object value = Expression.get(namespace, key);
|
||||
if (value != null) {
|
||||
next.monitor(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object namespace;
|
||||
private Expression expression;
|
||||
private Class<?> type;
|
||||
|
||||
private ArrayList<KeyPathMonitor> argumentMonitors;
|
||||
|
||||
private int listenerCount = 0;
|
||||
|
||||
public MyExpressionValue(Object namespace, Expression expression, Class<?> type) {
|
||||
if (namespace == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
if (expression == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
this.namespace = namespace;
|
||||
this.expression = expression;
|
||||
this.type = type;
|
||||
|
||||
List<KeyPath> arguments = expression.getArguments();
|
||||
argumentMonitors = new ArrayList<KeyPathMonitor>(arguments.size());
|
||||
|
||||
for (KeyPath argument : arguments) {
|
||||
argumentMonitors.add(new KeyPathMonitor(argument.iterator()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return BeanAdapter.coerce(expression.evaluate(namespace), type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(InvalidationListener listener) {
|
||||
if (listenerCount == 0) {
|
||||
monitorArguments();
|
||||
}
|
||||
|
||||
super.addListener(listener);
|
||||
listenerCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(InvalidationListener listener) {
|
||||
super.removeListener(listener);
|
||||
listenerCount--;
|
||||
|
||||
if (listenerCount == 0) {
|
||||
unmonitorArguments();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ChangeListener<? super Object> listener) {
|
||||
if (listenerCount == 0) {
|
||||
monitorArguments();
|
||||
}
|
||||
|
||||
super.addListener(listener);
|
||||
listenerCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(ChangeListener<? super Object> listener) {
|
||||
super.removeListener(listener);
|
||||
listenerCount--;
|
||||
|
||||
if (listenerCount == 0) {
|
||||
unmonitorArguments();
|
||||
}
|
||||
}
|
||||
|
||||
private void monitorArguments() {
|
||||
for (KeyPathMonitor argumentMonitor : argumentMonitors) {
|
||||
argumentMonitor.monitor(namespace);
|
||||
}
|
||||
}
|
||||
|
||||
private void unmonitorArguments() {
|
||||
for (KeyPathMonitor argumentMonitor : argumentMonitors) {
|
||||
argumentMonitor.unmonitor();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.edu.scau.biubiusuisui.factory;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/4 11:16
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public interface BeanBuilder {
|
||||
/**
|
||||
* 万能工厂方法
|
||||
*
|
||||
* @param type 类型
|
||||
* @return 实例对象
|
||||
*/
|
||||
Object getBean(Class type);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.edu.scau.biubiusuisui.factory;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLoggerFactory;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/4 11:13
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXBuilder implements BeanBuilder {
|
||||
private IFXPlusLogger logger = FXPlusLoggerFactory.getLogger(FXBuilder.class);
|
||||
|
||||
@Override
|
||||
public Object getBean(Class type) {
|
||||
Object object = null;
|
||||
try {
|
||||
object = type.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
package cn.edu.scau.biubiusuisui.factory;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXBind;
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXController;
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXData;
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
|
||||
import cn.edu.scau.biubiusuisui.config.FXMLLoaderPlus;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXPlusContext;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXPlusLocale;
|
||||
import cn.edu.scau.biubiusuisui.exception.NoSuchChangeMethod;
|
||||
import cn.edu.scau.biubiusuisui.expression.data.ExpressionParser;
|
||||
import cn.edu.scau.biubiusuisui.function.FXWindowParser;
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLoggerFactory;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
import cn.edu.scau.biubiusuisui.mq.MessageQueue;
|
||||
import cn.edu.scau.biubiusuisui.proxy.FXControllerProxy;
|
||||
import cn.edu.scau.biubiusuisui.stage.StageManager;
|
||||
import cn.edu.scau.biubiusuisui.utils.ResourceBundleUtil;
|
||||
import cn.edu.scau.biubiusuisui.utils.StringUtil;
|
||||
import javafx.collections.ObservableMap;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 8:12
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXControllerFactory {
|
||||
private static IFXPlusLogger logger = FXPlusLoggerFactory.getLogger(FXControllerFactory.class);
|
||||
|
||||
private static final BeanBuilder BEAN_BUILDER = new FXBuilder();
|
||||
private static FXWindowParser fxWindowAnnotationParser = new FXWindowParser();
|
||||
|
||||
|
||||
/**
|
||||
* 控制类的注入流程
|
||||
* 这是一个即将被创建的控制类
|
||||
* <pre>
|
||||
* <code>
|
||||
* class MainController{
|
||||
* @Autowired
|
||||
* Student stu; //普通属性
|
||||
* @FXML
|
||||
* Button btn; //FX属性
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
* 1. 实现对普通属性的注入
|
||||
* 如果使用了Spring那么这类会自动注入那些@Autowired的属性,请不要将这个方法用在控制器属性中
|
||||
* <pre>
|
||||
* <code>
|
||||
* class MainController{
|
||||
* @Autowired
|
||||
* Student stu ; //初始化完成
|
||||
* @FXML
|
||||
* Button btn; // null
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
* 2. 通过loadFXML实现对FX属性的注入
|
||||
* <pre>
|
||||
* <code>
|
||||
* class MainController{
|
||||
* @Autowired
|
||||
* Student stu ; //初始化完成
|
||||
* @FXML
|
||||
* Button btn; // 初始化完成
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
* <p>
|
||||
* 3. 完成对FXBind的注解的解析
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* 4. 完成注册
|
||||
*
|
||||
* @param clazz instance that extends by FXBaseController
|
||||
* @param controllerName
|
||||
* @return
|
||||
*/
|
||||
private static FXBaseController getFxBaseController(Class clazz, String controllerName, BeanBuilder beanBuilder) {
|
||||
return getFxBaseController0(clazz, controllerName, beanBuilder);
|
||||
}
|
||||
|
||||
private static FXBaseController getFxBaseController0(Class clazz, String controllerName, BeanBuilder beanBuilder) {
|
||||
URL fxmlPath;
|
||||
FXController fxController = null; //reflect and get FXController cn.edu.scau.biubiusuisui.annotation
|
||||
fxController = (FXController) clazz.getDeclaredAnnotation(FXController.class);
|
||||
Pane parent = null;
|
||||
FXBaseController fxBaseController = null;
|
||||
FXBaseController fxControllerProxy = null;
|
||||
if (fxController != null) {
|
||||
logger.info("loading the FXML file of " + clazz.getName());
|
||||
String fxmlPathName = fxController.path();
|
||||
String fxmlBaseName = StringUtil.getFilePathInResources(fxmlPathName);
|
||||
FXPlusLocale fxPlusLocale = fxController.locale();
|
||||
ResourceBundle resourceBundle = ResourceBundleUtil.getResourceBundle(fxmlBaseName, fxPlusLocale);
|
||||
fxmlPath = clazz.getClassLoader().getResource(fxmlPathName);
|
||||
FXMLLoaderPlus fxmlLoader = new FXMLLoaderPlus(fxmlPath);
|
||||
// create a cn.edu.scau.biubiusuisui.proxy for monitoring methods
|
||||
|
||||
fxBaseController = (FXBaseController) beanBuilder.getBean(clazz); //获取controller实例
|
||||
parseData(fxBaseController);
|
||||
|
||||
if (fxBaseController != null) {
|
||||
FXControllerProxy controllerProxy = new FXControllerProxy();
|
||||
fxControllerProxy = (FXBaseController) controllerProxy.getInstance(fxBaseController); //产生代理从而实现赋能
|
||||
fxmlLoader.setRoot(fxControllerProxy);
|
||||
fxmlLoader.setController(fxControllerProxy);
|
||||
fxmlLoader.setBaseController(fxBaseController);
|
||||
fxmlLoader.setResources(resourceBundle);
|
||||
try {
|
||||
|
||||
fxControllerProxy.onLoad(); //页面加载
|
||||
|
||||
parent = fxmlLoader.load();
|
||||
|
||||
if (controllerName != null) {
|
||||
fxControllerProxy.setName(controllerName);
|
||||
fxBaseController.setName(controllerName);
|
||||
} else {
|
||||
fxBaseController.setName(parent.getId());
|
||||
}
|
||||
ObservableMap namespace = fxmlLoader.getNamespace();
|
||||
addDataInNameSpace(namespace, fxBaseController); //处理fxBaseController里面的@FXData
|
||||
scanBind(namespace, fxBaseController); //处理@FXBind
|
||||
register(fxBaseController, fxControllerProxy);
|
||||
} catch (IOException exception) {
|
||||
logger.error(exception.getMessage());
|
||||
throw new RuntimeException(exception);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return fxControllerProxy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将代理对象和目标对象注册
|
||||
*
|
||||
* @param fxBaseController 目标对象
|
||||
* @param fxBaseControllerProxy 代理对象
|
||||
*/
|
||||
private static void register(FXBaseController fxBaseController, FXBaseController fxBaseControllerProxy) {
|
||||
FXPlusContext.registerController(fxBaseController); //保存
|
||||
MessageQueue.getInstance().registerConsumer(fxBaseController, fxBaseControllerProxy); // 添加进入消息队列 信号功能
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fxWindow
|
||||
* @param clazz
|
||||
* @param fxBaseControllerProxy
|
||||
* @return
|
||||
* @Description 为有FXWindow注解的类创建Stage
|
||||
*/
|
||||
private static Stage createWindow(FXWindow fxWindow, Class clazz, FXBaseController fxBaseControllerProxy) {
|
||||
logger.info("creating window.....");
|
||||
Stage stage = new Stage();
|
||||
fxBaseControllerProxy.setStage(stage);
|
||||
double preWidth = fxWindow.preWidth() == 0 ? fxBaseControllerProxy.getPrefWidth() : fxWindow.preWidth();
|
||||
double preHeight = fxWindow.preHeight() == 0 ? fxBaseControllerProxy.getPrefHeight() : fxWindow.preHeight();
|
||||
Scene scene = new Scene(fxBaseControllerProxy, preWidth, preHeight);
|
||||
stage.setScene(scene);
|
||||
fxWindowAnnotationParser.parse(stage, fxBaseControllerProxy, fxWindow);
|
||||
|
||||
// 此处设置生命周期中的onShow,onHide,onClose
|
||||
fxBaseControllerProxy.initLifeCycle();
|
||||
|
||||
StageManager.getInstance().registerWindow(clazz, fxBaseControllerProxy); //注册舞台
|
||||
if (fxWindow.mainStage() == true) { //当是主舞台时,先show为敬
|
||||
fxBaseControllerProxy.showStage();
|
||||
}
|
||||
return stage;
|
||||
}
|
||||
|
||||
private FXControllerFactory() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载舞台
|
||||
* 原函数名为loadMainStage(Class clazz, BeanBuilder beanBuilder)
|
||||
*
|
||||
* @param clazz
|
||||
* @param beanBuilder
|
||||
*/
|
||||
public static void loadStage(Class clazz, BeanBuilder beanBuilder) {
|
||||
FXWindow declaredAnnotation = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
|
||||
//只有当用了FXWindow注解,才会注册Stage
|
||||
if (declaredAnnotation != null) {
|
||||
getFXWindow(clazz, null, beanBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
public static FXBaseController getFXController(Class clazz) {
|
||||
return getFXController(clazz, BEAN_BUILDER);
|
||||
}
|
||||
|
||||
public static FXBaseController getFXController(Class clazz, BeanBuilder beanBuilder) {
|
||||
FXBaseController fxBaseController = getFXController(clazz, null, beanBuilder);
|
||||
return fxBaseController;
|
||||
}
|
||||
|
||||
public static FXBaseController getFXController(Class clazz, String controllerName) {
|
||||
return getFXController(clazz, controllerName, BEAN_BUILDER);
|
||||
}
|
||||
|
||||
public static FXBaseController getFXController(Class clazz, String controllerName, BeanBuilder beanBuilder) {
|
||||
FXBaseController fxBaseController = getFxBaseController(clazz, controllerName, beanBuilder);
|
||||
return fxBaseController;
|
||||
}
|
||||
|
||||
|
||||
public static Stage getFXWindow(Class clazz) {
|
||||
FXWindow fxWindow = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
|
||||
if (fxWindow != null) {
|
||||
FXBaseController fxController = getFXController(clazz, null, BEAN_BUILDER);
|
||||
return createWindow(fxWindow, clazz, fxController);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Stage getFXWindow(Class clazz, BeanBuilder beanBuilder) {
|
||||
FXWindow fxWindow = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
|
||||
if (fxWindow != null) {
|
||||
FXBaseController fxController = getFXController(clazz, null, beanBuilder);
|
||||
return createWindow(fxWindow, clazz, fxController);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Stage getFXWindow(Class clazz, String controllerName) {
|
||||
FXWindow fxWindow = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
|
||||
if (fxWindow != null) {
|
||||
FXBaseController fxController = getFXController(clazz, controllerName, BEAN_BUILDER);
|
||||
return createWindow(fxWindow, clazz, fxController);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Stage getFXWindow(Class clazz, String controllerName, BeanBuilder beanBuilder) {
|
||||
FXWindow fxWindow = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
|
||||
if (fxWindow != null) {
|
||||
FXBaseController fxController = getFXController(clazz, controllerName, beanBuilder);
|
||||
return createWindow(fxWindow, clazz, fxController);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseData(Object fxControllerObject) {
|
||||
Class clazz = fxControllerObject.getClass();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
FXData annotation = field.getAnnotation(FXData.class);
|
||||
if (annotation != null) {
|
||||
field.setAccessible(true);
|
||||
//建立代理
|
||||
try {
|
||||
Object fieldValue = field.get(fxControllerObject);
|
||||
Object fieldValueProxy = FXEntityFactory.wrapFXBean(fieldValue);
|
||||
field.set(fxControllerObject, fieldValueProxy);
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addDataInNameSpace(ObservableMap namespace, Object object) {
|
||||
Class clazz = object.getClass();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
FXData annotation = field.getAnnotation(FXData.class);
|
||||
if (annotation != null) {
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
String fx_id;
|
||||
field.setAccessible(true);
|
||||
if ("".equals(annotation.fx_id())) {
|
||||
fx_id = field.getName();
|
||||
} else {
|
||||
fx_id = annotation.fx_id();
|
||||
}
|
||||
Object fieldValue = field.get(object);
|
||||
namespace.put(fx_id, fieldValue);
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void scanBind(ObservableMap namespace, Object object) {
|
||||
Class clazz = object.getClass();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
parseBind(namespace, object, field);
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseBind(ObservableMap namespace, Object object, Field field) {
|
||||
FXBind fxBind = field.getAnnotation(FXBind.class);
|
||||
field.setAccessible(true);
|
||||
ExpressionParser expressionParser = new ExpressionParser(namespace, object);
|
||||
if (fxBind != null) {
|
||||
String[] expressions = fxBind.value();
|
||||
try {
|
||||
Object objectValue = field.get(object);
|
||||
for (String e : expressions) {
|
||||
expressionParser.parse(objectValue, e);
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchChangeMethod noSuchChangeMethod) {
|
||||
logger.error(noSuchChangeMethod.getMessage());
|
||||
noSuchChangeMethod.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isFXWindow(Class clazz) {
|
||||
if (clazz.getDeclaredAnnotation(FXWindow.class) != null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package cn.edu.scau.biubiusuisui.factory;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXField;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXFieldWrapper;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXPlusContext;
|
||||
import cn.edu.scau.biubiusuisui.proxy.FXEntityProxy;
|
||||
import cn.edu.scau.biubiusuisui.utils.ClassUtil;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.collections.FXCollections;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/28 1:12
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXEntityFactory {
|
||||
|
||||
private FXEntityFactory() {
|
||||
}
|
||||
|
||||
public static Object wrapFXBean(Class clazz) {
|
||||
return wrapFXBean(clazz, new FXBuilder());
|
||||
}
|
||||
|
||||
public static Object wrapFXBean(Class clazz, BeanBuilder beanBuilder) {
|
||||
Object object = null;
|
||||
object = beanBuilder.getBean(clazz);
|
||||
if (object != null) {
|
||||
return wrapFXBean(object);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object 被转换的对象
|
||||
* @return
|
||||
*/
|
||||
public static Object wrapFXBean(Object object) {
|
||||
FXEntityProxy fxEntityProxy = new FXEntityProxy();
|
||||
Object proxyObject = null;
|
||||
try {
|
||||
proxyObject = fxEntityProxy.getInstance(object); // 初始化代理类
|
||||
processFXEntityProxyFields(object, proxyObject, fxEntityProxy); //处理FXEntity上的@FXField
|
||||
FXPlusContext.setProxyByBeanObject(proxyObject, fxEntityProxy);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return proxyObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entityObject 被转换的原Entity对象
|
||||
* @param proxyObject 被转换对象的FXEntityProxy对象
|
||||
* @param fxEntityProxy 被转换对象的FXEntityProxy类
|
||||
* @throws IllegalAccessException
|
||||
* @Description 处理FXEntity中的FXField注解,1. 添加监听 2.赋值FXEntityProxy中的fxFieldWrapperMap
|
||||
*/
|
||||
private static void processFXEntityProxyFields(Object entityObject, Object proxyObject, FXEntityProxy fxEntityProxy) throws IllegalAccessException {
|
||||
Map<String, FXFieldWrapper> fxFieldWrapperMap = new HashMap<>();
|
||||
Field[] fields = entityObject.getClass().getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
Annotation annotation = ClassUtil.getAnnotationInList(FXField.class, field.getDeclaredAnnotations());
|
||||
if (annotation != null) {
|
||||
Property property = null;
|
||||
field.setAccessible(true);
|
||||
FXField fxField = (FXField) annotation;
|
||||
FXFieldWrapper fieldWrapper = new FXFieldWrapper(fxField, field.getType());
|
||||
if (field.get(entityObject) == null) { //没有初始值
|
||||
property = getFieldDefaultProperty(field);
|
||||
} else { //有初始值
|
||||
property = getFieldProperty(entityObject, field);
|
||||
}
|
||||
if (property != null) {
|
||||
// 监听
|
||||
property.addListener((object, oldVal, newVal) -> {
|
||||
if (!fxField.readOnly()) {
|
||||
// 判断field.getType()是否为List类型
|
||||
if (!List.class.isAssignableFrom(field.getType())) {
|
||||
try {
|
||||
field.set(proxyObject, newVal);//赋值
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// 设置属性
|
||||
fieldWrapper.setProperty(property);
|
||||
fxFieldWrapperMap.put(field.getName(), fieldWrapper);
|
||||
}
|
||||
}
|
||||
fxEntityProxy.setFXFieldWrapperMap(fxFieldWrapperMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entityObject
|
||||
* @param field
|
||||
* @return
|
||||
* @throws IllegalAccessException
|
||||
* @Description 某一属性中有初始值时
|
||||
*/
|
||||
private static Property getFieldProperty(Object entityObject, Field field) throws IllegalAccessException {
|
||||
Class type = field.getType();
|
||||
Object value = field.get(entityObject);
|
||||
Property property = null;
|
||||
|
||||
if (Boolean.class.equals(type) || boolean.class.equals(type)) {
|
||||
property = new SimpleBooleanProperty((Boolean) value);
|
||||
} else if (Double.class.equals(type) || double.class.equals(type)) {
|
||||
property = new SimpleDoubleProperty((Double) value);
|
||||
} else if (Float.class.equals(type) || float.class.equals(type)) {
|
||||
property = new SimpleFloatProperty((Float) value);
|
||||
} else if (Integer.class.equals(type) || int.class.equals(type)) {
|
||||
property = new SimpleIntegerProperty((Integer) value);
|
||||
} else if (Long.class.equals(type) || long.class.equals(type)) {
|
||||
property = new SimpleLongProperty((Long) value);
|
||||
} else if (String.class.equals(type)) {
|
||||
property = new SimpleStringProperty((String) value);
|
||||
} else if (List.class.isAssignableFrom(type)) {
|
||||
property = new SimpleListProperty(FXCollections.observableList((List) value));
|
||||
} else if (Object.class.isAssignableFrom(type)) {
|
||||
property = new SimpleObjectProperty(value);
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field
|
||||
* @return
|
||||
* @throws IllegalAccessException
|
||||
* @Description 某一属性中无初始值
|
||||
*/
|
||||
private static Property getFieldDefaultProperty(Field field) throws IllegalAccessException {
|
||||
Class type = field.getType();
|
||||
Property property = null;
|
||||
|
||||
if (Boolean.class.equals(type) || boolean.class.equals(type)) {
|
||||
property = new SimpleBooleanProperty();
|
||||
} else if (Double.class.equals(type) || double.class.equals(type)) {
|
||||
property = new SimpleDoubleProperty();
|
||||
} else if (Float.class.equals(type) || float.class.equals(type)) {
|
||||
property = new SimpleFloatProperty();
|
||||
} else if (Integer.class.equals(type) || int.class.equals(type)) {
|
||||
property = new SimpleIntegerProperty();
|
||||
} else if (Long.class.equals(type) || long.class.equals(type)) {
|
||||
property = new SimpleLongProperty();
|
||||
} else if (String.class.equals(type)) {
|
||||
property = new SimpleStringProperty();
|
||||
} else if (List.class.isAssignableFrom(type)) {
|
||||
property = new SimpleListProperty();
|
||||
} else if (Object.class.isAssignableFrom(type)) {
|
||||
property = new SimpleObjectProperty();
|
||||
}
|
||||
return property;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package cn.edu.scau.biubiusuisui.function;
|
||||
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/30 10:11
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class DragWindowHandlerImpl implements EventHandler<MouseEvent> {
|
||||
//参考<a href="https://www.cnblogs.com/moonlightL/p/5982679.html"></a>
|
||||
private Stage stage; //primaryStage为start方法头中的Stage
|
||||
private double oldStageX;
|
||||
private double oldStageY;
|
||||
private double oldScreenX;
|
||||
private double oldScreenY;
|
||||
final int RESIZE_WIDTH = 5;// 判定是否为调整窗口状态的范围与边界距离
|
||||
private double MIN_WIDTH = 300;// 窗口最小宽度
|
||||
private double MIN_HEIGHT = 250;// 窗口最小高度
|
||||
boolean isRight;// 是否处于右边界调整窗口状态
|
||||
boolean isBottomRight;// 是否处于右下角调整窗口状态
|
||||
boolean isBottom;// 是否处于下边界调整窗口状态
|
||||
private Pane pane;
|
||||
private boolean resizable; //是否拉伸
|
||||
private boolean draggable; //是否拖拽
|
||||
|
||||
|
||||
public DragWindowHandlerImpl(Stage primaryStage, Pane pane, boolean draggable, boolean resizable) { //构造器
|
||||
this.stage = primaryStage;
|
||||
this.pane = pane;
|
||||
this.draggable = draggable;
|
||||
this.resizable = resizable;
|
||||
}
|
||||
|
||||
public DragWindowHandlerImpl(Stage stage, double MIN_WIDTH, double MIN_HEIGHT, Pane pane, boolean draggable, boolean resizable) {
|
||||
this.stage = stage;
|
||||
this.MIN_WIDTH = MIN_WIDTH;
|
||||
this.MIN_HEIGHT = MIN_HEIGHT;
|
||||
this.pane = pane;
|
||||
this.draggable = draggable;
|
||||
this.resizable = resizable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(MouseEvent e) {
|
||||
|
||||
if (e.getEventType() == MouseEvent.MOUSE_PRESSED) { //鼠标按下的事件
|
||||
//鼠标按下时记录坐标
|
||||
this.oldStageX = this.stage.getX();
|
||||
this.oldStageY = this.stage.getY();
|
||||
this.oldScreenX = e.getScreenX();
|
||||
this.oldScreenY = e.getScreenY();
|
||||
} else if (e.getEventType() == MouseEvent.MOUSE_DRAGGED) { //鼠标拖动的事件
|
||||
double nextX = stage.getX();
|
||||
double nextY = stage.getY();
|
||||
double nextWidth = stage.getWidth();
|
||||
double nextHeight = stage.getHeight();
|
||||
|
||||
double x = e.getSceneX();
|
||||
double y = e.getSceneY();
|
||||
// 保存窗口改变后的x、y坐标和宽度、高度,用于预判是否会小于最小宽度、最小高度
|
||||
if (isRight || isBottomRight) {// 所有右边调整窗口状态
|
||||
nextWidth = x;
|
||||
}
|
||||
if (isBottomRight || isBottom) {// 所有下边调整窗口状态
|
||||
nextHeight = y;
|
||||
}
|
||||
if (nextWidth <= MIN_WIDTH) {// 如果窗口改变后的宽度小于最小宽度,则宽度调整到最小宽度
|
||||
nextWidth = MIN_WIDTH;
|
||||
}
|
||||
if (nextHeight <= MIN_HEIGHT) {// 如果窗口改变后的高度小于最小高度,则高度调整到最小高度
|
||||
nextHeight = MIN_HEIGHT;
|
||||
}
|
||||
|
||||
// 最后统一改变窗口的x、y坐标和宽度、高度,可以防止刷新频繁出现的屏闪情况
|
||||
if (draggable) {
|
||||
if (isBottom || isBottomRight || isRight) {
|
||||
stage.setX(nextX);
|
||||
stage.setY(nextY);
|
||||
} else {
|
||||
this.stage.setX(e.getScreenX() - this.oldScreenX + this.oldStageX);
|
||||
this.stage.setY(e.getScreenY() - this.oldScreenY + this.oldStageY);
|
||||
}
|
||||
}
|
||||
if (resizable) {
|
||||
stage.setWidth(nextWidth);
|
||||
stage.setHeight(nextHeight);
|
||||
}
|
||||
} else if (e.getEventType() == MouseEvent.MOUSE_MOVED) { //鼠标移动
|
||||
e.consume();
|
||||
double x = e.getSceneX();
|
||||
double y = e.getSceneY();
|
||||
double width = stage.getWidth();
|
||||
double height = stage.getHeight();
|
||||
Cursor cursorType = Cursor.DEFAULT;// 鼠标光标初始为默认类型,若未进入调整窗口状态,保持默认类型
|
||||
// 先将所有调整窗口状态重置
|
||||
isRight = isBottomRight = isBottom = false;
|
||||
|
||||
if (resizable) {
|
||||
if (y >= height - RESIZE_WIDTH) {
|
||||
if (x <= RESIZE_WIDTH) {// 左下角调整窗口状态
|
||||
|
||||
} else if (x >= width - RESIZE_WIDTH) {// 右下角调整窗口状态
|
||||
isBottomRight = true;
|
||||
cursorType = Cursor.SE_RESIZE;
|
||||
} else {// 下边界调整窗口状态
|
||||
isBottom = true;
|
||||
cursorType = Cursor.S_RESIZE;
|
||||
}
|
||||
} else if (x >= width - RESIZE_WIDTH) {// 右边界调整窗口状态
|
||||
isRight = true;
|
||||
cursorType = Cursor.E_RESIZE;
|
||||
}
|
||||
// 最后改变鼠标光标
|
||||
pane.setCursor(cursorType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.edu.scau.biubiusuisui.function;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/7/27 1:54
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public interface Draggable {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package cn.edu.scau.biubiusuisui.function;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
|
||||
import cn.edu.scau.biubiusuisui.exception.ProtocolNotSupport;
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLoggerFactory;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
import cn.edu.scau.biubiusuisui.utils.FileUtil;
|
||||
import cn.edu.scau.biubiusuisui.utils.StringUtil;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/30 10:40
|
||||
* @description 解析@FXWindow
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXWindowParser {
|
||||
private static final IFXPlusLogger logger = FXPlusLoggerFactory.getLogger(FXWindowParser.class);
|
||||
|
||||
public void parse(Stage stage, FXBaseController fxControllerProxy, FXWindow fxWindow) {
|
||||
logger.info("parsing @FXWindow of class: " + fxControllerProxy.getName());
|
||||
|
||||
// 处理 title
|
||||
fxControllerProxy.setWindowTitle(fxWindow.title());
|
||||
|
||||
// 处理 icon
|
||||
fxControllerProxy.setIcon(fxWindow.icon());
|
||||
|
||||
// 处理draggable和resizable
|
||||
if (fxWindow.draggable() || fxWindow.resizable()) {
|
||||
fxControllerProxy.setDragAndResize(fxWindow.draggable(), fxWindow.resizable());
|
||||
}
|
||||
|
||||
// fxWindow的resizable默认为false
|
||||
if (fxWindow.resizable()) {
|
||||
fxControllerProxy.setDragAndResize(fxWindow.draggable(), true);
|
||||
}
|
||||
|
||||
|
||||
// 处理style
|
||||
stage.initStyle(fxWindow.style());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.edu.scau.biubiusuisui.log;
|
||||
|
||||
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description JavaPlus的日志类
|
||||
* @date 2020/5/1 10:55
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXPlusLogger implements IFXPlusLogger {
|
||||
private Logger logger;
|
||||
private String FQCN;
|
||||
|
||||
public FXPlusLogger(Logger logger) {
|
||||
this.FQCN = FXPlusLogger.class.getName();
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public FXPlusLogger(String fqcn, Logger logger) {
|
||||
this.FQCN = fqcn;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message) {
|
||||
logger.log(FQCN, Level.DEBUG, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message, Throwable t) {
|
||||
logger.log(FQCN, Level.DEBUG, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message) {
|
||||
logger.log(FQCN, Level.INFO, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message, Throwable t) {
|
||||
logger.log(FQCN, Level.INFO, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message) {
|
||||
logger.log(FQCN, Level.WARN, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message, Throwable t) {
|
||||
logger.log(FQCN, Level.WARN, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message) {
|
||||
logger.log(FQCN, Level.ERROR, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message, Throwable t) {
|
||||
logger.log(FQCN, Level.ERROR, message, t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cn.edu.scau.biubiusuisui.log;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description 日志类上下文
|
||||
* @date 2020/5/1 10:56
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXPlusLoggerContext {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.edu.scau.biubiusuisui.log;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.utils.LogUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description 生成日志类的工厂
|
||||
* @date 2020/5/1 10:56
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXPlusLoggerFactory {
|
||||
|
||||
private FXPlusLoggerFactory() {
|
||||
|
||||
}
|
||||
|
||||
public static IFXPlusLogger getLogger(Class<?> clazz) {
|
||||
LogUtil.initLog4jBase();
|
||||
Logger logger = Logger.getLogger(clazz);
|
||||
return new FXPlusLogger(logger);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.edu.scau.biubiusuisui.log;
|
||||
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description 日志接口
|
||||
* @date 2020/5/1 10:54
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public interface IFXPlusLogger {
|
||||
void debug(Object message);
|
||||
|
||||
void debug(Object message, Throwable t);
|
||||
|
||||
void info(Object message);
|
||||
|
||||
void info(Object message, Throwable t);
|
||||
|
||||
void warn(Object message);
|
||||
|
||||
void warn(Object message, Throwable t);
|
||||
|
||||
void error(Object message);
|
||||
|
||||
void error(Object message, Throwable t);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package cn.edu.scau.biubiusuisui.mq;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXReceiver;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXMethodEntity;
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLoggerFactory;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 12:24
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class MessageQueue {
|
||||
private static final IFXPlusLogger logger = FXPlusLoggerFactory.getLogger(MessageQueue.class);
|
||||
|
||||
private static Map<String, List<FXMethodEntity>> receivers = new ConcurrentHashMap<>(); //Map<主题,订阅了主题的所有方法>
|
||||
|
||||
private static MessageQueue messageQueue = null;
|
||||
|
||||
private MessageQueue() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取mq单例
|
||||
*
|
||||
* @return MessageQueue
|
||||
*/
|
||||
public static synchronized MessageQueue getInstance() {
|
||||
if (messageQueue == null) {
|
||||
messageQueue = new MessageQueue();
|
||||
}
|
||||
return messageQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fxBaseController 基础controller
|
||||
* @param fxBaseControllerProxy 基础controller代理
|
||||
* @description 注册消费者,即FXReceiver注解的method
|
||||
*/
|
||||
public void registerConsumer(FXBaseController fxBaseController, FXBaseController fxBaseControllerProxy) {
|
||||
Class clazz = fxBaseController.getClass();
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
Annotation[] annotations = method.getDeclaredAnnotations();
|
||||
for (Annotation annotation : annotations) {
|
||||
if (FXReceiver.class.equals(annotation.annotationType())) {
|
||||
logger.info("registering consumer: " + fxBaseControllerProxy.getName());
|
||||
FXReceiver receiver = (FXReceiver) annotation;
|
||||
FXMethodEntity fxMethodEntity = new FXMethodEntity(fxBaseControllerProxy, method);
|
||||
List<FXMethodEntity> fxMethodEntities = receivers.get(receiver.name());
|
||||
if (fxMethodEntities == null) {
|
||||
fxMethodEntities = new ArrayList<>();
|
||||
}
|
||||
fxMethodEntities.add(fxMethodEntity);
|
||||
receivers.put(receiver.name(), fxMethodEntities);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id 消息topic
|
||||
* @param msg 消息内容
|
||||
* @description 处理消息发送
|
||||
*/
|
||||
public void sendMsg(String id, Object msg) {
|
||||
List<FXMethodEntity> lists = receivers.get(id);
|
||||
if (lists != null) {
|
||||
for (FXMethodEntity fxMethodEntity : lists) {
|
||||
Method method = fxMethodEntity.getMethod();
|
||||
method.setAccessible(true);
|
||||
FXBaseController fxBaseController = fxMethodEntity.getFxBaseController();
|
||||
if (method.getParameterCount() == 0) {
|
||||
try {
|
||||
method.invoke(fxBaseController);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
// 调起FXReceiver注解的方法
|
||||
method.invoke(fxBaseController, msg);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package cn.edu.scau.biubiusuisui.proxy;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXRedirect;
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXSender;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
|
||||
import cn.edu.scau.biubiusuisui.mq.MessageQueue;
|
||||
import cn.edu.scau.biubiusuisui.stage.StageManager;
|
||||
import net.sf.cglib.proxy.Enhancer;
|
||||
import net.sf.cglib.proxy.MethodInterceptor;
|
||||
import net.sf.cglib.proxy.MethodProxy;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* This proxy class intercept Methods that has special annotation such as
|
||||
* FXSender which is a mark for message queue
|
||||
*
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 2:03
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXControllerProxy implements MethodInterceptor {
|
||||
|
||||
|
||||
FXBaseController target;
|
||||
|
||||
|
||||
public Object getInstance(FXBaseController target) {
|
||||
this.target = target;
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(this.target.getClass());
|
||||
enhancer.setCallback(this);
|
||||
Object proxy = enhancer.create();
|
||||
// target.* -> proxy.*
|
||||
inject(target, proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
|
||||
Object o1 = methodProxy.invokeSuper(o, objects); //获取该方法运行后的结果
|
||||
Annotation[] annotations = method.getDeclaredAnnotations();
|
||||
|
||||
for (Annotation annotation : annotations) {
|
||||
if (FXSender.class.equals(annotation.annotationType())) { // 拦截是否发送消息函数
|
||||
FXSender fxSender = (FXSender) annotation;
|
||||
// System.out.println("FXSender");
|
||||
String name = target.getName() + ":";
|
||||
// System.out.println("FXControllerProxy:" + name);
|
||||
if ("".equals(fxSender.name())) {
|
||||
name += method.getName();
|
||||
} else {
|
||||
name += fxSender.name();
|
||||
}
|
||||
MessageQueue.getInstance().sendMsg(name, o1);
|
||||
}
|
||||
if (FXRedirect.class.equals((annotation.annotationType()))) { //拦截是否重定向函数
|
||||
FXRedirect fxRedirect = (FXRedirect) annotation;
|
||||
if (fxRedirect.close()) { //关闭原窗口
|
||||
StageManager.getInstance().closeStage(target.getName());
|
||||
}
|
||||
StageManager.getInstance().redirectTo(o1);
|
||||
}
|
||||
}
|
||||
return o1;
|
||||
}
|
||||
|
||||
private void inject(Object target, Object proxy) {
|
||||
Class clazz = target.getClass();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
Object value = field.get(target);
|
||||
field.set(proxy, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package cn.edu.scau.biubiusuisui.proxy;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.entity.FXFieldWrapper;
|
||||
import cn.edu.scau.biubiusuisui.utils.StringUtil;
|
||||
import javafx.beans.property.*;
|
||||
import net.sf.cglib.proxy.Enhancer;
|
||||
import net.sf.cglib.proxy.MethodInterceptor;
|
||||
import net.sf.cglib.proxy.MethodProxy;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/27 18:47
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FXEntityProxy implements MethodInterceptor {
|
||||
|
||||
Object target;
|
||||
private Map<String, FXFieldWrapper> fxFieldWrapperMap;
|
||||
|
||||
/**
|
||||
* @param target
|
||||
* @return
|
||||
* @Desciption 通过getInstance获取代理对象
|
||||
*/
|
||||
public Object getInstance(Object target) {
|
||||
this.target = target;
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(this.target.getClass());
|
||||
enhancer.setCallback(this);
|
||||
return enhancer.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* intercept get and set method and
|
||||
*
|
||||
* @param proxy cglib生成的代理对象
|
||||
* @param method 被代理对象的方法
|
||||
* @param args 拦截的方法的入参
|
||||
* @param methodProxy 拦截方法的代理方法
|
||||
* @return
|
||||
* @throws Throwable
|
||||
* @Descripton 拦截getter, setter, del, cls, add方法
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
|
||||
Object revokeResult = methodProxy.invokeSuper(proxy, args); //获取该方法运行后的结果
|
||||
String methodName = method.getName();
|
||||
String fieldName = null;
|
||||
if (methodName.length() >= 3) {
|
||||
fieldName = StringUtil.toInstanceName(methodName.substring(3)); // 该method有可能是getter和setter方法,进行处理
|
||||
} else {
|
||||
return revokeResult;
|
||||
}
|
||||
FXFieldWrapper fxFieldWrapper = fxFieldWrapperMap.get(fieldName);
|
||||
Property property = getPropertyByFieldName(fieldName);
|
||||
if (fxFieldWrapper == null || property == null) { //非属性的getter或setter
|
||||
return revokeResult;
|
||||
}
|
||||
Class type = fxFieldWrapper.getType();
|
||||
if (methodName.startsWith("set")) {
|
||||
if (Boolean.class.equals(type) || boolean.class.equals(type)) {
|
||||
((SimpleBooleanProperty) property).set((Boolean) args[0]);
|
||||
} else if (Double.class.equals(type) || double.class.equals(type)) {
|
||||
((SimpleDoubleProperty) property).set((Double) args[0]);
|
||||
} else if (Float.class.equals(type) || float.class.equals(type)) {
|
||||
((SimpleFloatProperty) property).set((Float) args[0]);
|
||||
} else if (Integer.class.equals(type) || int.class.equals(type)) {
|
||||
((SimpleIntegerProperty) property).set((Integer) args[0]);
|
||||
} else if (Long.class.equals(type) || long.class.equals(type)) {
|
||||
((SimpleLongProperty) property).set((Long) args[0]);
|
||||
} else if (String.class.equals(type)) {
|
||||
((SimpleStringProperty) property).set((String) args[0]);
|
||||
}
|
||||
} else if (methodName.startsWith("add")) {
|
||||
((SimpleListProperty) (property)).add(args[0]);
|
||||
} else if (methodName.startsWith("del")) {
|
||||
((SimpleListProperty) (property)).remove(args[0]);
|
||||
} else if (methodName.startsWith("cls")) {
|
||||
((SimpleListProperty) (property)).clear();
|
||||
}
|
||||
return revokeResult;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(Object target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public Property getPropertyByFieldName(String name) {
|
||||
if (fxFieldWrapperMap.get(name) == null) {
|
||||
return null;
|
||||
}
|
||||
return fxFieldWrapperMap.get(name).getProperty();
|
||||
}
|
||||
|
||||
public Map<String, FXFieldWrapper> getFXFieldWrapperMap() {
|
||||
return fxFieldWrapperMap;
|
||||
}
|
||||
|
||||
public void setFXFieldWrapperMap(Map<String, FXFieldWrapper> fxFieldWrapperMap) {
|
||||
this.fxFieldWrapperMap = fxFieldWrapperMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package cn.edu.scau.biubiusuisui.stage;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXPlusContext;
|
||||
import cn.edu.scau.biubiusuisui.entity.FXRedirectParam;
|
||||
import cn.edu.scau.biubiusuisui.exception.InvalidURLException;
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLoggerFactory;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.1
|
||||
* @description 舞台管理器
|
||||
* @date 2019/12/3 15:43
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class StageManager {
|
||||
private static IFXPlusLogger logger = FXPlusLoggerFactory.getLogger(StageManager.class);
|
||||
|
||||
private static StageManager stageManager = null;
|
||||
private static Map<String, FXBaseController> initWindows = new ConcurrentHashMap<>();
|
||||
private static Map<String, Class> windowClazz = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* @author yangsuiyu
|
||||
* @description 1.2新增属性
|
||||
*/
|
||||
private static ArrayDeque<FXBaseController> windowsStack = new ArrayDeque<>();
|
||||
|
||||
private StageManager() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static synchronized StageManager getInstance() {
|
||||
if (stageManager == null) {
|
||||
stageManager = new StageManager();
|
||||
}
|
||||
return stageManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册FXWindow注解的Controller
|
||||
*
|
||||
* @param clazz
|
||||
* @param fxBaseControllerProxy
|
||||
*/
|
||||
public void registerWindow(Class clazz, FXBaseController fxBaseControllerProxy) {
|
||||
fxBaseControllerProxy.getClass().getDeclaredAnnotations();
|
||||
initWindows.put(fxBaseControllerProxy.getName(), fxBaseControllerProxy);
|
||||
windowClazz.put(fxBaseControllerProxy.getName(), clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭窗口
|
||||
*
|
||||
* @param controllerName
|
||||
*/
|
||||
public void closeStage(String controllerName) {
|
||||
if (initWindows.get(controllerName) != null) {
|
||||
initWindows.get(controllerName).closeStage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param redirectParams
|
||||
* @Description 跳转
|
||||
*/
|
||||
public void redirectTo(Object redirectParams) {
|
||||
FXRedirectParam fxRedirectParam = null;
|
||||
if (redirectParams instanceof String) {
|
||||
if (((String) redirectParams).contains("?")) { //有参数,query return "SuccessController?name=ss&psw=111"
|
||||
try {
|
||||
fxRedirectParam = getQueryParamsFromURL((String) redirectParams);
|
||||
} catch (InvalidURLException e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else { //无参数 return "SuccessController"
|
||||
fxRedirectParam = new FXRedirectParam((String) redirectParams);
|
||||
}
|
||||
} else if (redirectParams instanceof FXRedirectParam) { // return FXRedirectParam
|
||||
fxRedirectParam = (FXRedirectParam) redirectParams;
|
||||
}
|
||||
redirectWithParams(fxRedirectParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fxRedirectParam
|
||||
* @Description 携带参数跳转
|
||||
*/
|
||||
private void redirectWithParams(FXRedirectParam fxRedirectParam) {
|
||||
if (fxRedirectParam != null) {
|
||||
String toControllerStr = fxRedirectParam.getToController();
|
||||
FXBaseController toController = initWindows.get(toControllerStr);
|
||||
if (toController != null) {
|
||||
List<FXBaseController> controllers = FXPlusContext.getControllers(toController.getName());
|
||||
// if (controllers.size() > 0) {
|
||||
// FXBaseController newController = controllers.get(controllers.size() - 1);
|
||||
// toController = FXControllerFactory.getFXController(newController.getClass(), toControllerStr);
|
||||
//// registerWindow(, toController);
|
||||
// }
|
||||
logger.debug("redirecting to " + toController.getName());
|
||||
toController.setParam(fxRedirectParam.getParams());
|
||||
toController.setQuery(fxRedirectParam.getQueryMap());
|
||||
toController.showStage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RedirectController?num=10&name=suisui -> Map:{"num","10"},{"name","suisui"}
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
private FXRedirectParam getQueryParamsFromURL(String url) throws InvalidURLException {
|
||||
String[] items = url.split("\\?");
|
||||
if (items.length != 2) {
|
||||
throw new InvalidURLException();
|
||||
}
|
||||
String leftBase = items[0];
|
||||
String paramsStr = items[1];
|
||||
String[] paramsKV = paramsStr.split("&");
|
||||
|
||||
FXRedirectParam fxRedirectParam = new FXRedirectParam(leftBase);
|
||||
for (int i = 0; i < paramsKV.length; i++) {
|
||||
String params[] = paramsKV[i].split("=");
|
||||
if (params.length != 2) {
|
||||
throw new InvalidURLException();
|
||||
} else {
|
||||
fxRedirectParam.addQuery(params[0], params[1]);
|
||||
}
|
||||
}
|
||||
return fxRedirectParam;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.edu.scau.biubiusuisui.utils;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.entity.FXPlusContext;
|
||||
import cn.edu.scau.biubiusuisui.proxy.FXEntityProxy;
|
||||
import javafx.beans.property.Property;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @Date:2019/7/28 1:52
|
||||
* @Description:
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class BeanUtil {
|
||||
public static Property getPropertyByName(Object entity, String fieldName) {
|
||||
FXEntityProxy fxEntityProxy = FXPlusContext.getProxyByBeanObject(entity);
|
||||
if (fxEntityProxy == null) {
|
||||
return null;
|
||||
}
|
||||
return fxEntityProxy.getFXFieldWrapperMap().get(fieldName).getProperty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package cn.edu.scau.biubiusuisui.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 5:20
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class ClassUtil {
|
||||
private ClassLoader classLoader;
|
||||
|
||||
public ClassUtil() {
|
||||
classLoader = getClass().getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有FxController的类名
|
||||
*
|
||||
* @param base 基础目录路径
|
||||
* @param nameList 类名列表
|
||||
* @return 所有FXController的类名列表
|
||||
*/
|
||||
private List<String> getAllFXControllerClassName(String base, List<String> nameList) throws UnsupportedEncodingException {
|
||||
String splashPath = StringUtil.dotToSplash(base);
|
||||
URL url = classLoader.getResource(splashPath);
|
||||
String filePath = StringUtil.getRootPath(url);
|
||||
List<String> names = null;
|
||||
if (filePath.endsWith("jar")) {
|
||||
nameList = readFromJarDirectory(filePath, base);
|
||||
} else {
|
||||
names = readFromDirectory(filePath);
|
||||
for (String name : names) {
|
||||
if (isClassFile(name)) {
|
||||
nameList.add(toFullyQualifiedName(name, base));
|
||||
} else if (isDirectory(name)) {
|
||||
nameList = getAllFXControllerClassName(base + "." + name, nameList);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nameList;
|
||||
}
|
||||
|
||||
public List<String> scanAllClassName(String base) throws UnsupportedEncodingException {
|
||||
return getAllFXControllerClassName(base, new LinkedList<>());
|
||||
}
|
||||
|
||||
private static String toFullyQualifiedName(String shortName, String basePackage) {
|
||||
StringBuilder sb = new StringBuilder(basePackage);
|
||||
sb.append('.');
|
||||
sb.append(StringUtil.trimExtension(shortName));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static boolean isClassFile(String name) {
|
||||
return name.endsWith(".class");
|
||||
}
|
||||
|
||||
private static boolean isDirectory(String name) {
|
||||
return !name.contains(".");
|
||||
}
|
||||
|
||||
private static List<String> readFromDirectory(String path) {
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
return readFromFileDirectory(path);
|
||||
}
|
||||
|
||||
private static List<String> readFromJarDirectory(String path, String packageName) {
|
||||
JarFile jarFile = null;
|
||||
try {
|
||||
jarFile = new JarFile(path);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Enumeration<JarEntry> entrys = jarFile.entries();
|
||||
List<String> classNames = new ArrayList<>();
|
||||
while (entrys.hasMoreElements()) {
|
||||
JarEntry jarEntry = entrys.nextElement();
|
||||
if (!jarEntry.getName().endsWith(".class")) continue;
|
||||
int packageNameIndex = jarEntry.getName().indexOf("/");
|
||||
if ("".equals(packageName)) {
|
||||
classNames.add(jarEntry.getName());
|
||||
} else {
|
||||
if (packageNameIndex == -1) continue;
|
||||
String baseName = jarEntry.getName().substring(0, packageNameIndex);
|
||||
if (baseName.equals(packageName)) {
|
||||
classNames.add(StringUtil.trimExtension(jarEntry.getName()).replaceAll("/", "."));
|
||||
}
|
||||
}
|
||||
}
|
||||
return classNames;
|
||||
}
|
||||
|
||||
private static List<String> readFromFileDirectory(String path) {
|
||||
File file = new File(path);
|
||||
String[] names = file.list();
|
||||
if (null == names) {
|
||||
return null;
|
||||
} else {
|
||||
return Arrays.asList(names);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean hasDeclaredAnnotation(Class clazz, Class annotation) {
|
||||
if (annotation == null) {
|
||||
return false;
|
||||
}
|
||||
if (hasAnnotationInList(annotation, clazz.getDeclaredAnnotations())) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasAnnotation(Class clazz, Class annotation) {
|
||||
if (annotation == null) {
|
||||
return false;
|
||||
}
|
||||
if (hasAnnotationInList(annotation, clazz.getAnnotations())) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasAnnotationInList(Class annotation, Annotation[] annotations2) {
|
||||
if (getAnnotationInList(annotation, annotations2) == null) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static Annotation getAnnotationInList(Class annotation, Annotation[] annotations) {
|
||||
if (annotations == null || annotation == null) {
|
||||
return null;
|
||||
}
|
||||
for (Annotation annotation1 : annotations) {
|
||||
if (annotation1.annotationType().equals(annotation)) {
|
||||
return annotation1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void copyField(Object target, Object base) {
|
||||
Class clazz = base.getClass();
|
||||
Class targetClass = target.getClass();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package cn.edu.scau.biubiusuisui.utils;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.exception.ProtocolNotSupport;
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLoggerFactory;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 7:01
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class FileUtil {
|
||||
private static IFXPlusLogger logger = FXPlusLoggerFactory.getLogger(FileUtil.class);
|
||||
|
||||
/**
|
||||
* @param filePath
|
||||
* @return 返回URL
|
||||
* @throws ProtocolNotSupport
|
||||
* @decription 从resources文件夹中读取File
|
||||
* 输出如: file:/Users/suisui/workspace/Idea/JavaFX-Plus/target/classes/image/icon.png
|
||||
* @version 1.0
|
||||
*/
|
||||
public URL getFilePathFromResources(String filePath) throws ProtocolNotSupport {
|
||||
return FileUtil.class.getClassLoader().getResource(filePath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param filePath
|
||||
* @return
|
||||
* @description 读取resources文件夹下的file,相对于resources的文件路径,如 resources/config.conf 则只需 config.conf
|
||||
*/
|
||||
public static String readFileFromResources(String filePath) throws UnsupportedEncodingException {
|
||||
URL url = FileUtil.class.getClassLoader().getResource(filePath);
|
||||
if (url != null) {
|
||||
String path = StringUtil.getRootPath(url);
|
||||
return readFile(path);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filePath 绝对路径或相对路径
|
||||
* @return 返回文件内容
|
||||
* @description 读取文件
|
||||
*/
|
||||
public static String readFile(String filePath) {
|
||||
StringBuffer content = new StringBuffer();
|
||||
try (FileReader reader = new FileReader(filePath);
|
||||
BufferedReader br = new BufferedReader(reader) // 建立一个对象,它把文件内容转成计算机能读懂的语言
|
||||
) {
|
||||
String temp;
|
||||
while ((temp = br.readLine()) != null) {
|
||||
// 一次读入一行数据
|
||||
content.append(temp + "\r\n");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
return content.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filePath 写出文件的地址
|
||||
* @param content 文件内容
|
||||
* @description 写文件
|
||||
*/
|
||||
public static void writeFile(String filePath, String content) {
|
||||
try {
|
||||
File writeName = new File(filePath); // 相对路径,如果没有则要建立一个新的output.txt文件
|
||||
writeName.createNewFile(); // 创建新文件,有同名的文件的话直接覆盖
|
||||
try (FileWriter writer = new FileWriter(writeName);
|
||||
BufferedWriter out = new BufferedWriter(writer)
|
||||
) {
|
||||
out.write(content);
|
||||
out.flush(); // 把缓存区内容压入文件
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package cn.edu.scau.biubiusuisui.utils;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @description 函数工具类
|
||||
* @date 2020/8/28 23:32
|
||||
* @since JDK1.8
|
||||
*/
|
||||
public class FunctionUtil {
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.edu.scau.biubiusuisui.utils;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2.0
|
||||
* <p> Description: JavaFx-Plus常量 </p>
|
||||
* @time 2021/9/5 10:36 下午
|
||||
*/
|
||||
public interface IFxPlusConstants {
|
||||
/**
|
||||
* 项目默认编码 UTF-8
|
||||
*/
|
||||
String DEFAULT_CHARSET = "UTF-8";
|
||||
/**
|
||||
* FXController名称分隔符
|
||||
*/
|
||||
String CONTROLLER_NAME_SEPARATOR = "#";
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.edu.scau.biubiusuisui.utils;
|
||||
|
||||
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLogger;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description 日志工具类
|
||||
* @date 2020/5/1 10:54
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class LogUtil {
|
||||
private static final String FQCN = LogUtil.class.getName();
|
||||
private static IFXPlusLogger logger;
|
||||
|
||||
static {
|
||||
initLog4jBase();
|
||||
logger = new FXPlusLogger(FQCN, Logger.getLogger(LogUtil.class));
|
||||
}
|
||||
|
||||
public static void initLog4jBase() {
|
||||
if (System.getProperty("log.base") == null) {
|
||||
// 默认是当前目录下
|
||||
String projectPath = PathUtil.getCurrentPath();
|
||||
initLog4jBase(projectPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static void initLog4jBase(String base) {
|
||||
System.setProperty("log.base", base);
|
||||
}
|
||||
|
||||
public static void debug(Object message) {
|
||||
logger.debug(message);
|
||||
}
|
||||
|
||||
public static void debug(Object message, Throwable t) {
|
||||
logger.debug(message, t);
|
||||
}
|
||||
|
||||
public static void info(Object message) {
|
||||
logger.info(message);
|
||||
}
|
||||
|
||||
public static void info(Object message, Throwable t) {
|
||||
logger.debug(message, t);
|
||||
}
|
||||
|
||||
public static void warn(Object message) {
|
||||
logger.warn(message);
|
||||
}
|
||||
|
||||
public static void warn(Object message, Throwable t) {
|
||||
logger.warn(message, t);
|
||||
}
|
||||
|
||||
public static void error(Object message) {
|
||||
logger.error(message);
|
||||
}
|
||||
|
||||
public static void error(Object message, Throwable t) {
|
||||
logger.error(message, t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.edu.scau.biubiusuisui.utils;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description 路径工具类
|
||||
* @date 2020/5/2 14:43
|
||||
* @since JDK1.8
|
||||
*/
|
||||
public class PathUtil {
|
||||
public static String getCurrentPath() {
|
||||
return System.getProperty("user.dir");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package cn.edu.scau.biubiusuisui.utils;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.entity.FXPlusLocale;
|
||||
import cn.edu.scau.biubiusuisui.exception.ProtocolNotSupport;
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLoggerFactory;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* @author suisui
|
||||
* @version 1.2
|
||||
* @description 语言国际化工具类
|
||||
* @date 2020/5/1 11:15
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
*/
|
||||
public class ResourceBundleUtil {
|
||||
private static final IFXPlusLogger logger = FXPlusLoggerFactory.getLogger(ResourceBundleUtil.class);
|
||||
|
||||
/**
|
||||
* @param baseName
|
||||
* @param fxPlusLocale
|
||||
* @return
|
||||
* @description 获取Java的ResourceBundle
|
||||
*/
|
||||
public static ResourceBundle getResourceBundle(String baseName, FXPlusLocale fxPlusLocale) {
|
||||
baseName = StringUtil.trimExtension(baseName);
|
||||
baseName = StringUtil.splashToDot(baseName);
|
||||
Locale locale = ResourceBundleUtil.getLocale(fxPlusLocale);
|
||||
|
||||
// logger.info(baseName);
|
||||
if (locale != null) {
|
||||
return ResourceBundle.getBundle(baseName, locale);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fxPlusLocale
|
||||
* @return
|
||||
* @description 通过FXPlusLocale枚举类型获取Locale
|
||||
*/
|
||||
private static Locale getLocale(FXPlusLocale fxPlusLocale) {
|
||||
switch (fxPlusLocale) {
|
||||
case SIMPLIFIED_CHINESE:
|
||||
return Locale.SIMPLIFIED_CHINESE;
|
||||
case FRANCE:
|
||||
return Locale.FRANCE;
|
||||
case KOREAN:
|
||||
return Locale.KOREAN;
|
||||
case ENGLISH:
|
||||
return Locale.UK;
|
||||
case GERMANY:
|
||||
return Locale.GERMANY;
|
||||
case ITALIAN:
|
||||
return Locale.ITALIAN;
|
||||
case AMERICAN:
|
||||
return Locale.US;
|
||||
case JAPANESE:
|
||||
return Locale.JAPAN;
|
||||
case TRADITIONAL_CHINESE:
|
||||
return Locale.TRADITIONAL_CHINESE;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @return
|
||||
* @description 通过key获取String类型的value值,失败或不存在返回空字符串
|
||||
*/
|
||||
public static String getStringValue(ResourceBundle resource, String key) {
|
||||
if ("".equals(key) || null == key) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
return resource.getString(key);
|
||||
} catch (MissingResourceException | ClassCastException e) {
|
||||
logger.error(e.getMessage());
|
||||
// e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @return
|
||||
* @description 通过key获取Integer类型的value值,失败或不存在返回-1
|
||||
*/
|
||||
public static Integer getIntegerValue(ResourceBundle resource, String key) {
|
||||
if ("".equals(key) || null == key) {
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
return Integer.valueOf(resource.getString(key));
|
||||
} catch (MissingResourceException | NumberFormatException e) {
|
||||
logger.error(e.getMessage());
|
||||
// e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package cn.edu.scau.biubiusuisui.utils;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.log.FXPlusLoggerFactory;
|
||||
import cn.edu.scau.biubiusuisui.log.IFXPlusLogger;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
/**
|
||||
* @author jack
|
||||
* @author suisui
|
||||
* @version 1.0
|
||||
* @date 2019/6/25 3:46
|
||||
* @since JavaFX2.0 JDK1.8
|
||||
* @since 1.3.0 add:继承StringUtils
|
||||
*/
|
||||
public class StringUtil extends StringUtils {
|
||||
private static IFXPlusLogger logger = FXPlusLoggerFactory.getLogger(StringUtil.class);
|
||||
|
||||
private StringUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* "file:/home/whf/cn/fh" -> "/home/whf/cn/fh"
|
||||
* "jar:file:/home/whf/foo.jar!cn/fh" -> "/home/whf/foo.jar"
|
||||
*/
|
||||
public static String getRootPath(URL url) throws UnsupportedEncodingException {
|
||||
String fileUrl = URLDecoder.decode(url.getFile(),IFxPlusConstants.DEFAULT_CHARSET);
|
||||
int pos = fileUrl.indexOf('!');
|
||||
|
||||
if (-1 == pos) {
|
||||
return fileUrl;
|
||||
}
|
||||
|
||||
return fileUrl.substring(5, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* "cn.fh.lightning" -> "cn/fh/lightning"
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static String dotToSplash(String name) {
|
||||
return name.replaceAll("\\.", "/");
|
||||
}
|
||||
|
||||
/**
|
||||
* "cn/fh/lightning" -> "cn.fh.lightning"
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static String splashToDot(String name) {
|
||||
return name.replaceAll("/", "\\.");
|
||||
}
|
||||
|
||||
/**
|
||||
* "Apple.class" -> "Apple"
|
||||
*/
|
||||
public static String trimExtension(String name) {
|
||||
int pos = name.lastIndexOf('.');
|
||||
if (-1 != pos) {
|
||||
return name.substring(0, pos);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* /application/home -> /home
|
||||
*
|
||||
* @param uri
|
||||
* @return
|
||||
*/
|
||||
public static String trimURI(String uri) {
|
||||
String trimmed = uri.substring(1);
|
||||
int splashIndex = trimmed.indexOf('/');
|
||||
return trimmed.substring(splashIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* MainController$receive -> MainController
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static String getBaseClassName(String name) {
|
||||
int index = name.indexOf("$");
|
||||
if (index == -1) {
|
||||
return name;
|
||||
}
|
||||
// System.out.println(name.substring(0, index));
|
||||
return name.substring(0, index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Object -> object ; Student -> student
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static String toInstanceName(String name) {
|
||||
return name.substring(0, 1).toLowerCase().concat(name.substring(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* object -> Object ; student -> Student
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static String toClassName(String name) {
|
||||
return name.substring(0, 1).toUpperCase().concat(name.substring(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* cn/edu/scau/biubiusuisui/resources/fxml/languageDemo/langDemo.fxml -> fxml/languageDemo/langDemo.fxml
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
* @description 获取相对于resources目录下的路径
|
||||
*/
|
||||
public static String getFilePathInResources(String name) {
|
||||
String resources = "resources";
|
||||
int resIdx = name.indexOf(resources);
|
||||
if (resIdx == -1) {
|
||||
return name;
|
||||
}
|
||||
return name.substring(resIdx + resources.length() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* cn/edu/scau/biubiusuisui/resources/fxml/languageDemo/langDemo.fxml -> languageDemo
|
||||
*
|
||||
* @param name 文件名
|
||||
* @return
|
||||
* @version 1.2
|
||||
*/
|
||||
public static String getFileBaseName(String name) {
|
||||
String result = "";
|
||||
String[] tempStrs = name.split("/");
|
||||
if (1 == tempStrs.length) { //只有文件名,即name: langDemo.fxml
|
||||
result = StringUtil.trimExtension(name);
|
||||
} else {
|
||||
result = StringUtil.trimExtension(tempStrs[tempStrs.length - 1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
20
javafx-plus/src/main/resources/applicationContext.xml
Normal file
20
javafx-plus/src/main/resources/applicationContext.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?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: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/context http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
|
||||
<!-- <bean id="..." class="...">
|
||||
collaborators and configuration for this bean go here
|
||||
</bean>
|
||||
<bean id="..." class="...">
|
||||
collaborators and configuration for this bean go here
|
||||
</bean> -->
|
||||
|
||||
<!-- more bean definitions go here
|
||||
UserDao ud = new UserDao();
|
||||
-->
|
||||
<context:component-scan base-package="cn.edu.scau.biubiusuisui"/>
|
||||
|
||||
</beans>
|
||||
6
javafx-plus/src/main/resources/banner.txt
Normal file
6
javafx-plus/src/main/resources/banner.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
_ ________ __ _____ _
|
||||
| | | ____\ \ / / | __ \| |
|
||||
| | __ ___ ____ _| |__ \ V / _____ | |__) | |_ _ ___
|
||||
_ | |/ _` \ \ / / _` | __| > < _____ | ___/| | | | / __|
|
||||
| |__| | (_| |\ V / (_| | | / . \ | | | | |_| \__ \
|
||||
\____/ \__,_| \_/ \__,_|_| /_/ \_\ |_| |_|\__,_|___/
|
||||
27
javafx-plus/src/main/resources/log4j.properties
Normal file
27
javafx-plus/src/main/resources/log4j.properties
Normal file
@@ -0,0 +1,27 @@
|
||||
### 设置###
|
||||
log4j.rootLogger=debug,stdout,D,E
|
||||
### 输出信息到控制台 ###
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] - %m%n
|
||||
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
|
||||
log4j.appender.D=org.apache.log4j.DailyRollingFileAppender
|
||||
### Windowsy
|
||||
#log4j.appender.D.File = E://logs/debug/log.log
|
||||
# MacOS
|
||||
log4j.appender.D.File=${log.base}/logs/debug/javafxplus.log
|
||||
log4j.appender.D.Append=true
|
||||
log4j.appender.D.Threshold=DEBUG
|
||||
log4j.appender.D.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.D.layout.ConversionPattern=[%p] %-d{yyyy-MM-dd HH:mm:ss} [%t] [%l] - %m%n
|
||||
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
|
||||
log4j.appender.E=org.apache.log4j.DailyRollingFileAppender
|
||||
### Windows
|
||||
#log4j.appender.E.File = E://logs/error/log.log
|
||||
# MacOS
|
||||
log4j.appender.E.File=${log.base}/logs/error/javafxplus.log
|
||||
log4j.appender.E.Append=true
|
||||
log4j.appender.E.Threshold=ERROR
|
||||
log4j.appender.E.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.E.layout.ConversionPattern=[%p] %-d{yyyy-MM-dd HH:mm:ss} [%t] [%l] - %m%n
|
||||
19
javafx-plus/src/test/java/MainTest.java
Normal file
19
javafx-plus/src/test/java/MainTest.java
Normal file
@@ -0,0 +1,19 @@
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
/**
|
||||
* @Author jack
|
||||
* @Date:2019/6/25 2:11
|
||||
*/
|
||||
public class MainTest {
|
||||
|
||||
public void testMethod(String a,int b){
|
||||
|
||||
}
|
||||
@Test
|
||||
public void test() throws NoSuchMethodException {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package cn.edu.scau.biubiusuisui.expression;
|
||||
|
||||
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/**
|
||||
* @Author jack
|
||||
* @Date:2019/7/24 11:55
|
||||
*/
|
||||
public class ExpressionParserTest {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.edu.scau.biubiusuisui.expression.data;
|
||||
|
||||
import cn.edu.scau.biubiusuisui.annotation.FXValue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @Author jack
|
||||
* @Date:2019/7/27 3:13
|
||||
*/
|
||||
public class ExpressionParserTest {
|
||||
|
||||
private ExpressionParser expressionParser;
|
||||
@Before
|
||||
public void init(){
|
||||
expressionParser = new ExpressionParser(null);
|
||||
}
|
||||
@Test
|
||||
public void parse() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getArgs() throws NoSuchMethodException {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package cn.edu.scau.biubiusuisui.factory;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @Author jack
|
||||
* @Date:2019/6/28 1:32
|
||||
*/
|
||||
public class FXEntityFactoryTest {
|
||||
|
||||
@Test
|
||||
public void getClassProperty() {
|
||||
// Student student = new Student();
|
||||
// student.setName("Jack");
|
||||
// try {
|
||||
// Map<String, Property> entityProperty = FXEntityFactory.processFXEntityProxy(student,null);
|
||||
// entityProperty.forEach((k,v)->{
|
||||
// System.out.println("key" + k +" v" + v);
|
||||
// });
|
||||
// } catch (IllegalAccessException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInstance() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createJavaBeanProxy() {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createJavaBeanProxy2() throws InstantiationException, IllegalAccessException {
|
||||
// Student student1 = (Student) FXEntityFactory.warpFxBean(Student.class);
|
||||
// System.out.println(student1);
|
||||
// FXPlusContext.getProxyByBeanObject(student1).getStringPropertyMap().forEach((k, v)->{
|
||||
// System.out.println("k " +k +"v" + v);
|
||||
// });
|
||||
// student1.setName("Jack");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntityProperty() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.edu.scau.biubiusuisui.utils;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class ClassUtilsTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
JarFile jarFile = null;
|
||||
try {
|
||||
jarFile = new JarFile("/Users/Jack/test.jar");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Enumeration<JarEntry> entrys = jarFile.entries();
|
||||
List<String> classNames = new ArrayList<>();
|
||||
while (entrys.hasMoreElements()) {
|
||||
JarEntry jarEntry = entrys.nextElement();
|
||||
classNames.add(jarEntry.getName());
|
||||
}
|
||||
classNames.forEach(System.out::println);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user