# OpenHIS 系统审计字段填充最佳实践 ## 概述 本文档介绍如何在 OpenHIS 系统中确保所有实体的审计字段(create_by、create_time、update_by、update_time)能够正确自动填充。 ## 自动填充机制 ### 1. 基础实体类 所有需要审计字段的实体类都应该继承自 `HisBaseEntity`: ```java import com.core.common.core.domain.HisBaseEntity; @Data @TableName("adm_practitioner") public class Practitioner extends HisBaseEntity { @TableId(type = IdType.AUTO) private Long id; private String name; // 其他业务字段... } ``` ### 2. 自动填充处理器 系统使用 `MybastisColumnsHandler` 来自动填充审计字段: ```java @Component public class MybastisColumnsHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { // 填充创建时间和创建人 this.strictInsertFill(metaObject, "createTime", Date.class, new Date()); this.strictInsertFill(metaObject, "create_time", Date.class, new Date()); String username = getCurrentUsername(); // 获取当前用户名 this.strictInsertFill(metaObject, "createBy", String.class, username); this.strictInsertFill(metaObject, "create_by", String.class, username); } @Override public void updateFill(MetaObject metaObject) { // 填充更新时间和更新人 this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); this.strictUpdateFill(metaObject, "update_time", Date.class, new Date()); String username = getCurrentUsername(); // 获取当前用户名 this.strictUpdateFill(metaObject, "updateBy", String.class, username); this.strictUpdateFill(metaObject, "update_by", String.class, username); } private String getCurrentUsername() { String username = "system"; try { LoginUser loginUser = SecurityUtils.getLoginUser(); if (loginUser != null) { username = loginUser.getUsername(); } } catch (Exception ignored) { } return username; } } ``` ## 确保自动填充正常工作的要点 ### 1. 检查实体类继承关系 确保所有实体类都正确继承了 `HisBaseEntity`: ```java // 正确的做法 public class Practitioner extends HisBaseEntity { ... } // 如果不能继承 HisBaseEntity,则需要手动添加审计字段 public class CustomEntity { @TableField(fill = FieldFill.INSERT) private String createBy; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.UPDATE) private String updateBy; @TableField(fill = FieldFill.UPDATE) private Date updateTime; } ``` ### 2. 验证安全上下文 确保在执行数据库操作时有有效的安全上下文: ```java @Service public class PractitionerService { public void savePractitioner(Practitioner practitioner) { // 确保调用此方法时用户已登录 // SecurityUtils.getLoginUser() 应该能返回有效的 LoginUser 对象 // MyBatis-Plus 会在保存时自动调用 MybastisColumnsHandler practitionerMapper.insert(practitioner); } } ``` ### 3. 检查配置 确保自动填充处理器被正确配置: ```yaml # application.yml mybatis-plus: global-config: db-config: # 其他配置... configuration: # 其他配置... ``` ### 4. 手动填充(特殊情况) 在某些特殊情况下,如果自动填充不工作,可以手动设置: ```java @Service public class PractitionerService { public void savePractitionerManually(Practitioner practitioner) { // 手动设置审计字段 Date now = new Date(); String currentUser = getCurrentUsername(); practitioner.setCreateTime(now); practitioner.setCreateBy(currentUser); practitioner.setUpdateTime(now); practitioner.setUpdateBy(currentUser); practitionerMapper.insert(practitioner); } } ``` ## 常见问题及解决方案 ### 问题1:自动填充不生效 **原因:** - 实体类没有继承 `HisBaseEntity` - `MybastisColumnsHandler` 没有被Spring管理(缺少@Component注解) - 没有有效的安全上下文 **解决方案:** - 确保实体类继承 `HisBaseEntity` - 检查 `MybastisColumnsHandler` 是否有 `@Component` 注解 - 确保在调用保存方法时用户已登录 ### 问题2:获取不到当前用户 **原因:** - 用户未登录 - 安全上下文配置错误 **解决方案:** - 在调用保存方法前确保用户已登录 - 检查安全配置是否正确 ### 问题3:批量操作时审计字段未填充 **原因:** - 批量操作可能绕过了自动填充机制 **解决方案:** - 对于批量操作,手动设置审计字段 - 或者使用 MyBatis-Plus 的批量操作方法,确保它们支持自动填充 ## 测试验证 创建一个简单的测试来验证自动填充是否正常工作: ```java @SpringBootTest public class AuditFieldTest { @Autowired private PractitionerMapper practitionerMapper; @Test public void testAuditFieldsAutoFill() { Practitioner practitioner = new Practitioner(); practitioner.setName("Test Practitioner"); // 保存实体 practitionerMapper.insert(practitioner); // 验证审计字段是否被正确填充 assertThat(practitioner.getCreateBy()).isNotNull(); assertThat(practitioner.getCreateTime()).isNotNull(); // 清理测试数据 practitionerMapper.deleteById(practitioner.getId()); } } ``` ## 总结 通过遵循以上最佳实践,可以确保 OpenHIS 系统中的所有实体在保存时都能正确填充审计字段,避免因缺少这些字段而引发的数据库约束错误。