feat(ai): 添加AI模型管理和分段上传功能

- 创建AI模型版本管理表tz_ai_model并添加相关索引
- 添加AiModelController、AiModelService等完整的模型管理接口
- 实现模型创建、更新、删除、分页查询等功能
- 添加模型状态更新功能支持启用禁用等状态变更
- 在S3FileClient中实现分段上传uploadMultipart方法
- 扩展FileApi接口增加createFileMultipart分段上传接口
- 修改Nacos配置将命名空间从dev改为具体ID值
- 在SecurityConfiguration中开放AI模型管理接口权限
This commit is contained in:
2026-02-27 11:01:44 +08:00
parent 0c051643d5
commit 29cdf6c581
20 changed files with 498 additions and 16 deletions

View File

@@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RestController;
import static com.tashow.cloud.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class FileApiImpl implements FileApi {
@@ -24,4 +25,11 @@ public class FileApiImpl implements FileApi {
createReqDTO.getContent()));
}
@Override
public CommonResult<String> createFileMultipart(FileCreateReqDTO createReqDTO) {
return success(fileService.createFileMultipart(createReqDTO.getName(), createReqDTO.getPath(),
createReqDTO.getContent()));
}
}

View File

@@ -11,10 +11,13 @@ import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.*;
import com.tashow.cloud.file.framework.file.core.client.AbstractFileClient;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
@@ -92,7 +95,32 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
objectMetadata);
// 拼接返回路径
return config.getDomain() + "/" + path;
return config.getDomain() + path;
}
/** 分段上传 */
public String uploadMultipart(byte[] content, String path, String type) throws Exception {
int partSize = 5 * 1024 * 1024;
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(type);
String uploadId = client.initiateMultipartUpload(new InitiateMultipartUploadRequest(config.getBucket(), path, metadata)).getUploadId();
try {
List<PartETag> partETags = new ArrayList<>();
for (int i = 0, partNum = 1; i < content.length; i += partSize, partNum++) {
int size = Math.min(partSize, content.length - i);
byte[] part = new byte[size];
System.arraycopy(content, i, part, 0, size);
UploadPartResult result = client.uploadPart(new UploadPartRequest()
.withBucketName(config.getBucket()).withKey(path).withUploadId(uploadId)
.withPartNumber(partNum).withInputStream(new ByteArrayInputStream(part)).withPartSize(size));
partETags.add(result.getPartETag());
}
client.completeMultipartUpload(new CompleteMultipartUploadRequest(config.getBucket(), path, uploadId, partETags));
return config.getDomain() + path;
} catch (Exception e) {
client.abortMultipartUpload(new AbortMultipartUploadRequest(config.getBucket(), path, uploadId));
throw e;
}
}
@Override

View File

@@ -31,6 +31,9 @@ public interface FileService {
*/
String createFile(String name, String path, byte[] content);
/** 分段上传文件 */
String createFileMultipart(String name, String path, byte[] content);
/**
* 创建文件
*

View File

@@ -12,6 +12,7 @@ import com.tashow.cloud.file.dal.dataobject.file.FileDO;
import com.tashow.cloud.file.dal.mysql.file.FileMapper;
import com.tashow.cloud.file.framework.file.core.client.FileClient;
import com.tashow.cloud.file.framework.file.core.client.s3.FilePresignedUrlRespDTO;
import com.tashow.cloud.file.framework.file.core.client.s3.S3FileClient;
import com.tashow.cloud.file.framework.file.core.utils.FileTypeUtils;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
@@ -70,6 +71,30 @@ public class FileServiceImpl implements FileService {
return url;
}
@Override
@SneakyThrows
public String createFileMultipart(String name, String path, byte[] content) {
String type = FileTypeUtils.getMineType(content, name);
if (StrUtil.isEmpty(path)) {
path = FileUtils.generatePath(content, name);
}
if (StrUtil.isEmpty(name)) {
name = path;
}
FileClient client = fileConfigService.getMasterFileClient();
Assert.notNull(client, "客户端(master) 不能为空");
String url = ((S3FileClient) client).uploadMultipart(content, path, type);
FileDO file = new FileDO();
file.setConfigId(client.getId());
file.setName(name);
file.setPath(path);
file.setUrl(url);
file.setType(type);
file.setSize(content.length);
fileMapper.insert(file);
return url;
}
@Override
public Long createFile(FileCreateReqVO createReqVO) {
FileDO file = BeanUtils.toBean(createReqVO, FileDO.class);

View File

@@ -7,13 +7,11 @@ spring:
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
namespace: 63caf548-313d-44bb-929c-531bf2f3b1a2 # 命名空间
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
metadata:
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
config: # 【注册中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
namespace: 63caf548-313d-44bb-929c-531bf2f3b1a2 # 命名空间
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP