背景
在上一篇的博客JavaFX爱好者看过来,这款工具值得拥有中,简单介绍了一款JavaFx开发框架xJavaFxTool。本次将采用debug的方式对xJavaFxTool进行调试,深度讲解重点模块的代码设计实现。希望通过本文的讲解,能够让您对xJavaFxTool有更深入的了解和认识。
一、项目主体结构
在这里再次重复一遍工程项目的主体结构,遵循MVC三层架构,在JavaFx中也是有相应的应用的,视图层采用Fxml来进行展示,控制层有对应的Contoller,每个视图层对象都会对应一个Controller,模型层对象这里采用了多个JavaBean和业务实体来组成,共同完成相应的逻辑功能封装。
xJavaFxTool ├─ images 项目截图 ├─ pom.xml maven配置文件 ├─ README.md 说明文件 ├─ src │ ├─ main │ │ ├─ java │ │ │ └─ com │ │ │ └─ xwintop │ │ │ └─ xJavaFxTool │ │ │ ├─ common 第三方工具类 │ │ │ ├─ controller javafx控制层 │ │ │ │ └─ index 首页控制层 │ │ │ ├─ model 基础bean类层 │ │ │ ├─ services 工具服务层 │ │ │ │ └─ index 首页工具服务层 │ │ │ ├─ utils 系统工具类 │ │ │ └─ view javafx视图层 │ │ │ └─ index 首页工具视图层 │ │ └─ resources │ │ ├─ com │ │ │ └─ xwintop │ │ │ └─ xJavaFxTool │ │ │ └─ fxmlView .fxml文件 │ │ ├─ config 配置文件 │ │ │ └─ toolFxmlLoaderConfiguration.xml 系统菜单加载配置文件 │ │ ├─ css 样式资源 │ │ ├─ images 图片资源 │ │ ├─ locale 国际化 │ │ ├─ banner.txt 启动banner图片 │ │ └─ logback.xml logback日志配置文件 │ └─ test 测试类 │ ├─ java │ └─ resources
二、Main.java 程序入口
-
public
static
void
main
(String[] args) {
-
XJavaFxSystemUtil.initSystemLocal();
//初始化本地语言
-
XJavaFxSystemUtil.addJarByLibs();
//添加外部jar包
-
-
SplashScreen
splashScreen
=
new
SplashScreen() {
-
@Override
-
public String
getImagePath
() {
-
return
"/images/javafx.png";
-
}
-
};
-
launch(Main.class, IndexView.class, splashScreen, args);
-
}
1、本地语言设置
下面通过Debug来看看在这短短的几行代码中会包含那些操作。第一步需要进行本地语言设置,通过调用InitSystemLocal方法来实现。
2、加载外置的插件jar包
-
/**
-
* @Title: addJarByLibs
-
* @Description: 添加libs中jar包到系统中
-
*/
-
public
static
void
addJarByLibs
() {
-
PluginManager.getInstance().loadLocalPlugins();
-
try {
-
// 系统类库路径
-
File
libPath
=
new
File(
"libs/");
-
// 获取所有的.jar和.zip文件
-
File[] jarFiles = libPath.listFiles(
-
(dir, name) -> name.endsWith(
".jar")
-
);
-
if (jarFiles !=
null) {
-
for (File file : jarFiles) {
-
if (!PluginManageService.isPluginEnabled(file.getName())) {
-
continue;
-
}
-
addJarClass(file);
-
}
-
}
-
}
catch (Exception e) {
-
log.error(
"添加libs中jar包到系统中异常:", e);
-
}
-
}
这里需要注意的是,为了方便集中统一管理jar包,将外置的可运行的jar都放在libs目录下面,应用程序启动后在固定目录下读取指定jar,通过反射即可完成插件的调用。这也是该框架的一个亮点,在开发时大大减少了工作量,也降低了代码的复杂度。
通过上述代码可以看到,通过配置的插件json配置,插件读取器会自动将数据解析并绑定到相应的数据集合中。下图是解析出来的插件json文件。
-
private
void
addOrUpdatePlugin
(PluginJarInfo pluginJarInfo, Consumer<PluginJarInfo> ifExists) {
-
PluginJarInfo
exists
= getPlugin(pluginJarInfo.getJarName());
-
if (exists ==
null) {
-
this.pluginList.add(pluginJarInfo);
-
}
else {
-
ifExists.accept(exists);
-
}
-
}
加载已下载插件,并通过反射机制进行调用,核心代码如下:
至此主程序的驱动入口函数调试完成,最后两行代码是指定程序的启动窗口。关键代码如下:
launch(Main.class, IndexView.class, splashScreen, args);
IndexView是应用程序的入口窗口。splashScreen定义了启动页面,同时在启动页面中嵌入了一张本地图片。
三、IndexView解析
通常来说,一个IndexView包含了三个文件,一个是IndexView.java,在这个文件中绑定了相对应的页面配置fxml,controller是页面视图对象上所有操作逻辑的处理对象。核心的功能也是放在Controller对象中。
-
@Scope("prototype")
-
@FXMLView(value = "/com/xwintop/xJavaFxTool/fxmlView/Index.fxml", bundle = "locale.Menu")
-
public
class
IndexView
extends
AbstractFxmlView {
-
public
IndexView
()
throws Exception {
-
//反射修改默认语言
-
ResourceBundle
bundle
= ResourceBundle.getBundle(
this.getResourceBundle().get().getBaseBundleName(), Config.defaultLocale);
-
FieldUtils.writeField(
this,
"bundle",Optional.ofNullable(bundle),
true);
-
GUIState.getStage().setTitle(bundle.getString(
"Title"));
//修改标题国际化
-
}
-
-
@Override
-
public Parent
getView
() {
-
JFXDecorator
decorator
= JavaFxViewUtil.getJFXDecorator(GUIState.getStage(),GUIState.getStage().getTitle() + Config.xJavaFxToolVersions,
"/images/icon.jpg",
super.getView());
-
decorator.setOnCloseButtonAction(() -> {
-
if (AlertUtil.showConfirmAlert(
"确定要退出吗?")) {
-
System.exit(
0);
-
}
-
});
-
return decorator;
-
}
-
}
下面是通过场景编辑器打开Index.Fxml页面对象,可以看到这里的布局选择器采用的是:AnchorPane、BorderPane,中间采用的是TabPane,通过Tab页来切换功能。
在这里主要完成页面上相关菜单的加载和展示。
-
private
void
initView
() {
-
menuMap.put(
"toolsMenu", toolsMenu);
-
menuMap.put(
"moreToolsMenu", moreToolsMenu);
-
File
libPath
=
new
File(
"libs/");
-
// 获取所有的.jar和.zip文件
-
File[] jarFiles = libPath.listFiles((dir, name) -> name.endsWith(
".jar"));
-
if (jarFiles !=
null) {
-
for (File jarFile : jarFiles) {
-
if (!PluginManageService.isPluginEnabled(jarFile.getName())) {
-
continue;
-
}
-
try {
-
this.addToolMenu(jarFile);
-
}
catch (Exception e) {
-
log.error(
"加载工具出错:", e);
-
}
-
}
-
}
-
}
通过以上的方法可以生成相应的菜单列表供调用。在默认的tab页面,前面可以看到有一个默认的记事本的页面。
-
public
void
addNodepadAction
(ActionEvent event) {
-
TextArea
notepad
=
new
TextArea();
-
notepad.setFocusTraversable(
true);
-
if (indexController.getSingleWindowBootCheckBox().isSelected()) {
-
JavaFxViewUtil.getNewStage(indexController.getBundle().getString(
"addNodepad"),
null, notepad);
-
}
else {
-
Tab
tab
=
new
Tab(indexController.getBundle().getString(
"addNodepad"));
-
tab.setContent(notepad);
-
indexController.getTabPaneMain().getTabs().add(tab);
-
if (event !=
null) {
-
indexController.getTabPaneMain().getSelectionModel().select(tab);
-
}
-
}
-
}
窗口的默认设置方法和参数可以参考以下的配置。
-
/**
-
* 获取新窗口
-
**/
-
public
static Stage
getNewStage
(String title, String iconUrl, Parent root) {
-
double[] screenSize = JavaFxSystemUtil.getScreenSizeByScale(
0.74,
0.8);
-
Stage
newStage
= getNewStageNull(title, iconUrl, root, screenSize[
0], screenSize[
1],
true,
true,
true);
-
newStage.initModality(Modality.NONE);
-
//newStage.setMaximized(false);
-
newStage.show();
-
return newStage;
-
}
四、总结
以上就是本文的主要内容,本文主要通过对代码进行debug的方式进行深入调试,详细讲解了在启动过程中,各业务逻辑模块是怎么工作的,插件的读取到菜单的生成,最重要的核心技术应该是用过JAVA的反射技术来实现动态注册及调用。心动不如行动,喜欢的朋友可以学习起来,给自己充电加油。
转载:https://blog.csdn.net/yelangkingwuzuhu/article/details/128467278