Files
his/audit_field_best_practices.md

5.8 KiB
Raw Blame History

OpenHIS 系统审计字段填充最佳实践

概述

本文档介绍如何在 OpenHIS 系统中确保所有实体的审计字段create_by、create_time、update_by、update_time能够正确自动填充。

自动填充机制

1. 基础实体类

所有需要审计字段的实体类都应该继承自 HisBaseEntity

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 来自动填充审计字段:

@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

// 正确的做法
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. 验证安全上下文

确保在执行数据库操作时有有效的安全上下文:

@Service
public class PractitionerService {
    public void savePractitioner(Practitioner practitioner) {
        // 确保调用此方法时用户已登录
        // SecurityUtils.getLoginUser() 应该能返回有效的 LoginUser 对象
        
        // MyBatis-Plus 会在保存时自动调用 MybastisColumnsHandler
        practitionerMapper.insert(practitioner);
    }
}

3. 检查配置

确保自动填充处理器被正确配置:

# application.yml
mybatis-plus:
  global-config:
    db-config:
      # 其他配置...
  configuration:
    # 其他配置...

4. 手动填充(特殊情况)

在某些特殊情况下,如果自动填充不工作,可以手动设置:

@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 的批量操作方法,确保它们支持自动填充

测试验证

创建一个简单的测试来验证自动填充是否正常工作:

@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 系统中的所有实体在保存时都能正确填充审计字段,避免因缺少这些字段而引发的数据库约束错误。