chore: initialize qiming workspace repository
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-compose</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
</parent>
|
||||
|
||||
<artifactId>app-platform-compose-application</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-compose-infra</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-compose-domain</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.xspaceagi.compose.application.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
||||
import com.xspaceagi.compose.sdk.request.QueryDorisTableDefinePageRequest;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页查询doris表结构定义
|
||||
*/
|
||||
@Schema(description = "分页查询doris表结构定义")
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class QueryDorisTableDefinePageRequestVo {
|
||||
|
||||
/**
|
||||
* 空间ID
|
||||
*/
|
||||
@Schema(description = "空间ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonPropertyDescription("空间ID")
|
||||
private Long spaceId;
|
||||
|
||||
@Schema(description = "空间ID列表,查询用户有权限的空间,限制访问空间,比如工作流查询全部知识库,要限制用户有权限的空间下的知识库")
|
||||
private List<Long> authSpaceIds;
|
||||
|
||||
/**
|
||||
* 创建人ID列表
|
||||
*/
|
||||
@Schema(description = "创建人ID列表")
|
||||
private List<Long> creatorIds;
|
||||
|
||||
/**
|
||||
* 表名
|
||||
*/
|
||||
@Schema(description = "表名")
|
||||
private String tableName;
|
||||
|
||||
/**
|
||||
* 转换为QueryDorisTableDefinePageRequest
|
||||
*
|
||||
* @param request 查询请求
|
||||
* @return 查询请求
|
||||
*/
|
||||
public static QueryDorisTableDefinePageRequestVo convert(QueryDorisTableDefinePageRequest request) {
|
||||
return QueryDorisTableDefinePageRequestVo.builder()
|
||||
.spaceId(request.getSpaceId())
|
||||
.authSpaceIds(request.getAuthSpaceIds())
|
||||
.creatorIds(request.getCreatorIds())
|
||||
.tableName(request.getKw())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.xspaceagi.compose.application.service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.xspaceagi.compose.application.model.QueryDorisTableDefinePageRequestVo;
|
||||
import com.xspaceagi.compose.domain.dto.CustomAddBusinessRowDataVo;
|
||||
import com.xspaceagi.compose.domain.dto.CustomDeleteBusinessRowDataVo;
|
||||
import com.xspaceagi.compose.domain.dto.CustomEmptyTableVo;
|
||||
import com.xspaceagi.compose.domain.dto.CustomUpdateBusinessRowDataVo;
|
||||
import com.xspaceagi.compose.domain.model.CustomDorisDataRequest;
|
||||
import com.xspaceagi.compose.domain.model.CustomFieldDefinitionModel;
|
||||
import com.xspaceagi.compose.domain.model.CustomTableDefinitionModel;
|
||||
import com.xspaceagi.compose.sdk.DorisDataPage;
|
||||
import com.xspaceagi.compose.sdk.vo.define.CreateTableDefineVo;
|
||||
import com.xspaceagi.system.spec.common.UserContext;
|
||||
import com.xspaceagi.system.spec.page.PageQueryVo;
|
||||
import com.xspaceagi.system.spec.page.SuperPage;
|
||||
|
||||
/**
|
||||
* 自定义 数据表服务
|
||||
*/
|
||||
public interface CustomTableDefinitionApplicationService {
|
||||
|
||||
/**
|
||||
* 新增空表定义
|
||||
*
|
||||
* @param model
|
||||
* @param userContext
|
||||
* @return
|
||||
*/
|
||||
Long addInfo(CustomEmptyTableVo model, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 新增空表定义,不检查空间权限
|
||||
*
|
||||
* @param model
|
||||
* @param userContext
|
||||
* @return
|
||||
*/
|
||||
Long myAddInfoNoCheckSpace(CustomEmptyTableVo model, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 更新表定义
|
||||
*
|
||||
* @param model
|
||||
* @param userContext
|
||||
*/
|
||||
void updateInfo(Long tableId, List<CustomFieldDefinitionModel> fieldList, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 更新表定义,不检查空间权限
|
||||
*
|
||||
* @param tableId
|
||||
* @param fieldList
|
||||
* @param userContext
|
||||
*/
|
||||
void myUpdateInfoNoCheckSpace(Long tableId, List<CustomFieldDefinitionModel> fieldList, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 更新表名称
|
||||
*
|
||||
* @param model
|
||||
* @param userContext
|
||||
*/
|
||||
void updateTableName(CustomTableDefinitionModel model, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 查询表定义
|
||||
*
|
||||
* @param tableId 表定义ID
|
||||
* @return
|
||||
*/
|
||||
CustomTableDefinitionModel queryOneTableDefineVo(Long tableId);
|
||||
|
||||
/**
|
||||
* 删除表定义
|
||||
*
|
||||
* @param tableId
|
||||
* @param userContext
|
||||
*/
|
||||
void deleteById(Long tableId, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 查询doris表数据,分页查询;给前端使用的,分页查询
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
DorisDataPage<Map<String, Object>> queryPageDorisTableDataForWeb(CustomDorisDataRequest request);
|
||||
|
||||
/**
|
||||
* 根据表ID和行ID查询单行数据
|
||||
*
|
||||
* @param tableId 表ID
|
||||
* @param rowId 行数据ID
|
||||
* @return 行数据,如果不存在返回 null
|
||||
*/
|
||||
Map<String, Object> queryRowDataByTableIdAndRowId(Long tableId, Long rowId);
|
||||
|
||||
/**
|
||||
* 导出Doris表数据到Excel
|
||||
*
|
||||
* @param tableId 表定义ID
|
||||
* @param outputStream 输出流,用于写入Excel数据
|
||||
* @param userContext 用户上下文
|
||||
*/
|
||||
void exportTableDataToExcel(Long tableId, OutputStream outputStream, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 新增业务数据
|
||||
*
|
||||
* @param request
|
||||
* @param userContext
|
||||
*/
|
||||
void addBusinessData(CustomAddBusinessRowDataVo request, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 修改业务数据,行数修改
|
||||
*
|
||||
* @param request
|
||||
* @param userContext
|
||||
*/
|
||||
void updateBusinessData(CustomUpdateBusinessRowDataVo request, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 删除业务数据,行数删除
|
||||
*
|
||||
* @param request 删除请求对象(包含 tableId 和 rowId)
|
||||
* @param rowData 要删除的完整行数据(用于日志记录以便恢复)
|
||||
* @param userContext 用户上下文
|
||||
*/
|
||||
void deleteBusinessData(CustomDeleteBusinessRowDataVo request, Map<String, Object> rowData, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 清空业务数据
|
||||
*
|
||||
* @param tableId
|
||||
* @param userContext
|
||||
*/
|
||||
void clearBusinessData(Long tableId, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 分页查询表定义
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
SuperPage<CustomTableDefinitionModel> queryPageTableDefine(
|
||||
PageQueryVo<QueryDorisTableDefinePageRequestVo> pageQueryVo);
|
||||
|
||||
/**
|
||||
* 根据空间ID查询表定义
|
||||
*
|
||||
* @param spaceId
|
||||
* @return
|
||||
*/
|
||||
List<CustomTableDefinitionModel> queryTableDefineBySpaceId(Long spaceId);
|
||||
|
||||
/**
|
||||
* 查询是否存在业务数据
|
||||
*
|
||||
* @param tableId
|
||||
* @return
|
||||
*/
|
||||
Boolean existTableData(Long tableId);
|
||||
|
||||
/**
|
||||
* 复制表结构定义
|
||||
*
|
||||
* @param tableId
|
||||
* @param userContext
|
||||
* @return
|
||||
*/
|
||||
Long copyTableDefinition(Long tableId, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 导入业务表数据Excel
|
||||
*
|
||||
* @param tableId
|
||||
* @param file
|
||||
* @param userContext
|
||||
*/
|
||||
void importTableDataFromExcel(Long tableId, InputStream inputStream, UserContext userContext);
|
||||
|
||||
|
||||
/**
|
||||
* 创建表结构定义
|
||||
*
|
||||
* @param tableDefineVo 创建表结构定义
|
||||
* @return 数据表的创建成功的主键ID
|
||||
*/
|
||||
Long createTable(CreateTableDefineVo tableDefineVo);
|
||||
|
||||
/**
|
||||
* 根据操作日志的 extraContent 恢复被删除的业务数据
|
||||
*
|
||||
* @param extraContent 操作日志的 extraContent JSON 字符串
|
||||
* @param forceRestore 是否强制恢复(覆盖已存在的数据)
|
||||
* @param userContext 用户上下文
|
||||
* @return 恢复结果信息
|
||||
*/
|
||||
String restoreBusinessDataByExtraContent(String extraContent, Boolean forceRestore, UserContext userContext);
|
||||
|
||||
/**
|
||||
* 统计用户下所有表的数量
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户下所有表的数量
|
||||
*/
|
||||
Long countUserTotalTable(Long userId);
|
||||
}
|
||||
@@ -0,0 +1,696 @@
|
||||
package com.xspaceagi.compose.application.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.xspaceagi.agent.core.sdk.dto.AgentInfoDto;
|
||||
import com.xspaceagi.compose.adapter.IAgentRpcServiceAdapter;
|
||||
import com.xspaceagi.compose.application.model.QueryDorisTableDefinePageRequestVo;
|
||||
import com.xspaceagi.compose.application.service.CustomTableDefinitionApplicationService;
|
||||
import com.xspaceagi.compose.domain.dto.CustomAddBusinessRowDataVo;
|
||||
import com.xspaceagi.compose.domain.dto.CustomDeleteBusinessRowDataVo;
|
||||
import com.xspaceagi.compose.domain.dto.CustomEmptyTableVo;
|
||||
import com.xspaceagi.compose.domain.dto.CustomUpdateBusinessRowDataVo;
|
||||
import com.xspaceagi.compose.domain.model.CustomDorisDataRequest;
|
||||
import com.xspaceagi.compose.domain.model.CustomFieldDefinitionModel;
|
||||
import com.xspaceagi.compose.domain.model.CustomTableDefinitionModel;
|
||||
import com.xspaceagi.compose.domain.repository.ICustomTableDefinitionRepository;
|
||||
import com.xspaceagi.compose.domain.service.CustomDorisTableDomainService;
|
||||
import com.xspaceagi.compose.domain.service.CustomTableDefinitionDomainService;
|
||||
import com.xspaceagi.compose.domain.util.excel.ExcelUtils;
|
||||
import com.xspaceagi.compose.domain.util.excel.ReadExcelDataVo;
|
||||
import com.xspaceagi.compose.sdk.DorisDataPage;
|
||||
import com.xspaceagi.compose.sdk.enums.DefaultTableFieldEnum;
|
||||
import com.xspaceagi.compose.sdk.vo.define.CreateTableDefineVo;
|
||||
import com.xspaceagi.system.application.dto.UserDto;
|
||||
import com.xspaceagi.system.application.service.UserApplicationService;
|
||||
import com.xspaceagi.system.domain.log.LogPrint;
|
||||
import com.xspaceagi.system.domain.track.reporter.OperateLogExtraData;
|
||||
import com.xspaceagi.system.infra.service.QueryVoListDelegateService;
|
||||
import com.xspaceagi.system.sdk.operate.ActionType;
|
||||
import com.xspaceagi.system.sdk.operate.OperationLogReporter;
|
||||
import com.xspaceagi.system.sdk.operate.SystemEnum;
|
||||
import com.xspaceagi.system.sdk.permission.SpacePermissionService;
|
||||
import com.xspaceagi.system.sdk.server.IUserRpcService;
|
||||
import com.xspaceagi.system.spec.common.UserContext;
|
||||
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
|
||||
import com.xspaceagi.system.spec.exception.ComposeException;
|
||||
import com.xspaceagi.system.spec.page.PageQueryParamVo;
|
||||
import com.xspaceagi.system.spec.page.PageQueryVo;
|
||||
import com.xspaceagi.system.spec.page.SuperPage;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class CustomTableDefinitionApplicationServiceImpl implements CustomTableDefinitionApplicationService {
|
||||
|
||||
@Resource
|
||||
private CustomTableDefinitionDomainService customTableDefinitionDomainService;
|
||||
|
||||
@Resource
|
||||
private CustomDorisTableDomainService customDorisTableDomainService;
|
||||
|
||||
@Resource
|
||||
private ICustomTableDefinitionRepository customTableDefinitionRepository;
|
||||
|
||||
@Resource
|
||||
private SpacePermissionService spacePermissionService;
|
||||
|
||||
@Resource
|
||||
private QueryVoListDelegateService queryVoListDelegateService;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Resource
|
||||
private UserApplicationService userApplicationService;
|
||||
|
||||
/**
|
||||
* 智能体服务适配器
|
||||
*/
|
||||
@Resource
|
||||
private IAgentRpcServiceAdapter agentRpcServiceAdapter;
|
||||
|
||||
@Lazy
|
||||
@Resource
|
||||
private CustomTableDefinitionApplicationService self;
|
||||
|
||||
|
||||
@Resource
|
||||
private IUserRpcService userRpcService;
|
||||
|
||||
|
||||
@Override
|
||||
public Long addInfo(CustomEmptyTableVo model, UserContext userContext) {
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = model.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
return this.myAddInfoNoCheckSpace(model, userContext);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long myAddInfoNoCheckSpace(CustomEmptyTableVo model, UserContext userContext) {
|
||||
// 新增 表结构
|
||||
var tableId = customTableDefinitionDomainService.addInfo(model, userContext);
|
||||
|
||||
var tableModel = customTableDefinitionDomainService.queryOneTableInfoById(tableId);
|
||||
|
||||
// 新增 doris 表结构
|
||||
customDorisTableDomainService.createTable(tableModel);
|
||||
|
||||
return tableId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInfo(Long tableId, List<CustomFieldDefinitionModel> fieldList, UserContext userContext) {
|
||||
CustomTableDefinitionModel tableModel = customTableDefinitionDomainService.queryOneTableInfoById(tableId);
|
||||
if (Objects.isNull(tableModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
this.myUpdateInfoNoCheckSpace(tableId, fieldList, userContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void myUpdateInfoNoCheckSpace(Long tableId, List<CustomFieldDefinitionModel> fieldList,
|
||||
UserContext userContext) {
|
||||
CustomTableDefinitionModel tableModel = customTableDefinitionDomainService.queryOneTableInfoById(tableId);
|
||||
if (Objects.isNull(tableModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
var spaceId = tableModel.getSpaceId();
|
||||
|
||||
// 不全字段的 spaceId 等字段,从主表上获取补充,避免新增字段缺失
|
||||
fieldList.forEach(field -> {
|
||||
field.setSpaceId(spaceId);
|
||||
field.setTenantId(tableModel.getTenantId());
|
||||
field.setTableId(tableModel.getId());
|
||||
field.setCreatorId(userContext.getUserId());
|
||||
field.setCreatorName(userContext.getUserName());
|
||||
field.setModifiedId(userContext.getUserId());
|
||||
field.setModifiedName(userContext.getUserName());
|
||||
field.setModified(LocalDateTime.now());
|
||||
if (Objects.nonNull(field.getFieldName())) {
|
||||
//去掉两边空格
|
||||
field.setFieldName(field.getFieldName().trim());
|
||||
}
|
||||
|
||||
});
|
||||
// check fieldList 是否存在重复的 field_name,把所有重复字段列出来,提示给用户
|
||||
var fieldMap = fieldList.stream()
|
||||
.collect(Collectors.groupingBy(CustomFieldDefinitionModel::getFieldName));
|
||||
// 把重复的字段列出来,提示给用户
|
||||
var duplicateFieldList = fieldMap.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().size() > 1)
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.toList());
|
||||
if (!duplicateFieldList.isEmpty()) {
|
||||
var duplicateFieldNames = String.join(",", duplicateFieldList);
|
||||
log.info("Field [{}] already exists", duplicateFieldNames);
|
||||
throw ComposeException.build(BizExceptionCodeEnum.composeFieldAlreadyExists, duplicateFieldNames);
|
||||
}
|
||||
|
||||
customTableDefinitionDomainService.updateInfo(tableModel, fieldList, userContext);
|
||||
|
||||
// 修改 TableModel的最后更新时间
|
||||
customTableDefinitionDomainService.updateTableLastModified(tableId, userContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(Long tableId, UserContext userContext) {
|
||||
|
||||
CustomTableDefinitionModel tableModel = customTableDefinitionDomainService.queryOneTableInfoById(tableId);
|
||||
if (Objects.isNull(tableModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
// 2. 删除Doris表
|
||||
customDorisTableDomainService.dropTable(tableModel.getDorisDatabase(), tableModel.getDorisTable());
|
||||
|
||||
// 1. 删除表定义
|
||||
customTableDefinitionDomainService.deleteById(tableId, userContext);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportTableDataToExcel(Long tableId, OutputStream outputStream, UserContext userContext) {
|
||||
CustomTableDefinitionModel tableDefinitionModel = this.customTableDefinitionRepository
|
||||
.queryOneInfoById(tableId);
|
||||
if (Objects.isNull(tableDefinitionModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableDefinitionModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
customTableDefinitionDomainService.exportTableDataToExcel(tableId, outputStream, userContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DorisDataPage<Map<String, Object>> queryPageDorisTableDataForWeb(CustomDorisDataRequest request) {
|
||||
|
||||
var tableId = request.getTableId();
|
||||
CustomTableDefinitionModel tableDefinitionModel = this.customTableDefinitionRepository
|
||||
.queryOneInfoById(tableId);
|
||||
if (Objects.isNull(tableDefinitionModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableDefinitionModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
var data = customDorisTableDomainService.queryPageDorisTableDataForWeb(request, tableDefinitionModel);
|
||||
// 对 agent_name,nick_name,user_name
|
||||
// 字段,根据id,读取用户信息,以及智能体信息,替换中文名称,因为中文名称可能修改,所以需要根据id来读取
|
||||
// 查询所有的 uid 字段,即用户id
|
||||
List<String> uidFieldList = data.getRecords().stream()
|
||||
.map(record -> {
|
||||
var uid = record.get(DefaultTableFieldEnum.UID.getFieldName());
|
||||
return uid;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.map(item -> item.toString())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
var userList = this.userApplicationService.queryUserListByUids(uidFieldList);
|
||||
// 将 userList 转换为 map,key为id,value为user
|
||||
Map<String, UserDto> userMap = userList.stream()
|
||||
.collect(Collectors.toMap(UserDto::getUid, Function.identity()));
|
||||
|
||||
// 查询所有的 agent_id 字段,即智能体ID
|
||||
List<Long> agentIdFieldList = data.getRecords().stream()
|
||||
.map(record -> {
|
||||
var agentId = record.get(DefaultTableFieldEnum.AGENT_ID.getFieldName());
|
||||
return agentId;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.map(item -> {
|
||||
try {
|
||||
return Long.parseLong(item.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("agentId not Long, skip row: {}", item);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
// 等agent智能体提供sdk接口,读取智能体信息,补充智能体名称
|
||||
List<AgentInfoDto> agentListResult = agentRpcServiceAdapter.queryAgentInfoList(agentIdFieldList);
|
||||
// 将agentList转换为map,key为id,value为agent
|
||||
|
||||
Map<Long, AgentInfoDto> agentMap = agentListResult.stream()
|
||||
.collect(Collectors.toMap(AgentInfoDto::getId, Function.identity()));
|
||||
|
||||
// 补充用户名称:nick_name,user_name
|
||||
data.getRecords().forEach(record -> {
|
||||
var uid = record.get(DefaultTableFieldEnum.UID.getFieldName());
|
||||
if (Objects.nonNull(uid)) {
|
||||
var user = userMap.get(uid);
|
||||
// 使用optional来判断
|
||||
Optional.ofNullable(user).ifPresent(userDto -> {
|
||||
record.put(DefaultTableFieldEnum.NICK_NAME.getFieldName(), userDto.getNickName());
|
||||
record.put(DefaultTableFieldEnum.USER_NAME.getFieldName(), userDto.getUserName());
|
||||
});
|
||||
}
|
||||
var agentId = record.get(DefaultTableFieldEnum.AGENT_ID.getFieldName());
|
||||
if (Objects.nonNull(agentId)) {
|
||||
try {
|
||||
var agent = agentMap.get(Long.parseLong(agentId.toString()));
|
||||
Optional.ofNullable(agent).ifPresent(agentInfoDto -> {
|
||||
record.put(DefaultTableFieldEnum.AGENT_NAME.getFieldName(), agentInfoDto.getName());
|
||||
});
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("agentId not Long, skip agentName: {}", agentId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomTableDefinitionModel queryOneTableDefineVo(Long tableId) {
|
||||
CustomTableDefinitionModel tableInfo = customTableDefinitionDomainService.queryOneTableInfoById(tableId);
|
||||
if (Objects.isNull(tableInfo)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableInfo.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
// 获取表的DDL语句
|
||||
try {
|
||||
String createTableDdl = customTableDefinitionDomainService.getCreateTableDdl(tableId, tableInfo);
|
||||
// 设置原始建表DDL
|
||||
tableInfo.setCreateTableDdl(createTableDdl);
|
||||
} catch (Exception e) {
|
||||
log.error("Get table DDL failed, tableId: {}", tableId, e);
|
||||
}
|
||||
|
||||
return tableInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> queryRowDataByTableIdAndRowId(Long tableId, Long rowId) {
|
||||
// 1. 查询表定义
|
||||
CustomTableDefinitionModel tableDefinitionModel = this.customTableDefinitionRepository
|
||||
.queryOneInfoById(tableId);
|
||||
if (Objects.isNull(tableDefinitionModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound, "表定义不存在,tableId=" + tableId);
|
||||
}
|
||||
|
||||
// 2. 校验空间权限
|
||||
var spaceId = tableDefinitionModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
// 3. 构建查询条件
|
||||
Map<String, Object> conditions = new java.util.HashMap<>();
|
||||
conditions.put("id", rowId);
|
||||
|
||||
// 4. 查询单行数据
|
||||
List<Map<String, Object>> rowDataList = customDorisTableDomainService.queryAllTableData(
|
||||
tableDefinitionModel.getDorisDatabase(),
|
||||
tableDefinitionModel.getDorisTable(),
|
||||
conditions,
|
||||
null,
|
||||
1 // 只查询1条
|
||||
);
|
||||
|
||||
// 5. 返回结果
|
||||
if (CollectionUtils.isEmpty(rowDataList)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return rowDataList.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBusinessData(CustomAddBusinessRowDataVo request, UserContext userContext) {
|
||||
// 1. 查询表定义
|
||||
CustomTableDefinitionModel tableDefinitionModel = this.customTableDefinitionRepository
|
||||
.queryOneInfoById(request.getTableId());
|
||||
if (Objects.isNull(tableDefinitionModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableDefinitionModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
// 2. 新增业务数据
|
||||
customDorisTableDomainService.addBusinessData(request, tableDefinitionModel, userContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBusinessData(CustomUpdateBusinessRowDataVo request, UserContext userContext) {
|
||||
// 1. 查询表定义
|
||||
CustomTableDefinitionModel tableDefinitionModel = this.customTableDefinitionRepository
|
||||
.queryOneInfoById(request.getTableId());
|
||||
if (Objects.isNull(tableDefinitionModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableDefinitionModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
// 根据主键id,查询对应数据是否存在,如果存在,在进行根据主键id来更新
|
||||
var isExist = customDorisTableDomainService.queryDorisTableRowDataById(tableDefinitionModel.getDorisDatabase(),
|
||||
tableDefinitionModel.getDorisTable(), request.getRowId());
|
||||
// 如果不存在,则主动抛异常
|
||||
if (!isExist) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 2. 修改业务数据
|
||||
customDorisTableDomainService.updateBusinessData(request, tableDefinitionModel, userContext);
|
||||
}
|
||||
|
||||
@OperationLogReporter(
|
||||
actionType = ActionType.DELETE,
|
||||
action = "删除业务数据",
|
||||
objectName = "业务数据操作",
|
||||
systemCode = SystemEnum.DB_TABLE,
|
||||
spelExpression = "{'request': #request, 'rowData': #rowData}" // 记录删除请求和完整行数据
|
||||
)
|
||||
@LogPrint(step = "业务数据操作-删除业务数据")
|
||||
@Override
|
||||
public void deleteBusinessData(CustomDeleteBusinessRowDataVo request, Map<String, Object> rowData, UserContext userContext) {
|
||||
// 1. 查询表定义
|
||||
|
||||
CustomTableDefinitionModel tableDefinitionModel = this.customTableDefinitionRepository
|
||||
.queryOneInfoById(request.getTableId());
|
||||
if (Objects.isNull(tableDefinitionModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableDefinitionModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
// 根据主键id,查询对应数据是否存在,如果存在,在进行根据主键id来删除
|
||||
var isExist = customDorisTableDomainService.queryDorisTableRowDataById(tableDefinitionModel.getDorisDatabase(),
|
||||
tableDefinitionModel.getDorisTable(), request.getRowId());
|
||||
// 如果不存在,则主动抛异常
|
||||
if (!isExist) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
// 2. 删除业务数据
|
||||
customDorisTableDomainService.deleteBusinessData(request, tableDefinitionModel, userContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearBusinessData(Long tableId, UserContext userContext) {
|
||||
// 1. 查询表定义
|
||||
CustomTableDefinitionModel tableDefinitionModel = this.customTableDefinitionRepository
|
||||
.queryOneInfoById(tableId);
|
||||
if (Objects.isNull(tableDefinitionModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableDefinitionModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
// 2. 清空业务数据
|
||||
customDorisTableDomainService.clearBusinessData(tableId, tableDefinitionModel, userContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTableName(CustomTableDefinitionModel model, UserContext userContext) {
|
||||
// 1. 查询表定义
|
||||
CustomTableDefinitionModel tableDefinitionModel = this.customTableDefinitionRepository
|
||||
.queryOneInfoById(model.getId());
|
||||
if (Objects.isNull(tableDefinitionModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableDefinitionModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
// 2. 更新表名称
|
||||
customTableDefinitionDomainService.updateTableName(model, userContext);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuperPage<CustomTableDefinitionModel> queryPageTableDefine(
|
||||
PageQueryVo<QueryDorisTableDefinePageRequestVo> pageQueryVo) {
|
||||
|
||||
var filter = pageQueryVo.getQueryFilter();
|
||||
pageQueryVo.setQueryFilter(filter);
|
||||
|
||||
PageQueryParamVo pageQueryParamVo = new PageQueryParamVo(pageQueryVo);
|
||||
|
||||
SuperPage<CustomTableDefinitionModel> superPage = this.queryVoListDelegateService.queryVoList(
|
||||
this.customTableDefinitionRepository,
|
||||
pageQueryParamVo, null);
|
||||
|
||||
return superPage;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<CustomTableDefinitionModel> queryTableDefineBySpaceId(Long spaceId) {
|
||||
|
||||
var data = this.customTableDefinitionDomainService.queryTableDefineBySpaceId(spaceId);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean existTableData(Long tableId) {
|
||||
CustomTableDefinitionModel tableDefinitionModel = this.customTableDefinitionRepository
|
||||
.queryOneInfoById(tableId);
|
||||
if (Objects.isNull(tableDefinitionModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
return customDorisTableDomainService.existTableData(tableDefinitionModel.getDorisDatabase(),
|
||||
tableDefinitionModel.getDorisTable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long copyTableDefinition(Long tableId, UserContext userContext) {
|
||||
var tableModel = this.customTableDefinitionRepository.queryOneInfoById(tableId);
|
||||
if (tableModel == null) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.composeTableDefinitionNotFound);
|
||||
}
|
||||
// 校验用户和空间对应权限,校验用户查询表业务数据的权限,不能超出用户有权限的空间(spaceId)
|
||||
var spaceId = tableModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
// 复制表结构定义
|
||||
var newTableId = this.customTableDefinitionDomainService.copyTableDefinition(tableId, userContext);
|
||||
|
||||
// 创建doris库表,需要重新查询表定义
|
||||
var newTableModel = this.customTableDefinitionRepository.queryOneInfoById(newTableId);
|
||||
customDorisTableDomainService.createTable(newTableModel);
|
||||
|
||||
return newTableId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importTableDataFromExcel(Long tableId, InputStream inputStream, UserContext userContext) {
|
||||
// 1. 查询表定义
|
||||
CustomTableDefinitionModel tableDefinitionModel = this.customTableDefinitionRepository
|
||||
.queryOneInfoById(tableId);
|
||||
if (Objects.isNull(tableDefinitionModel)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound);
|
||||
}
|
||||
|
||||
// 校验用户和空间对应权限
|
||||
var spaceId = tableDefinitionModel.getSpaceId();
|
||||
spacePermissionService.checkSpaceUserPermission(spaceId);
|
||||
|
||||
// 2. 读取并解析Excel
|
||||
ReadExcelDataVo readExcelDataVo = ExcelUtils.readExcel(inputStream, tableDefinitionModel);
|
||||
List<Map<String, Object>> excelData = readExcelDataVo.getData();
|
||||
List<String> newFieldsToCreate = readExcelDataVo.getNewFieldsToCreate();
|
||||
|
||||
// 3. 如果有新字段,先创建字段,并获取更新后的表定义和字段映射
|
||||
if (!CollectionUtils.isEmpty(newFieldsToCreate)) {
|
||||
log.info("Detected {} new fields, auto-creating in domain...", newFieldsToCreate.size());
|
||||
var fieldCreationResult = customTableDefinitionDomainService.handleNewFieldsFromExcel(
|
||||
tableDefinitionModel, newFieldsToCreate, userContext);
|
||||
|
||||
tableDefinitionModel = fieldCreationResult.getUpdatedTableModel();
|
||||
ExcelUtils.remapExcelDataKeys(excelData, fieldCreationResult.getNewFieldMapping());
|
||||
log.info("New fields created; table def refreshed and data remapped.");
|
||||
}
|
||||
|
||||
// 4. 导入业务数据
|
||||
if (!CollectionUtils.isEmpty(excelData)) {
|
||||
//针对 excelData 表格数据,根据 userContext 的用户信息,插入 uid,user_name,nick_name 字段
|
||||
excelData.forEach(record -> {
|
||||
record.put(DefaultTableFieldEnum.UID.getFieldName(), userContext.getUid());
|
||||
record.put(DefaultTableFieldEnum.USER_NAME.getFieldName(), userContext.getUserName());
|
||||
record.put(DefaultTableFieldEnum.NICK_NAME.getFieldName(), userContext.getNickName());
|
||||
});
|
||||
customDorisTableDomainService.batchInsertData(tableDefinitionModel, excelData, userContext);
|
||||
} else {
|
||||
log.warn("No valid Excel rows, skip import, tableId: {}", tableId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createTable(CreateTableDefineVo tableDefineVo) {
|
||||
// 新增 表结构
|
||||
var userList = this.userRpcService.queryUserListByIds(Lists.newArrayList(tableDefineVo.getCreatorId()));
|
||||
var userContext = userList.stream()
|
||||
.findFirst()
|
||||
.orElse(UserContext.builder()
|
||||
.userId(tableDefineVo.getCreatorId())
|
||||
.userName("未知用户")
|
||||
.nickName("未知用户")
|
||||
.build());
|
||||
|
||||
var model = CustomEmptyTableVo.convertToVo(tableDefineVo);
|
||||
var tableId = this.self.myAddInfoNoCheckSpace(model, userContext);
|
||||
// 表字段,组装更新数据表定义 List<CustomFieldDefinitionModel>
|
||||
|
||||
// 组装表字段
|
||||
List<CustomFieldDefinitionModel> fieldList = tableDefineVo.getFieldList().stream()
|
||||
.map(CustomFieldDefinitionModel::convertToModelForCreate)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
this.self.myUpdateInfoNoCheckSpace(tableId, fieldList, userContext);
|
||||
return tableId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String restoreBusinessDataByExtraContent(String extraContent, Boolean forceRestore, UserContext userContext) {
|
||||
try {
|
||||
// 1. 解析 extraContent JSON
|
||||
if (!StringUtils.hasText(extraContent)) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound, "extraContent 不能为空");
|
||||
}
|
||||
|
||||
OperateLogExtraData extraData = JSON.parseObject(extraContent, OperateLogExtraData.class);
|
||||
if (extraData == null || extraData.getSpelData() == null) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound, "日志中没有记录删除的数据信息");
|
||||
}
|
||||
|
||||
// 2. 解析 spelData(包含 request 和 rowData)
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> spelDataMap = JSON.parseObject(
|
||||
JSON.toJSONString(extraData.getSpelData()),
|
||||
Map.class
|
||||
);
|
||||
|
||||
if (spelDataMap == null) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound, "无法解析日志中的 spelData");
|
||||
}
|
||||
|
||||
// 3. 提取 request 信息
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> requestMap = (Map<String, Object>) spelDataMap.get("request");
|
||||
if (requestMap == null) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound, "日志中缺少 request 信息");
|
||||
}
|
||||
|
||||
Object tableIdObj = requestMap.get("tableId");
|
||||
Object rowIdObj = requestMap.get("rowId");
|
||||
|
||||
if (tableIdObj == null || rowIdObj == null) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound, "日志中缺少 tableId 或 rowId");
|
||||
}
|
||||
|
||||
Long tableId = Long.valueOf(tableIdObj.toString());
|
||||
Long rowId = Long.valueOf(rowIdObj.toString());
|
||||
|
||||
// 4. 提取完整的行数据
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> rowData = (Map<String, Object>) spelDataMap.get("rowData");
|
||||
if (rowData == null || rowData.isEmpty()) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound, "日志中没有记录完整的行数据");
|
||||
}
|
||||
|
||||
log.info("Restore data start: tableId={}, rowId={}, forceRestore={}", tableId, rowId, forceRestore);
|
||||
|
||||
// 5. 查询表定义
|
||||
CustomTableDefinitionModel tableModel = this.customTableDefinitionRepository.queryOneInfoById(tableId);
|
||||
if (tableModel == null) {
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound, "表定义不存在,tableId=" + tableId);
|
||||
}
|
||||
|
||||
// 6. 校验空间权限
|
||||
spacePermissionService.checkSpaceUserPermission(tableModel.getSpaceId());
|
||||
|
||||
// 7. 检查数据是否已存在
|
||||
boolean dataExists = customDorisTableDomainService.queryDorisTableRowDataById(
|
||||
tableModel.getDorisDatabase(),
|
||||
tableModel.getDorisTable(),
|
||||
rowId
|
||||
);
|
||||
|
||||
if (dataExists) {
|
||||
if (!Boolean.TRUE.equals(forceRestore)) {
|
||||
return "数据已存在(rowId=" + rowId + "),如需覆盖请开启强制恢复";
|
||||
}
|
||||
// 强制恢复:先删除已存在的数据
|
||||
log.info("Force restore: delete existing row, rowId={}", rowId);
|
||||
customDorisTableDomainService.deleteDorisTableRowDataById(
|
||||
tableModel.getDorisDatabase(),
|
||||
tableModel.getDorisTable(),
|
||||
rowId
|
||||
);
|
||||
}
|
||||
|
||||
// 8. 准备恢复数据
|
||||
// 确保 rowData 中包含正确的 id
|
||||
rowData.put("id", rowId);
|
||||
|
||||
// 构建新增请求
|
||||
CustomAddBusinessRowDataVo addRequest = new CustomAddBusinessRowDataVo();
|
||||
addRequest.setTableId(tableId);
|
||||
addRequest.setRowData(rowData);
|
||||
|
||||
// 9. 执行数据恢复(本质上是重新插入)
|
||||
customDorisTableDomainService.addBusinessData(addRequest, tableModel, userContext);
|
||||
|
||||
log.info("Restore OK: tableId={}, rowId={}", tableId, rowId);
|
||||
return "数据恢复成功,rowId=" + rowId;
|
||||
|
||||
} catch (ComposeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to restore data", e);
|
||||
throw ComposeException.build(BizExceptionCodeEnum.resourceDataNotFound, "恢复数据失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countUserTotalTable(Long userId) {
|
||||
return customTableDefinitionRepository.countTotalTables(userId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user