refactor(ai): 重构AI

This commit is contained in:
Ray.Hao
2025-12-10 21:07:35 +08:00
parent 1b46b60b3f
commit f16c1e6227
12 changed files with 116 additions and 617 deletions

View File

@@ -13,6 +13,7 @@ import java.time.LocalDateTime;
* 基础实体类
*
* <p>实体类的基类,包含了实体类的公共属性,如创建时间、更新时间、逻辑删除标识等</p>
* <p>多租户模式下,会自动添加 tenant_id 字段(通过 MyMetaObjectHandler 自动填充)</p>
*
* @author Ray
* @since 2024/6/23
@@ -29,6 +30,26 @@ public class BaseEntity implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
/**
* 租户ID多租户模式
* <p>
* 注意:此字段仅在启用多租户时生效
* 通过 MyMetaObjectHandler 自动填充,无需手动设置
* 如果不需要多租户,可以通过配置 youlai.tenant.enabled=false 禁用
* </p>
* <p>
* 重要说明:
* 1. 默认使用 exist = false 标记字段不存在于数据库,避免单租户模式下报错
* 2. 在启用多租户时,需要确保数据库表中有 tenant_id 字段
* 3. 多租户的数据隔离主要通过 TenantLineHandler 自动添加 WHERE 条件实现
* 4. 如果需要在 INSERT 时写入 tenant_id请将 exist 改为 true 或移除 exist 属性
* 5. 或者执行 add_tenant_column.sql 脚本为表添加 tenant_id 字段
* </p>
*/
@TableField(value = "tenant_id", exist = false)
@JsonInclude(value = JsonInclude.Include.NON_NULL)
private Long tenantId;
/**
* 创建时间
*/

View File

@@ -5,11 +5,16 @@ import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.youlai.boot.config.property.TenantProperties;
import com.youlai.boot.plugin.mybatis.MyDataPermissionHandler;
import com.youlai.boot.plugin.mybatis.MyMetaObjectHandler;
import com.youlai.boot.plugin.mybatis.TenantLineHandler;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@@ -29,14 +34,30 @@ public class MybatisConfig {
@Value("${app.db-type:mysql}")
private String dbType;
@Autowired(required = false)
private TenantLineHandler tenantLineHandler;
@Autowired(required = false)
private TenantProperties tenantProperties;
/**
* 分页插件和数据权限插件
* <p>
* 如果启用了多租户,则添加多租户插件(必须在最前面)
* </p>
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 多租户插件(如果启用,必须在最前面)
if (tenantProperties != null && Boolean.TRUE.equals(tenantProperties.getEnabled()) && tenantLineHandler != null) {
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(tenantLineHandler));
}
// 数据权限
interceptor.addInnerInterceptor(new DataPermissionInterceptor(new MyDataPermissionHandler()));
// 分页插件,根据配置动态选择数据库类型
DbType mpDbType = DbType.MYSQL;
String type = dbType == null ? "mysql" : dbType.toLowerCase();

View File

@@ -23,3 +23,4 @@ public interface AiCommandLogMapper extends BaseMapper<AiCommandLog> {
IPage<AiCommandLogVO> getLogPage(Page<AiCommandLogVO> page, AiCommandPageQuery queryParams);
}

View File

@@ -79,3 +79,4 @@ public class AiCommandLog extends BaseEntity {
private String ipAddress;
}

View File

@@ -90,3 +90,4 @@ public class AiCommandLogVO implements Serializable {
private LocalDateTime updateTime;
}

View File

@@ -30,3 +30,4 @@ public interface AiCommandLogService extends IService<AiCommandLog> {
void rollbackCommand(String logId);
}

View File

@@ -47,3 +47,4 @@ public class AiCommandLogServiceImpl extends ServiceImpl<AiCommandLogMapper, AiC
}
}

View File

@@ -1,22 +1,33 @@
package com.youlai.boot.plugin.mybatis;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.youlai.boot.common.tenant.TenantContextHolder;
import com.youlai.boot.config.property.TenantProperties;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* mybatis-plus 字段自动填充
* <p>
* 支持自动填充创建时间、更新时间和租户ID
* </p>
*
* @author haoxr
* @since 2022/10/14
*/
@Component
@RequiredArgsConstructor
public class MyMetaObjectHandler implements MetaObjectHandler {
@Autowired(required = false)
private TenantProperties tenantProperties;
/**
* 新增填充创建时间
* 新增填充创建时间、更新时间和租户ID
*
* @param metaObject 元数据
*/
@@ -24,6 +35,27 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
// 如果启用了多租户自动填充租户ID
// 注意:由于 BaseEntity 中 tenantId 字段使用了 exist = false避免单租户模式报错
// 在启用多租户时,需要通过反射动态修改字段的 exist 属性,或者直接设置值
// 但 MyBatis-Plus 的字段映射是静态的,无法动态修改
// 因此,我们使用 strictInsertFill它会自动处理字段映射
// 如果字段不存在exist = falsestrictInsertFill 会跳过,不会报错
if (tenantProperties != null && Boolean.TRUE.equals(tenantProperties.getEnabled())) {
Long tenantId = TenantContextHolder.getTenantId();
if (tenantId != null) {
// 使用数据库字段名tenant_id进行填充
// 注意:由于 exist = false这个填充不会写入数据库
// 但多租户的数据隔离是通过 TenantLineHandler 自动添加 WHERE 条件实现的
// 所以这里只需要设置实体对象的属性值即可(用于业务逻辑)
String propertyName = "tenantId";
if (metaObject.hasGetter(propertyName)) {
// 直接设置值到实体对象,不依赖字段映射
metaObject.setValue(propertyName, tenantId);
}
}
}
}
/**