Files
contract-manager/.trae/rules/client_controller_rules.md
songqq c4eec0a9dd refactor(model): 重构模型类包结构并优化序列化处理
重构模型类包结构,将模型类按功能模块划分到不同的子包中。优化序列化处理,为VO类添加serialVersionUID并实现Serializable接口。移除部分冗余的serialVersionUID字段,简化模型类代码。同时修复UITools中空值处理的问题,并更新pom版本至0.0.100-SNAPSHOT。

- 将模型类按功能模块划分到ds子包中
- 为VO类添加序列化支持
- 移除冗余的serialVersionUID字段
- 修复UITools空值处理问题
- 更新项目版本号
2025-10-09 18:27:48 +08:00

6.5 KiB
Raw Blame History

客户端 Controller 类规则

1. 目录结构

客户端控制器位于client/src/main/java/com/ecep/contract/controller/目录下,按业务模块组织:

  • 根目录:包含基础控制器、抽象控制器和主窗口控制器
  • 业务子包:按业务领域组织,如company/project/contract/vendor/
  • tab/子包包含所有Tab皮肤控制器和相关接口、抽象类
  • table/子包:包含表格相关控制器和单元格实现

2. 命名规范

  • 基础控制器BaseController.java
  • 抽象控制器:以Abst开头,如AbstEntityController.javaAbstManagerWindowController.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>>:实体详情窗口控制器的抽象类
      • 具体业务窗口控制器,如CompanyWindowControllerProjectWindowController

Tab相关控制器继承关系

  • Skin:皮肤接口基础
    • TabSkinTab皮肤接口
      • AbstGenericTabSkin<C extends BaseController>通用Tab皮肤抽象类
        • AbstEntityBasedTabSkin<C extends AbstEntityController<T, V>, T extends IdentityEntity, V extends IdentityViewModel<T>>基于实体的Tab皮肤抽象类
          • 具体业务Tab皮肤控制器CompanyTabSkinBase.javaContractTabSkinFiles.java

4. 注解使用

客户端控制器类应使用以下注解:

  • @Component声明为Spring组件使其可被Spring容器管理
  • @Scope("prototype"):设置为原型作用域,确保每次请求创建新实例
  • @Lazy:延迟加载,提高应用启动性能
  • @FxmlPath("/ui/[业务模块]/[文件名].fxml")指定对应的FXML文件路径
  • @Autowired:自动注入依赖的服务层组件

5. FXML文件规范

  • 文件位置FXML文件通常位于/client/src/main/resources/ui/目录下,按业务模块组织子目录
  • 命名规范:使用小写字母和下划线,如home.fxmlcompany/company.fxml
  • 关联方式:通过@FxmlPath注解指定控制器对应的FXML文件路径
  • 组件IDFXML文件中组件的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方法
  • 命名规范:使用驼峰命名法,如nameFieldtabPanesaveBtn

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);
        // 窗口显示后的逻辑
    }
}