1. 限制记录 api 日志的字段长度
2. 完整记录所有的 databus api 的请求日志 3. 新增 iwork 同步可以按 id 维度进行 4. 新增自动扫描 BusinessBaseDO 的 公司部门数据权限模式
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.zt.plat.framework.mybatis.core.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 标记业务实体对应表中的公司字段名称,默认 company_id。
|
||||
*
|
||||
* @author chenbow
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface CompanyColumn {
|
||||
|
||||
/**
|
||||
* 表中公司字段名称
|
||||
*/
|
||||
String value() default "company_id";
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.zt.plat.framework.mybatis.core.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 标记业务实体对应表中的部门字段名称,默认 dept_id。
|
||||
*
|
||||
* @author chenbow
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface DeptColumn {
|
||||
|
||||
/**
|
||||
* 表中部门字段名称
|
||||
*/
|
||||
String value() default "dept_id";
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package com.zt.plat.framework.mybatis.core.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.zt.plat.framework.mybatis.core.annotation.CompanyColumn;
|
||||
import com.zt.plat.framework.mybatis.core.annotation.DeptColumn;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
@@ -13,6 +15,8 @@ import java.util.List;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@CompanyColumn
|
||||
@DeptColumn
|
||||
public class BusinessBaseDO extends BaseDO {
|
||||
|
||||
/** 公司编号 */
|
||||
|
||||
Reference in New Issue
Block a user