feat(core): 完善自动填充机制和时间格式化处理

- 替换 ServiceImpl 继承为 BaseService 以支持自动填充功能
- 在 HisBaseEntity 中添加 JsonFormat 注解统一时间格式化
- 重构 MybastisColumnsHandler 实现完整的自动填充逻辑,包括 createTime、updateTime、createBy、updateBy 和 tenantId 字段
- 添加详细的日志记录和异常处理机制
- 在 PractitionerAppServiceImpl 中增强租户ID和审计字段的设置逻辑
- 优化时间解析工具类 openhis.js 以正确处理 ISO 8601 格式时间字符串
- 更新数据库映射文件以支持下划线字段名映射
- 重构 SysUserServiceImpl 实现完整的审计字段自动填充机制
This commit is contained in:
2026-01-25 23:13:04 +08:00
parent ca043de624
commit ffce6f81c3
12 changed files with 372 additions and 158 deletions

View File

@@ -2,6 +2,7 @@ package com.core.framework.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
@@ -9,7 +10,9 @@ import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInt
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.core.common.utils.SecurityUtils;
import com.core.framework.handler.MybastisColumnsHandler;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.apache.ibatis.session.SqlSessionFactory;
@@ -165,7 +168,8 @@ public class MybatisPlusConfig {
@Primary
public SqlSessionFactory sqlSessionFactory(
@Qualifier("dynamicDataSource") DataSource dataSource,
MybatisPlusInterceptor mybatisPlusInterceptor) throws Exception {
MybatisPlusInterceptor mybatisPlusInterceptor,
MetaObjectHandler metaObjectHandler) throws Exception { // 注入 MetaObjectHandler
MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
// 设置 mapper 文件位置
@@ -173,7 +177,7 @@ public class MybatisPlusConfig {
.getResources("classpath*:mapper/**/*Mapper.xml"));
// 设置 typeAliases 包路径
sessionFactory.setTypeAliasesPackage("com.core.**.domain,com.openhis.**.domain");
// 配置 MyBatis-Plus
MybatisConfiguration configuration = new MybatisConfiguration();
// 使用驼峰命名法转换字段
@@ -187,10 +191,23 @@ public class MybatisPlusConfig {
// 配置日志实现
configuration.setLogImpl(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);
sessionFactory.setConfiguration(configuration);
// 设置 MyBatis-Plus 的全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setMetaObjectHandler(metaObjectHandler);
sessionFactory.setGlobalConfig(globalConfig);
// 设置拦截器(通过参数注入避免循环依赖)
sessionFactory.setPlugins(mybatisPlusInterceptor);
return sessionFactory.getObject();
}
/**
* 注册自动填充处理器
*/
@Bean
public MetaObjectHandler metaObjectHandler() {
return new MybastisColumnsHandler();
}
}

View File

@@ -5,6 +5,8 @@ import com.core.common.core.domain.model.LoginUser;
import com.core.common.utils.SecurityUtils;
import com.core.framework.config.TenantContext;
import org.apache.ibatis.reflection.MetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@@ -12,38 +14,97 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* MyBatis-Plus 自动填充处理器
* 用于自动填充创建时间和更新时间,以及创建人和更新人
*/
@Component
public class MybastisColumnsHandler implements MetaObjectHandler {
// 设置数据新增时候的,字段自动赋值规则
private static final Logger logger = LoggerFactory.getLogger(MybastisColumnsHandler.class);
// 设置数据新增时的字段自动赋值规则
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
String username = "system";
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
username = loginUser.getUsername();
}
} catch (Exception ignored) {
}
logger.info("开始执行 insertFill 自动填充");
// 填充创建时间
Date currentTime = new Date();
this.strictInsertFill(metaObject, "createTime", Date.class, currentTime);
this.strictInsertFill(metaObject, "create_time", Date.class, currentTime);
logger.debug("已填充创建时间: {}", currentTime);
// 获取当前登录用户名
String username = getCurrentUsername();
logger.debug("获取到当前用户名: {}", username);
// 填充创建人
this.strictInsertFill(metaObject, "createBy", String.class, username);
this.strictInsertFill(metaObject, "tenantId", Integer.class, getCurrentTenantId());
this.strictInsertFill(metaObject, "create_by", String.class, username);
logger.debug("已填充创建人: {}", username);
// 确保tenantId被设置
Integer tenantId = getCurrentTenantId();
if (tenantId == null) {
throw new RuntimeException("无法获取当前租户ID请确保用户已登录或正确设置租户上下文");
}
this.strictInsertFill(metaObject, "tenantId", Integer.class, tenantId);
this.strictInsertFill(metaObject, "tenant_id", Integer.class, tenantId);
logger.debug("已填充租户ID: {}", tenantId);
logger.info("insertFill 自动填充完成");
}
// 设置数据修改update时候的字段自动赋值规则
// 设置数据修改时的字段自动赋值规则
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
String username = "system";
logger.info("开始执行 updateFill 自动填充");
// 填充更新时间
Date currentTime = new Date();
this.strictUpdateFill(metaObject, "updateTime", Date.class, currentTime);
this.strictUpdateFill(metaObject, "update_time", Date.class, currentTime);
logger.debug("已填充更新时间: {}", currentTime);
// 填充更新人
String username = getCurrentUsername();
logger.debug("获取到当前用户名: {}", username);
this.strictUpdateFill(metaObject, "updateBy", String.class, username);
this.strictUpdateFill(metaObject, "update_by", String.class, username);
logger.debug("已填充更新人: {}", username);
logger.info("updateFill 自动填充完成");
}
/**
* 获取当前登录用户名
* @return 当前登录用户名,如果无法获取则返回 "system"
*/
private String getCurrentUsername() {
String username = "system"; // 默认值
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
username = loginUser.getUsername();
logger.debug("从SecurityContext获取到用户名: {}", username);
} else {
logger.warn("SecurityContext中没有找到登录用户信息");
// 尝试从请求中获取用户信息
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
// 可以在这里添加额外的逻辑来从请求中获取用户信息
// 例如从请求头、session等获取用户信息
}
}
} catch (Exception ignored) {
} catch (Exception e) {
// 记录异常但不中断处理流程
logger.error("获取当前登录用户时发生异常: ", e);
}
this.strictUpdateFill(metaObject, "updateBy", String.class, username);
return username;
}
/**
@@ -60,10 +121,14 @@ public class MybastisColumnsHandler implements MetaObjectHandler {
// 获取当前登录用户的租户ID优先使用SecurityUtils中储存的LoginUser的租户ID
try {
if (SecurityUtils.getAuthentication() != null) {
result = SecurityUtils.getLoginUser().getTenantId();
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
result = loginUser.getTenantId();
}
}
} catch (Exception e) {
result = 1; // 默认租户ID
// 记录异常但不中断处理
logger.error("获取当前登录用户租户ID时发生异常: ", e);
}
if (result == null) {
@@ -71,19 +136,31 @@ public class MybastisColumnsHandler implements MetaObjectHandler {
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
// 从请求头获取租户ID假设header名称为"X-Tenant-ID" ; 登录接口前端把租户id放到请求头里
String tenantIdHeader = request.getHeader("X-Tenant-ID");
String requestMethodName = request.getHeader("Request-Method-Name");
// 登录
if ("login".equals(requestMethodName)) {
if (tenantIdHeader != null && !tenantIdHeader.isEmpty()) {
result = Integer.parseInt(tenantIdHeader);
if (request != null) {
// 从请求头获取租户ID假设header名称为"X-Tenant-ID" ; 登录接口前端把租户id放到请求头里
String tenantIdHeader = request.getHeader("X-Tenant-ID");
String requestMethodName = request.getHeader("Request-Method-Name");
// 登录
if ("login".equals(requestMethodName)) {
if (tenantIdHeader != null && !tenantIdHeader.isEmpty()) {
try {
result = Integer.parseInt(tenantIdHeader);
} catch (NumberFormatException e) {
logger.error("解析请求头中的租户ID时发生异常: ", e);
}
}
}
}
}
}
}
return result != null ? result : 1; // 默认租户ID
// 如果仍然没有获取到租户ID返回默认值
if (result == null) {
logger.warn("未能获取当前租户ID将使用默认租户ID 1");
result = 1; // 默认租户ID
}
return result;
}
}