92 lines
3.8 KiB
Java
92 lines
3.8 KiB
Java
package tech.easyflow.starter;
|
|
|
|
import com.mybatisflex.core.FlexGlobalConfig;
|
|
import com.mybatisflex.core.audit.AuditMessage;
|
|
import com.mybatisflex.core.audit.AuditManager;
|
|
import com.mybatisflex.core.tenant.TenantManager;
|
|
import com.mybatisflex.spring.boot.MyBatisFlexCustomizer;
|
|
import cn.dev33.satoken.stp.StpUtil;
|
|
import cn.dev33.satoken.exception.NotWebContextException;
|
|
import cn.dev33.satoken.exception.SaTokenContextException;
|
|
import cn.dev33.satoken.context.SaHolder;
|
|
import java.math.BigInteger;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.context.annotation.Configuration;
|
|
import tech.easyflow.common.entity.LoginAccount;
|
|
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
|
import tech.easyflow.job.execution.SysJobExecutionContextHolder;
|
|
|
|
@Configuration
|
|
public class MybatisConfig implements MyBatisFlexCustomizer {
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(MybatisConfig.class);
|
|
private static final int MAX_AUDIT_SQL_LENGTH = 2_000;
|
|
|
|
@Value("${easyflow.mybatis.sql-audit-enabled:false}")
|
|
private boolean sqlAuditEnabled;
|
|
|
|
@Override
|
|
public void customize(FlexGlobalConfig flexGlobalConfig) {
|
|
// SQL 审计会同步格式化并输出每条语句,高频 Worker 轮询下必须显式开启。
|
|
AuditManager.setAuditEnable(sqlAuditEnabled);
|
|
|
|
// 统一使用标准 0/1 逻辑删除语义。
|
|
flexGlobalConfig.setNormalValueOfLogicDelete(0);
|
|
flexGlobalConfig.setDeletedValueOfLogicDelete(1);
|
|
|
|
// 登录请求自动追加 tenant_id 条件;系统任务没有登录上下文时保持显式全局语义。
|
|
TenantManager.setTenantFactory(this::currentTenantIds);
|
|
|
|
//取消控制台的 Banner 打印
|
|
flexGlobalConfig.setPrintBanner(false);
|
|
|
|
if (sqlAuditEnabled) {
|
|
AuditManager.setMessageCollector(MybatisConfig::collectSafeAuditMessage);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 审计日志只记录参数化 SQL 模板,绝不读取 AuditMessage 中的参数或完整 SQL。
|
|
*/
|
|
private static void collectSafeAuditMessage(AuditMessage message) {
|
|
log.info("SQL audit: statement={}, elapsedMs={}, rows={}, sql={}",
|
|
message.getStmtId(), message.getElapsedTime(), message.getQueryCount(),
|
|
compactSqlTemplate(message.getQuery()));
|
|
}
|
|
|
|
private static String compactSqlTemplate(String sql) {
|
|
if (sql == null) return null;
|
|
String compact = sql.replaceAll("\\s+", " ").trim();
|
|
return compact.length() <= MAX_AUDIT_SQL_LENGTH
|
|
? compact : compact.substring(0, MAX_AUDIT_SQL_LENGTH) + "...";
|
|
}
|
|
|
|
/**
|
|
* 返回当前请求的租户条件;启动与调度线程没有 Sa-Token 上下文时保留系统级查询语义。
|
|
*
|
|
* @return 当前租户 ID 数组;没有请求登录上下文时返回 {@code null}
|
|
*/
|
|
private Object[] currentTenantIds() {
|
|
BigInteger scheduledTenantId = SysJobExecutionContextHolder.current()
|
|
.map(context -> context.tenantId())
|
|
.orElse(null);
|
|
if (scheduledTenantId != null) {
|
|
return new Object[]{scheduledTenantId};
|
|
}
|
|
try {
|
|
if (!SaHolder.getContext().isValid() || !StpUtil.isLogin()) {
|
|
return null;
|
|
}
|
|
LoginAccount account = SaTokenUtil.getLoginAccount();
|
|
BigInteger tenantId = account == null || account.getTenantId() == null
|
|
? BigInteger.ZERO : account.getTenantId();
|
|
return new Object[]{tenantId};
|
|
} catch (NotWebContextException | SaTokenContextException ignored) {
|
|
// Bean 初始化与调度线程没有 Web 上下文,必须允许显式系统任务读取全局状态。
|
|
return null;
|
|
}
|
|
}
|
|
}
|