密钥模块修改测试完毕

This commit is contained in:
唐潇凯 2025-06-04 14:40:30 +08:00
parent 30c201a230
commit a238538106
12 changed files with 173 additions and 254 deletions

View File

@ -57,6 +57,13 @@
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version> <version>2.3.0</version>
</dependency> </dependency>
<!--文件上传-->
<dependency>
<groupId>cd.casic.boot</groupId>
<artifactId>module-infra-biz</artifactId>
<version>${revision}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,39 +0,0 @@
package cd.casic.module.machine.configuration;
import cd.casic.module.machine.exception.ServiceException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//@Configuration
@Getter
public class AliYunConfig {
private static final Logger logger = LoggerFactory.getLogger(AliYunConfig.class);
@Value("${aliyun.oss.endpoint}")
private String endpoint;
@Value("${aliyun.oss.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.oss.accessKeySecret}")
private String accessKeySecret;
@Value("${aliyun.oss.bucketName}")
private String bucketName;
// @Bean
public OSS ossClient() {
logger.info("OSS域名: {}", endpoint);
logger.info("AccessKeyId: {}", accessKeyId);
// 添加参数校验
if (endpoint == null || accessKeyId == null || accessKeySecret == null) {
throw new ServiceException(ServiceException.OSS_PARAM_NULL,"OSS参数为空");
}
return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
}
}

View File

@ -0,0 +1,33 @@
package cd.casic.module.machine.configuration;
import cd.casic.module.infra.framework.file.core.client.s3.S3FileClientConfig;
import cd.casic.module.machine.utils.AliYunOssClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AliYunOssConfig extends S3FileClientConfig{
@Value("${aliyun.oss.endpoint}")
private String endpoint;
@Value("${aliyun.oss.accessKeyId}")
private String accessKey;
@Value("${aliyun.oss.accessKeySecret}")
private String accessSecret;
@Value("${aliyun.oss.bucketName}")
private String bucket;
// 定义 S3 客户端 Bean
@Bean
public AliYunOssClient aliYunClient() {
// 创建配置对象
S3FileClientConfig config = new AliYunOssConfig();
config.setEndpoint(endpoint);
config.setAccessKey(accessKey);
config.setAccessSecret(accessSecret);
config.setBucket(bucket);
AliYunOssClient aliYunOssClient = new AliYunOssClient(1L, config);
// 创建并返回客户端实例
aliYunOssClient.init();
return aliYunOssClient;
}
}

View File

@ -8,15 +8,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
@ -30,31 +22,27 @@ public class SecretKeyController {
@Resource @Resource
private SecretKeyService secretKeyService; private SecretKeyService secretKeyService;
@PostMapping(value = "/add", consumes = "multipart/form-data") @PostMapping(value = "/add")
@Operation(summary ="新增密钥") @Operation(summary ="新增密钥")
public CommonResult<Boolean> add(@RequestBody SecretKeyDto secretKeyDto, @RequestPart("file") MultipartFile file) { public CommonResult<Boolean> add(@RequestBody SecretKeyDto secretKeyDto) throws Exception {
return success(secretKeyService.addSecretKey(secretKeyDto, file)); return success(secretKeyService.addSecretKey(secretKeyDto));
} }
@PutMapping("/bindingMachine") @PutMapping("/bindingMachine")
@Operation(summary ="绑定机器") @Operation(summary ="绑定机器")
public CommonResult<Boolean> bindingMachine(@RequestParam("secretKeyId") Long secretKeyId, @RequestParam("machineInfoIds") List<Long> machineInfoIds) { public CommonResult<Boolean> bindingMachine(@RequestParam("secretKeyId") Long secretKeyId, @RequestParam("machineIds") List<Long> machineIds) {
secretKeyService.bindingMachine(secretKeyId, machineInfoIds); secretKeyService.bindingMachine(secretKeyId, machineIds);
return success(true); return success(true);
} }
@PutMapping("/update") @PutMapping("/update")
@Operation(summary ="编辑密钥信息") @Operation(summary ="编辑密钥信息")
public CommonResult<Boolean> update(@RequestBody SecretKeyDto secretKeyDto, @RequestPart(value = "file", required = false) MultipartFile file) { public CommonResult<Boolean> update(@RequestBody SecretKeyDto secretKeyDto) {
return success(secretKeyService.updateSecretKey(secretKeyDto, file)); return success(secretKeyService.updateSecretKey(secretKeyDto));
} }
@DeleteMapping("/delete")
@Operation(summary ="删除密钥")
public CommonResult<Boolean> delete(@RequestParam("secretKeyId") Long secretKeyId) {
return success(secretKeyService.deleteSecretKey(secretKeyId));
}
@DeleteMapping("/deleteList") @DeleteMapping("/deleteList")
@Operation(summary ="批量删除密钥") @Operation(summary ="批量删除密钥")
@ -68,9 +56,5 @@ public class SecretKeyController {
return success(secretKeyService.listSecretKey(secretKeyDto)); return success(secretKeyService.listSecretKey(secretKeyDto));
} }
@GetMapping("/downloadSecretKeyFile")
@Operation(summary ="下载密钥文件")
public CommonResult<InputStreamResource> downloadSecretKeyFile(@RequestParam("secretKeyId") Long secretKeyId) {
return success(secretKeyService.downloadSecretKeyFile(secretKeyId).getBody());
}
} }

View File

@ -7,6 +7,7 @@ import lombok.NoArgsConstructor;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.util.Date; import java.util.Date;
import java.util.List;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Data @Data
@ -19,12 +20,9 @@ public class SecretKeyDto extends PageDto {
private String description; private String description;
//存储路径 //存储路径,本地上传文件路径
private String path; private String path;
//密钥文件
private MultipartFile file;
private String fileName; private String fileName;
//密钥密码 //密钥密码

View File

@ -19,7 +19,7 @@ public class SecretKey extends BaseEntity{
@TableField(value = "description") @TableField(value = "description")
private String description; private String description;
//存储路径 //oss存储路径
@TableField(value = "path") @TableField(value = "path")
private String path; private String path;

View File

@ -1,5 +1,6 @@
package cd.casic.module.machine.exception; package cd.casic.module.machine.exception;
import cd.casic.module.machine.entity.SecretKey;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -37,6 +38,8 @@ public class ServiceException extends RuntimeException {
public static final int MACHINE_ENV_KEY_ILLEGAL = 565; public static final int MACHINE_ENV_KEY_ILLEGAL = 565;
//oss参数无法读取 //oss参数无法读取
public static final int OSS_PARAM_NULL = 1001; public static final int OSS_PARAM_NULL = 1001;
//密钥为空
public static final int SECRETKEY_NULL = 1002;
/** /**
* 业务错误码 * 业务错误码

View File

@ -1,8 +1,8 @@
package cd.casic.module.machine.handler; package cd.casic.module.machine.handler;
import cd.casic.module.machine.utils.AliYunOssClient;
import cd.casic.module.machine.entity.MachineInfo; import cd.casic.module.machine.entity.MachineInfo;
import cd.casic.module.machine.utils.AliOssUtil;
import cd.casic.module.machine.entity.SecretKey; import cd.casic.module.machine.entity.SecretKey;
import cd.casic.module.machine.enums.AuthenticationType; import cd.casic.module.machine.enums.AuthenticationType;
import cd.casic.module.machine.enums.ConnectionStatus; import cd.casic.module.machine.enums.ConnectionStatus;
@ -28,7 +28,7 @@ public class ConnectionSession implements AutoCloseable {
SecretKeyService secretKeyService; SecretKeyService secretKeyService;
@Resource @Resource
AliOssUtil aliOssUtil; AliYunOssClient aliYunOssClient;
private final MachineInfo machineInfo; private final MachineInfo machineInfo;
private Session sshSession; private Session sshSession;
@ -602,7 +602,16 @@ public class ConnectionSession implements AutoCloseable {
return null; return null;
} }
SecretKey secretKey = secretKeyService.getById(secretKeyId); SecretKey secretKey = secretKeyService.getById(secretKeyId);
InputStream read = aliOssUtil.read(secretKey.getFileName()); byte[] content;
try {
content = aliYunOssClient.getContent(secretKey.getPath().substring(secretKey.getPath().lastIndexOf("/") + 1));
} catch (Exception e) {
throw new RuntimeException(e);
}
//改为S3FileClient读取
InputStream read = new ByteArrayInputStream(content);
try { try {
return StreamUtils.copyToString(read, StandardCharsets.UTF_8); return StreamUtils.copyToString(read, StandardCharsets.UTF_8);
} catch (IOException e) { } catch (IOException e) {

View File

@ -11,17 +11,16 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
public interface SecretKeyService extends IService<SecretKey> { public interface SecretKeyService extends IService<SecretKey> {
boolean addSecretKey(SecretKeyDto secretKeyDto, MultipartFile file); boolean addSecretKey(SecretKeyDto secretKeyDto) throws Exception;
void bindingMachine(Long secretKeyId, List<Long> machineInfoIds); void bindingMachine(Long secretKeyId, List<Long> machineInfoIds);
boolean updateSecretKey(SecretKeyDto secretKeyDto,MultipartFile file); boolean updateSecretKey(SecretKeyDto secretKeyDto);
boolean deleteSecretKey(Long secretKeyId);
PageResult<SecretKey> listSecretKey(SecretKeyDto secretKeyDto); PageResult<SecretKey> listSecretKey(SecretKeyDto secretKeyDto);
ResponseEntity<InputStreamResource> downloadSecretKeyFile(Long secretKeyId);
boolean deleteList(List<Long> secretKeyIds); boolean deleteList(List<Long> secretKeyIds);
} }

View File

@ -4,90 +4,96 @@ import cd.casic.module.machine.dto.SecretKeyDto;
import cd.casic.module.machine.entity.MachineInfo; import cd.casic.module.machine.entity.MachineInfo;
import cd.casic.module.machine.entity.SecretKey; import cd.casic.module.machine.entity.SecretKey;
import cd.casic.module.machine.mapper.SecretServiceMapper; import cd.casic.module.machine.mapper.SecretServiceMapper;
import cd.casic.module.machine.utils.AliOssUtil; import cd.casic.module.machine.service.MachineInfoService;
import cd.casic.module.machine.utils.PageResult; import cd.casic.module.machine.utils.PageResult;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cd.casic.module.machine.configuration.AliYunConfig; import cd.casic.module.machine.utils.AliYunOssClient;
import cd.casic.module.machine.exception.ServiceException; import cd.casic.module.machine.exception.ServiceException;
import cd.casic.module.machine.service.MachineInfoService; //import cd.casic.module.machine.service.MachineInfoService;
import cd.casic.module.machine.service.SecretKeyService; import cd.casic.module.machine.service.SecretKeyService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Service @Service
public class SecretKeyServiceImpl extends ServiceImpl<SecretServiceMapper, SecretKey> implements SecretKeyService { public class SecretKeyServiceImpl extends ServiceImpl<SecretServiceMapper, SecretKey> implements SecretKeyService {
@Resource
private AliOssUtil aliOssUtil;
@Resource @Resource
private MachineInfoService machineInfoService; private MachineInfoService machineInfoService;
// @Resource @Resource
private AliYunConfig aliYunConfig; private AliYunOssClient aliYunOssClient;
@Resource @Resource
private SecretServiceMapper secretServiceMapper; private SecretServiceMapper secretServiceMapper;
//todo public方便测试后面改为private
public static final ExecutorService FILE_DELETE_EXECUTOR = Executors.newFixedThreadPool(10);
Logger logger = LoggerFactory.getLogger(SecretKeyServiceImpl.class);
@Override @Override
public boolean addSecretKey(SecretKeyDto secretKeyDto, MultipartFile file) { public boolean addSecretKey(SecretKeyDto secretKeyDto){
secretKeyDto.setFile(file); if (secretKeyDto.getPath()==null)
String fileName = aliOssUtil.save(file); {
String path = "https://" + aliYunConfig.getBucketName() + "." + aliYunConfig.getEndpoint() + "/" + fileName; throw new ServiceException(ServiceException.MACHINE_PROXY_NULL,"密钥不能为空");
secretKeyDto.setPath(path);
secretKeyDto.setFileName(fileName);
SecretKey secretKey = new SecretKey();
BeanUtils.copyProperties(secretKeyDto,secretKey);
return this.save(secretKey);
}
@Override
public void bindingMachine(Long secretKeyId, List<Long> machineInfoIds) {
List<MachineInfo> machineInfos = machineInfoService.listByIds(machineInfoIds);
machineInfos.forEach(machineInfo -> machineInfo.setSecretKeyId(secretKeyId));
machineInfoService.updateBatchById(machineInfos);
}
@Override
public boolean updateSecretKey(SecretKeyDto secretKeyDto, MultipartFile file) {
if (file != null){
secretKeyDto.setFile(file);
String fileName = aliOssUtil.save(file);
String path = "https://" + aliYunConfig.getBucketName() + "." + aliYunConfig.getEndpoint() + "/" + fileName;
secretKeyDto.setPath(path);
secretKeyDto.setFileName(fileName);
} }
String ossPath = upLoadSecretKey(secretKeyDto.getPath());
if (ossPath == null){
throw new ServiceException(ServiceException.MACHINE_PROXY_NULL,"密钥上传失败");
}
secretKeyDto.setPath(ossPath);
SecretKey secretKey = new SecretKey(); SecretKey secretKey = new SecretKey();
BeanUtils.copyProperties(secretKeyDto,secretKey); BeanUtils.copyProperties(secretKeyDto,secretKey);
//todo检查密钥合法
return this.save(secretKey);
}
@Override
public boolean updateSecretKey(SecretKeyDto secretKeyDto) {
Long id = secretKeyDto.getId();
SecretKey secretKey = this.getById(id);
if (secretKey == null){
throw new ServiceException(ServiceException.MACHINE_PROXY_NULL,"密钥不存在");
}
if (!secretKey.getPath().equals(secretKeyDto.getPath())) {
//todo检查密钥合法
String ossPath = upLoadSecretKey(secretKeyDto.getPath());
BeanUtils.copyProperties(secretKeyDto,secretKey);
secretKey.setPath(ossPath);
}
else {
BeanUtils.copyProperties(secretKeyDto,secretKey);
}
return this.updateById(secretKey); return this.updateById(secretKey);
} }
@Override @Override
public boolean deleteSecretKey(Long secretKeyId) { public void bindingMachine(Long secretKeyId, List<Long> machineIds) {
String fileName = this.getById(secretKeyId).getFileName(); SecretKey secretKey = this.getById(secretKeyId);
aliOssUtil.deleteFile(fileName); if (secretKey==null){
return this.removeById(secretKeyId); throw new ServiceException(ServiceException.SECRETKEY_NULL,"密钥不存在");
}
List<MachineInfo> machineList = machineInfoService.listByIds(machineIds);
machineList.forEach(machine -> machine.setSecretKeyId(secretKeyId));
machineInfoService.updateBatchById(machineList);
} }
@Override @Override
public PageResult<SecretKey> listSecretKey(SecretKeyDto secretKeyDto) { public PageResult<SecretKey> listSecretKey(SecretKeyDto secretKeyDto) {
QueryWrapper<SecretKey> queryWrapper = new QueryWrapper<>(); QueryWrapper<SecretKey> queryWrapper = new QueryWrapper<>();
@ -107,28 +113,48 @@ public class SecretKeyServiceImpl extends ServiceImpl<SecretServiceMapper, Secre
); );
} }
@Override
public ResponseEntity<InputStreamResource> downloadSecretKeyFile(Long secretKeyId) {
String fileName = this.getById(secretKeyId).getFileName();
return aliOssUtil.downloadFile(fileName);
}
@Override @Override
public boolean deleteList(List<Long> secretKeyIds) { public boolean deleteList(List<Long> secretKeyIds) {
List<SecretKey> secretKeys = this.listByIds(secretKeyIds); List<SecretKey> secretKeys = this.listByIds(secretKeyIds);
// 提交异步任务到线程池
FILE_DELETE_EXECUTOR.execute(() -> { for (SecretKey secretKey : secretKeys) {
try { if (secretKey.getPath() != null && !secretKey.getPath().isEmpty()){
for (SecretKey secretKey : secretKeys) { try {
if (secretKey.getFileName() != null && !secretKey.getFileName().isEmpty()){ //文件名
aliOssUtil.deleteFile(secretKey.getFileName()); //删除子目录文件需要在前面加上根目录文件路径
} String fileName = secretKey.getPath().substring(secretKey.getPath().lastIndexOf("/") + 1);
aliYunOssClient.delete(fileName);
} catch (Exception e) {
throw new RuntimeException(e);
} }
} catch (Exception e) {
logger.error("异步删除文件失败:{}", e.getMessage());
throw new ServiceException(ServiceException.DELETE_FILE_FAIL,"异步删除文件失败:"+e.getMessage());
} }
}); }
//todo是否删除已经绑定的机器
return secretServiceMapper.deleteBatchIds(secretKeyIds) > 0 ; return secretServiceMapper.deleteBatchIds(secretKeyIds) > 0 ;
} }
public String upLoadSecretKey(String localPath) {
//使用S3FileClient上传文件
aliYunOssClient.init();
//传输到指定文件需要在path前面加上文件路径
String path = IdUtil.fastSimpleUUID() + ".txt";
//上传文件是从本地上传这里传的是本地文件地址
byte[] content = ResourceUtil.readBytes(localPath);
String ossPath;
try {
ossPath = aliYunOssClient.upload(content, path, "txt");
}catch (Exception e) {
throw new RuntimeException(e+"上传文件失败");
}
return ossPath;
}
} }

View File

@ -1,113 +0,0 @@
package cd.casic.module.machine.utils;
import cd.casic.module.machine.configuration.AliYunConfig;
import cd.casic.module.machine.exception.ServiceException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.OSSObject;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@Component
public class AliOssUtil{
// @Autowired
private OSS ossClient;
// @Resource
private AliYunConfig aliyunConfig;
private static final Logger logger = LoggerFactory.getLogger(AliOssUtil.class);
public String save(MultipartFile file) {
try {
String fileName = generateUniqueFileName(file.getName());
ossClient.putObject(
// 存储桶名称
aliyunConfig.getBucketName(),
//对象键Object Key即文件在 OSS 中的完整路径和名称
fileName,
//文件内容的输入流用于读取待上传的文件数据
file.getInputStream(),
//文件的元数据信息如内容类型Content-Type缓存策略文件大小等
null
);
return fileName;
} catch (Exception e) {
logger.info("文件上传失败:{}", e.getMessage());
throw new ServiceException(ServiceException.UPLOADING_FILE_FAIL, "上传文件失败:" + e.getMessage());
}
}
public ResponseEntity<InputStreamResource> downloadFile(String fileName) {
try {
// 读取文件流
InputStream inputStream = read(fileName);
// 处理文件名编码防止中文乱码
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8)
.replaceAll("\\+", "%20");
// 设置响应头
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + encodedFileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setCacheControl("no-cache, no-store, must-revalidate");
return ResponseEntity.ok()
.headers(headers)
.body(new InputStreamResource(inputStream));
} catch (Exception e) {
logger.error("下载失败:{}", e.getMessage());
throw new ServiceException(ServiceException.DOWNLOAD_FILE_FAIL, "下载失败: " + e.getMessage());
}
}
public void deleteFile(String fileName) {
try {
if (fileName == null || fileName.isEmpty()) {
throw new ServiceException(ServiceException.FILENAME_NULL, "文件名不能为空");
}
// 调用 OSS 客户端删除文件
ossClient.deleteObject(aliyunConfig.getBucketName(), fileName);
logger.info("文件删除成功: {}", fileName);
} catch (Exception e) {
logger.error("删除文件失败: {}", e.getMessage());
throw new ServiceException(ServiceException.DELETE_FILE_FAIL, "删除文件失败: " + e.getMessage());
}
}
public InputStream read(String fileName) {
try {
if (fileName == null || fileName.isEmpty()) {
throw new ServiceException(ServiceException.FILENAME_NULL, "文件名不能为空");
}
OSSObject ossObject = ossClient.getObject(aliyunConfig.getBucketName(), fileName);
return ossObject.getObjectContent();
} catch (Exception e) {
logger.error("读取文件失败:{}", e.getMessage());
throw new ServiceException(ServiceException.READ_FILE_FAIL, "读取文件失败: " + e.getMessage());
}
}
// 生成带时间戳的唯一文件名
private String generateUniqueFileName(String originalFileName) {
String timestamp = String.valueOf(System.currentTimeMillis());
String ext = originalFileName.substring(originalFileName.lastIndexOf("."));
return timestamp + ext;
}
}

View File

@ -0,0 +1,12 @@
package cd.casic.module.machine.utils;
import cd.casic.module.infra.framework.file.core.client.s3.S3FileClient;
import cd.casic.module.infra.framework.file.core.client.s3.S3FileClientConfig;
public class AliYunOssClient extends S3FileClient{
public AliYunOssClient(Long id, S3FileClientConfig config) {
super(id, config);
}
}