1. 限制记录 api 日志的字段长度

2. 完整记录所有的 databus api 的请求日志
3. 新增 iwork 同步可以按 id 维度进行
4. 新增自动扫描 BusinessBaseDO 的 公司部门数据权限模式
This commit is contained in:
chenbowen
2025-12-01 17:46:42 +08:00
parent e9542acd27
commit 95d905e76f
15 changed files with 606 additions and 66 deletions

View File

@@ -36,6 +36,11 @@
<artifactId>zt-spring-boot-starter-biz-tenant</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.zt.plat</groupId>
<artifactId>zt-spring-boot-starter-mybatis</artifactId>
<version>${revision}</version>
</dependency>
<!-- Test 测试相关 -->
<dependency>
<groupId>com.zt.plat</groupId>

View File

@@ -2,27 +2,54 @@ package com.zt.plat.framework.business.framework;
import com.zt.plat.framework.datapermission.core.rule.company.CompanyDataPermissionRuleCustomizer;
import com.zt.plat.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* @author chenbowen
* 自动为继承 BusinessBaseDO 的实体注册公司/部门数据权限字段。
*/
@Configuration(proxyBeanMethods = false)
public class BusinessDataPermissionConfiguration {
@Bean
public CompanyDataPermissionRuleCustomizer sysCompanyDataPermissionRuleCustomizer() {
return rule -> {
// companyId
rule.addCompanyColumn("demo_contract", "company_id");
};
public BusinessDataPermissionEntityScanner businessDataPermissionEntityScanner(BeanFactory beanFactory, ApplicationContext applicationContext) {
Set<String> basePackages = new LinkedHashSet<>();
if (AutoConfigurationPackages.has(beanFactory)) {
basePackages.addAll(AutoConfigurationPackages.get(beanFactory));
}
if (basePackages.isEmpty()) {
basePackages.add("com.zt");
}
ClassLoader classLoader = applicationContext != null
? applicationContext.getClassLoader()
: Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = BusinessDataPermissionConfiguration.class.getClassLoader();
}
return new BusinessDataPermissionEntityScanner(basePackages, classLoader);
}
@Bean
public DeptDataPermissionRuleCustomizer businessDeptDataPermissionRuleCustomizer() {
return rule -> {
// dept
rule.addDeptColumn("demo_contract", "dept_id");
};
public CompanyDataPermissionRuleCustomizer autoCompanyDataPermissionRuleCustomizer(BusinessDataPermissionEntityScanner scanner) {
return rule -> scanner.getEntityMetadata().forEach(metadata -> {
if (metadata.hasCompanyColumn()) {
rule.addCompanyColumn(metadata.getTableName(), metadata.getCompanyColumn());
}
});
}
@Bean
public DeptDataPermissionRuleCustomizer autoDeptDataPermissionRuleCustomizer(BusinessDataPermissionEntityScanner scanner) {
return rule -> scanner.getEntityMetadata().forEach(metadata -> {
if (metadata.hasDeptColumn()) {
rule.addDeptColumn(metadata.getTableName(), metadata.getDeptColumn());
}
});
}
}

View File

@@ -0,0 +1,159 @@
package com.zt.plat.framework.business.framework;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.zt.plat.framework.mybatis.core.annotation.CompanyColumn;
import com.zt.plat.framework.mybatis.core.annotation.DeptColumn;
import com.zt.plat.framework.mybatis.core.dataobject.BusinessBaseDO;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Modifier;
import java.util.*;
/**
* 扫描继承 {@link BusinessBaseDO} 的实体,自动提取公司/部门字段用于数据权限注册。
*
* @author chenbow
*/
@Slf4j
public class BusinessDataPermissionEntityScanner {
private final Set<String> basePackages;
private final ClassLoader classLoader;
private volatile List<EntityMetadata> cachedEntities;
public BusinessDataPermissionEntityScanner(Collection<String> basePackages, ClassLoader classLoader) {
Set<String> packages = new LinkedHashSet<>();
if (!CollectionUtils.isEmpty(basePackages)) {
packages.addAll(basePackages);
}
if (packages.isEmpty()) {
packages.add("com.zt");
}
this.basePackages = Collections.unmodifiableSet(packages);
this.classLoader = classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader();
}
public List<EntityMetadata> getEntityMetadata() {
List<EntityMetadata> result = cachedEntities;
if (result == null) {
synchronized (this) {
result = cachedEntities;
if (result == null) {
result = Collections.unmodifiableList(scanEntities());
cachedEntities = result;
}
}
}
return result;
}
private List<EntityMetadata> scanEntities() {
Map<String, EntityMetadata> metadataMap = new LinkedHashMap<>();
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AssignableTypeFilter(BusinessBaseDO.class));
for (String basePackage : basePackages) {
for (BeanDefinition beanDefinition : scanner.findCandidateComponents(basePackage)) {
String className = beanDefinition.getBeanClassName();
if (!StringUtils.hasText(className)) {
continue;
}
try {
Class<?> clazz = ClassUtils.forName(className, classLoader);
if (clazz == BusinessBaseDO.class || !BusinessBaseDO.class.isAssignableFrom(clazz)) {
continue;
}
if (Modifier.isAbstract(clazz.getModifiers())) {
continue;
}
@SuppressWarnings("unchecked")
Class<? extends BusinessBaseDO> entityClass = (Class<? extends BusinessBaseDO>) clazz;
EntityMetadata metadata = buildMetadata(entityClass);
if (metadata != null && StringUtils.hasText(metadata.getTableName())) {
metadataMap.putIfAbsent(metadata.getTableName(), metadata);
}
} catch (ClassNotFoundException ex) {
log.warn("[scanEntities][无法加载类 {}]", className, ex);
}
}
}
return new ArrayList<>(metadataMap.values());
}
private EntityMetadata buildMetadata(Class<? extends BusinessBaseDO> entityClass) {
String tableName = resolveTableName(entityClass);
if (!StringUtils.hasText(tableName)) {
log.debug("[buildMetadata][实体 {} 缺少表名配置,跳过自动注册]", entityClass.getName());
return null;
}
String companyColumn = resolveCompanyColumn(entityClass);
String deptColumn = resolveDeptColumn(entityClass);
if (!StringUtils.hasText(companyColumn) && !StringUtils.hasText(deptColumn)) {
log.debug("[buildMetadata][实体 {} 未配置公司/部门字段,跳过]", entityClass.getName());
return null;
}
return new EntityMetadata(tableName, companyColumn, deptColumn);
}
private String resolveTableName(Class<?> entityClass) {
TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
if (tableInfo != null && StringUtils.hasText(tableInfo.getTableName())) {
return tableInfo.getTableName();
}
TableName tableName = AnnotatedElementUtils.findMergedAnnotation(entityClass, TableName.class);
if (StringUtils.hasText(tableName.value())) {
return tableName.value();
}
// 退化为根据类名猜测(驼峰转下划线)
String fallback = com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(entityClass.getSimpleName());
return StringUtils.hasText(fallback) ? fallback : null;
}
private String resolveCompanyColumn(Class<?> entityClass) {
CompanyColumn annotation = AnnotatedElementUtils.findMergedAnnotation(entityClass, CompanyColumn.class);
return annotation.value();
}
private String resolveDeptColumn(Class<?> entityClass) {
DeptColumn annotation = AnnotatedElementUtils.findMergedAnnotation(entityClass, DeptColumn.class);
return annotation.value();
}
@Getter
@RequiredArgsConstructor
public static class EntityMetadata {
private final String tableName;
private final String companyColumn;
private final String deptColumn;
public boolean hasCompanyColumn() {
return StringUtils.hasText(companyColumn);
}
public boolean hasDeptColumn() {
return StringUtils.hasText(deptColumn);
}
@Override
public String toString() {
return "EntityMetadata{" +
"table='" + tableName + '\'' +
", company='" + companyColumn + '\'' +
", dept='" + deptColumn + '\'' +
'}';
}
}
}