- 新增SmbFileService服务类,支持SMB/CIFS协议的文件操作 - 修改合同文件管理逻辑,支持SMB路径检查与目录创建 - 优化BankTableCell实现工厂模式并更新相关文档 - 调整Redis配置并添加连接测试 - 修复合同发票视图模型的时间处理问题 - 更新项目版本至0.0.134-SNAPSHOT
8.3 KiB
8.3 KiB
客户端 Controller 类规则
1. 目录结构
客户端控制器位于client/src/main/java/com/ecep/contract/controller/目录下,按业务模块组织:
- 根目录:包含基础控制器、抽象控制器和主窗口控制器
- 业务子包:按业务领域组织,如
company/、project/、contract/、vendor/等 - tab/子包:包含所有Tab皮肤控制器和相关接口、抽象类
- table/子包:包含表格相关控制器和单元格实现
2. 命名规范
- 基础控制器:
BaseController.java - 抽象控制器:以
Abst开头,如AbstEntityController.java、AbstManagerWindowController.java - 窗口控制器:以
WindowController结尾,如HomeWindowController.java - 管理窗口控制器:以
ManagerWindowController结尾,如CompanyManagerWindowController.java - Tab皮肤控制器:以
TabSkin结尾,如CompanyTabSkinBase.java - 管理器皮肤:以
ManagerSkin结尾,如CompanyManagerSkin.java - 组件控制器:如
OkHttpLoginController.java
3. 继承关系
控制器类遵循以下继承层次结构:
BaseController:所有控制器的基础类,提供窗口显示、异常处理等通用功能AbstEntityBasedController:基于实体的控制器抽象类AbstManagerWindowController:管理窗口控制器的抽象类,包含搜索、分页等功能
AbstEntityController<T extends IdentityEntity, TV extends IdentityViewModel<T>>:实体详情窗口控制器的抽象类- 具体业务窗口控制器,如
CompanyWindowController、ProjectWindowController等
- 具体业务窗口控制器,如
Tab相关控制器继承关系:
Skin:皮肤接口基础TabSkin:Tab皮肤接口AbstGenericTabSkin<C extends BaseController>:通用Tab皮肤抽象类AbstEntityBasedTabSkin<C extends AbstEntityController<T, V>, T extends IdentityEntity, V extends IdentityViewModel<T>>:基于实体的Tab皮肤抽象类- 具体业务Tab皮肤控制器,如
CompanyTabSkinBase.java、ContractTabSkinFiles.java等
- 具体业务Tab皮肤控制器,如
4. 注解使用
客户端控制器类应使用以下注解:
@Component:声明为Spring组件,使其可被Spring容器管理@Scope("prototype"):设置为原型作用域,确保每次请求创建新实例@Lazy:延迟加载,提高应用启动性能@FxmlPath("/ui/[业务模块]/[文件名].fxml"):指定对应的FXML文件路径@Autowired:自动注入依赖的服务层组件
5. FXML文件规范
- 文件位置:FXML文件通常位于
/client/src/main/resources/ui/目录下,按业务模块组织子目录 - 命名规范:使用小写字母和下划线,如
home.fxml、company/company.fxml - 关联方式:通过
@FxmlPath注解指定控制器对应的FXML文件路径 - 组件ID:FXML文件中组件的id应与控制器中对应的字段名保持一致(驼峰命名法)
6. 控制器方法规范
6.1 初始化方法
initialize():控制器初始化方法,用于设置UI组件初始状态、绑定事件监听器等- 此方法会在FXML加载完成后自动调用
6.2 窗口生命周期方法
onShown(WindowEvent windowEvent):窗口显示时触发的方法- 用于执行窗口显示后的初始化操作,如数据加载、组件状态更新等
- 通常需要调用
super.onShown(windowEvent)确保父类逻辑执行
6.3 窗口显示方法
public static void show():静态方法,用于便捷地显示控制器对应的窗口- 通常有多个重载版本,支持不同参数(如viewModel、owner窗口等)
- 内部调用
BaseController.show()方法实现窗口显示逻辑
6.4 Tab相关方法
Tab皮肤控制器包含以下核心方法:
install():安装Tab皮肤,加载FXML并初始化UI组件initializeUIComponents():初始化UI组件,设置数据绑定和事件监听getTab():获取对应的Tab对象save():保存Tab中的数据变更dispose():释放资源,清理监听器等
7. 字段规范
- UI组件字段:与FXML文件中的组件id对应,使用
public访问修饰符 - 服务依赖字段:使用
@Autowired注解注入,通常使用private访问修饰符 - ViewModel字段:通常作为控制器的核心数据模型,提供
getter/setter方法 - 命名规范:使用驼峰命名法,如
nameField、tabPane、saveBtn等
8. 数据绑定与更新
- ViewModel绑定:控制器通常通过ViewModel与实体数据进行绑定
- 异步数据加载:使用
CompletableFuture进行异步数据加载,避免阻塞UI线程 - UI更新:在JavaFX应用线程中更新UI组件,可使用
Platform.runLater()确保线程安全
9. 事件处理
- 按钮点击事件:通过
setOnAction()方法绑定事件处理器 - 表单字段变更:可通过JavaFX的属性绑定机制监听字段变更
- Tab切换事件:实现
onTabShown()方法处理Tab显示事件
10. 异常处理
- 使用
handleException()方法统一处理异常 - 异常信息通常会显示在状态栏并记录日志
- 异步操作中的异常应通过
exceptionally()或handle()方法捕获处理
11. 最佳实践
- 职责分离:控制器应专注于UI交互和数据展示,业务逻辑应委托给服务层
- 避免重复代码:利用抽象类和接口提取通用逻辑
- 资源管理:及时释放资源,避免内存泄漏
- 线程安全:确保在JavaFX应用线程中更新UI
- 代码可读性:添加适当的注释,遵循命名规范
12. 示例代码结构
@Lazy
@Scope("prototype")
@Component
@FxmlPath("/ui/[模块名]/[文件名].fxml")
public class [业务]WindowController extends AbstEntityController<[Vo类型], [ViewModel类型]> {
private static final Logger logger = LoggerFactory.getLogger([业务]WindowController.class);
@Autowired
private [业务]Service [业务]Service;
// UI组件字段
public BorderPane root;
public TabPane tabPane;
public TextField nameField;
// ...其他UI组件
public static void show([Vo类型] entity, Window window) {
show([ViewModel类型].from(entity), window);
}
public static void show([ViewModel类型] viewModel, Window window) {
BaseController.show([业务]WindowController.class, viewModel, window);
}
@Override
public void initialize() {
// 初始化UI组件和事件监听
}
@Override
public void onShown(WindowEvent windowEvent) {
super.onShown(windowEvent);
// 窗口显示后的逻辑
}
}
13. TableCell 工厂模式规范
13.1 工厂方法命名
- TableCell类应提供静态工厂方法
forTableColumn,用于创建单元格工厂 - 方法命名必须为
forTableColumn,保持一致性
13.2 工厂方法参数
- 工厂方法应接收服务层参数,如
BankService - 参数类型应与TableCell构造函数所需的服务类型一致
13.3 工厂方法返回类型
- 返回类型应为
Callback<javafx.scene.control.TableColumn<V, T>, javafx.scene.control.TableCell<V, T>> - 其中
V为ViewModel类型,T为单元格值类型
13.4 工厂方法实现
- 在工厂方法内部,创建并返回TableCell实例
- 使用泛型参数确保类型安全
13.5 使用方式
- 在设置表格列的单元格工厂时,应调用TableCell的静态工厂方法
- 避免直接使用
new TableCell<>(service)的方式创建实例
13.6 示例代码
/**
* 银行单元格
*/
@NoArgsConstructor
public class BankTableCell<T> extends AsyncUpdateTableCell<T, Integer, BankVo> {
/**
* 创建单元格工厂
*
* @param bankService 银行服务
* @return 单元格工厂
*/
public static <V> Callback<javafx.scene.control.TableColumn<V, Integer>, javafx.scene.control.TableCell<V, Integer>> forTableColumn(
BankService bankService) {
return param -> new BankTableCell<V>(bankService);
}
public BankTableCell(BankService service) {
setService(service);
}
@Override
protected BankService getServiceBean() {
return getBean(BankService.class);
}
}
13.7 使用示例
// 推荐方式:使用工厂方法
column.setCellFactory(BankTableCell.forTableColumn(getBankService()));
// 不推荐方式:直接实例化
// column.setCellFactory(param -> new BankTableCell<>(getBankService()));