- 新增浏览器模块技术文档,涵盖 BrowserCore、BrowserWindow 等核心组件 - 添加事件系统文档,包括 EventBus、GlobalEventBus 及各类事件定义 - 创建 LanguageManager 国际化管理器详细说明文档 - 新增 Log4j2OutputStream 标准输出重定向类文档 - 添加 Main 入口类启动流程与路由机制说明 - 创建 BrowserCreationCallback 回调接口使用指南 - 完善 AxisInnovatorsBox 主类架构与崩溃诊断系统文档
5.9 KiB
5.9 KiB
这份文档是对 com.axis.innovators.box.browser 包核心架构的深度解析。它涵盖了从底层核心代理到高层 UI 容器,以及 Java-JS 桥接机制的所有关键类。
Axis Innovators Box Browser 核心类技术文档
本模块旨在为 Swing 应用程序提供一个高性能、易扩展的嵌入式浏览器解决方案。通过高度抽象的架构,开发者可以轻松地在 Java 窗口中嵌入 Web 页面,并实现双向通信。
1. 核心架构设计
系统采用了 代理模式 (Proxy Pattern) 和 构建者模式 (Builder Pattern):
- 核心逻辑 (
BrowserCore) 与 窗口容器 (BrowserWindow/BrowserWindowJDialog) 分离。 - 配置逻辑 (
BaseBrowserBuilder) 统一管理窗口属性。 - 通信逻辑 (
JsBridgeController) 通过注解驱动。
2. 接口与基类 (抽象层)
2.1 BrowserContainer.java (统一接口)
这是所有浏览器窗口容器的通用协议。无论是 JFrame 还是 JDialog,都必须实现此接口。
- 核心职责:提供对外的统一 API,使得
WindowRegistry和业务逻辑可以忽略窗口的具体物理类型。 - 关键方法:
executingJsCode(String script): 在 JS 环境中执行代码(支持跨线程)。setController(JsBridgeController controller): 动态切换 Java 逻辑控制器。getBrowser()/getMsgRouter(): 获取底层 CEF 对象。
2.2 BaseBrowserBuilder.java (通用配置器)
采用泛型链式调用的抽象构建器类。
- 核心职责:存储所有窗口初始化所需的配置数据(尺寸、标题、初始 URL、图标等)。
- 主要字段:
htmlUrl/htmlPath: 指定要加载的内容来源。operationHandler: 系统级消息处理器。controller: 初始的 JSBridge 控制器。size,title,resizable: 基础窗口属性。
3. UI 容器层 (实现层)
3.1 BrowserWindow.java
继承自 JFrame,用于创建独立的主窗口或顶层窗口。
- 特点:支持任务栏图标、最大化/最小化等标准窗口行为。
- 内部实现:通过
BrowserCore初始化浏览器组件,并将其作为BorderLayout.CENTER添加到内容面板。
3.2 BrowserWindowJDialog.java
继承自 JDialog,用于创建子窗口或模态/非模态对话框。
- 特点:支持设置
parentFrame,可以实现点击父窗口时弹窗保持在最前的逻辑。 - 应用场景:设置界面、详情弹窗、登录界面等。
4. 浏览器引擎核心
4.1 BrowserCore.java (系统大脑)
这是最关键的类,封装了 JCEF 的所有复杂逻辑。
- 职责:
- 初始化:管理
CefClient的创建和CefBrowser的生命周期。 - Handler 路由:自动设置加载监听、右键菜单处理、证书错误处理、文件选择对话框处理等。
- 通信初始化:配置
CefMessageRouter(基于window.javaQuery)。 - 脚本队列:维护
pendingScripts队列。如果页面尚未加载完成就调用了 JS 代码,代码会暂存在队列中,直到onLoadEnd触发后自动冲刷执行。 - 资源注入:自动向 Web 页面注入系统字体、主题颜色和
extLibsPath等全局变量。
- 初始化:管理
5. Java-JS 桥接机制 (通信层)
这是实现“Java 调用 JS”和“JS 调用 Java”的核心组件。
5.1 JsMapping.java (方法注解)
一个运行时注解,用于标记控制器中可以被 JS 访问的方法。
- 属性
value():- 若为空:默认挂载在
tzd.方法名()。 - 若为单纯字符串(如
"login"):挂载在tzd.login()。 - 若包含点号(如
"app.utils.calc"):挂载在window.app.utils.calc()。
- 若为空:默认挂载在
5.2 JsBridgeController.java (抽象控制器)
用户自定义业务逻辑的基类。
- 工作原理:
- 反射扫描:在初始化时自动扫描带有
@JsMapping的所有方法。 - 代码生成:
generateInjectionJs()会生成一套复杂的 JS 代理对象代码,在onLoadEnd时注入浏览器。 - 参数转换:利用 Gson 将 JS 传来的 JSON 数组自动反序列化为 Java 方法的参数类型(如
String,int,boolean或自定义 POJO)。 - 异步回调:封装了
window.javaQuery的复杂调用,使 JS 端可以像调用本地函数一样使用async/await获取结果。
- 反射扫描:在初始化时自动扫描带有
6. 开发流程示例
第一步:定义控制器
public class MyActionController extends JsBridgeController {
@JsMapping("saveConfig") // JS 调用: tzd.saveConfig(data)
public boolean save(String data) {
System.out.println("Saving: " + data);
return true;
}
@JsMapping("sys.getInfo") // JS 调用: sys.getInfo()
public String getInfo() {
return "Version 1.0.0";
}
}
第二步:启动窗口
WindowRegistry.getInstance().createNewChildWindow("win01", builder -> {
builder.title("我的应用")
.htmlPath("index.html")
.controller(new MyActionController()); // 绑定
});
第三步:前端调用
// index.html
async function doSave() {
// 调用 Java 并获取返回值
const success = await tzd.saveConfig("{id: 1}");
if (success) {
const info = await sys.getInfo();
alert("保存成功, " + info);
}
}
7. 最佳实践建议
- 资源管理:始终通过
WindowRegistry.unregisterWindow()关闭窗口,以确保内存和进程资源被释放。 - 线程注意事项:
executingJsCode是线程安全的,可以在任意线程调用。- 在
@JsMapping标记的 Java 方法中,如果涉及 UI 更新(如修改 Swing 组件),必须包裹在SwingUtilities.invokeLater中。
- 动态切换:由于
setController会重新注入脚本,建议在页面初次加载完成后进行控制器切换,以获得最佳稳定性。