update:调整项目结构,将example独立抽离module

This commit is contained in:
suisui
2021-09-16 00:40:18 +08:00
parent 3543f8acd3
commit 2fc8a622ab
140 changed files with 101 additions and 5 deletions

68
javafx-plus/pom.xml Normal file
View 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>

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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 "";
}

View File

@@ -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 {
}

View File

@@ -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 "";
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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 ".";
}

View File

@@ -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 "";
}

View File

@@ -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();
}

View File

@@ -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 "";
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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,
}

View File

@@ -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);
}
}

View File

@@ -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");
}
}

View File

@@ -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");
}
}

View File

@@ -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");
}
}

View File

@@ -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");
}
}

View File

@@ -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);
}

View File

@@ -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) {
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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) {
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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 {
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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 {
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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());
}
}
}
}
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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 {
}

View File

@@ -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 = "#";
}

View File

@@ -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);
}
}

View File

@@ -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");
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View 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>

View File

@@ -0,0 +1,6 @@
_ ________ __ _____ _
| | | ____\ \ / / | __ \| |
| | __ ___ ____ _| |__ \ V / _____ | |__) | |_ _ ___
_ | |/ _` \ \ / / _` | __| > < _____ | ___/| | | | / __|
| |__| | (_| |\ V / (_| | | / . \ | | | | |_| \__ \
\____/ \__,_| \_/ \__,_|_| /_/ \_\ |_| |_|\__,_|___/

View 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

View 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 {
}
}

View File

@@ -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 {
}

View File

@@ -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 {
}
}

View File

@@ -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() {
}
}

View File

@@ -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);
}
}