diff --git a/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/TargetController.java b/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/TargetController.java index b2594c99..bc63b8e2 100644 --- a/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/TargetController.java +++ b/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/TargetController.java @@ -1,25 +1,21 @@ package cd.casic.ci.api; -import cd.casic.ci.process.dal.req.target.TargetManagerCreateReq; -import cd.casic.ci.process.dal.req.target.TargetManagerUpdateReq; -import cd.casic.ci.process.dal.req.target.TargetQueryReq; -import cd.casic.ci.process.dal.req.target.TargetUploadReq; +import cd.casic.ci.process.dal.req.target.*; import cd.casic.ci.process.dal.resp.target.TargetManagerResp; import cd.casic.ci.process.process.dataObject.base.BaseIdReq; import cd.casic.ci.process.process.dataObject.target.TargetVersion; import cd.casic.ci.process.process.service.target.TargetManagerService; import cd.casic.ci.process.process.service.target.TargetVersionService; +import cd.casic.ci.process.util.SftpUploadUtil; import cd.casic.framework.commons.pojo.CommonResult; import cd.casic.framework.commons.pojo.PageResult; import jakarta.annotation.Resource; import jakarta.annotation.security.PermitAll; import jakarta.validation.Valid; import org.jetbrains.annotations.NotNull; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -50,6 +46,15 @@ public class TargetController { } + @PostMapping(value = "/createVersion") + @PermitAll + public CommonResult createVersion(@RequestBody @Valid TargetVersionCreateReq req) { + + targetManagerService.createVersion(req); + return CommonResult.success(); + } + + @PostMapping(value = "/updateTarget") @PermitAll public CommonResult updateTarget(@RequestBody @Valid TargetManagerUpdateReq req) { @@ -68,6 +73,15 @@ public class TargetController { } + @PostMapping(value = "/deleteVersion") + @PermitAll + public CommonResult deleteVersion(@RequestBody @Valid BaseIdReq req) { + + targetManagerService.deleteVersion(req); + return CommonResult.success(); + } + + @PostMapping(path="/findTargetPage") @PermitAll public CommonResult> findTargetPage(@RequestBody @NotNull @Valid TargetQueryReq query){ @@ -99,8 +113,10 @@ public class TargetController { @PostMapping(path="/fileUpload") - public CommonResult fileUpload(@RequestBody @Valid TargetUploadReq req){ + public CommonResult fileUpload(@RequestParam("file") MultipartFile file) throws SftpUploadUtil.SftpUploadException { + TargetUploadReq req = new TargetUploadReq(); + req.setFile(file); String filePath = targetManagerService.fileUpload(req); return CommonResult.success(filePath); diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetManagerCreateReq.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetManagerCreateReq.java index 80e17a25..423700d0 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetManagerCreateReq.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetManagerCreateReq.java @@ -16,11 +16,6 @@ public class TargetManagerCreateReq { */ private String targetName; - /** - * 目标图标 - */ - private String targetIcon; - /** * 组织ID */ diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetManagerUpdateReq.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetManagerUpdateReq.java index b67a3531..bbd6fbd3 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetManagerUpdateReq.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetManagerUpdateReq.java @@ -21,11 +21,6 @@ public class TargetManagerUpdateReq { */ private String targetName; - /** - * 目标图标 - */ - private String targetIcon; - /** * 组织ID */ diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetQueryReq.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetQueryReq.java index 73560e2e..1e3d7733 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetQueryReq.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetQueryReq.java @@ -29,6 +29,11 @@ public class TargetQueryReq extends PageParam { @TableField("target_name") private String targetName; + /** + * 目标类型 + */ + private String targetType; + /** * 创建人用户id */ diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetUploadReq.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetUploadReq.java index ee33e1f7..76fd082b 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetUploadReq.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetUploadReq.java @@ -1,8 +1,7 @@ package cd.casic.ci.process.dal.req.target; import lombok.Data; - -import java.io.File; +import org.springframework.web.multipart.MultipartFile; /** * @ClassName PipelineQueryReq @@ -13,11 +12,27 @@ import java.io.File; @Data public class TargetUploadReq{ - private File file; + //远程服务器IP或主机名 + private String remoteHost = "175.6.27.252"; - //文件上传远程路径 - private String remoteFilePath; + //远程服务器端口 (通常是 22),为 null 或 <= 0 时使用默认端口 22 + private Integer remotePort = 22; - //文件类型 - private String fileType; + //远程服务器用户名 + private String username = "roots"; + + //远程服务器密码 (如果使用密码认证) + private String password = "hnidc0327cn!@#xhh"; + + //SSH Key 文件路径 (如果使用密钥认证,password 参数可以为 null) + private String sshKeyPath; + + //文件输入流 + private MultipartFile file; + + //远程服务器存放文件的目录 (例如: /home/user/uploads/) + private String remoteDir = "/home/ops/ops-pro/file/"; + + //上传到远程服务器的文件名 (为 null 或空字符串时使用本地文件名) + private String remoteFileName; } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetVersionCreateReq.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetVersionCreateReq.java new file mode 100644 index 00000000..75722d96 --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/req/target/TargetVersionCreateReq.java @@ -0,0 +1,54 @@ +package cd.casic.ci.process.dal.req.target; + +import lombok.Data; + +/** + * @author HopeLi + * @version v1.0 + * @ClassName TargetManagerReq + * @Date: 2025/5/17 15:36 + * @Description: + */ +@Data +public class TargetVersionCreateReq { + + /** + * 目标ID + */ + private String targetId; + + /** + * 目标类型 + */ + private String targetType; + + /** + * 版本号 + */ + private String version; + + /** + * 描述 + */ + private String targetDesc; + + /** + * 文件大小(单位:字节) + */ + private Double fileSize; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件类型(例如 zip、tar.gz 等) + */ + private String fileType; + + /** + * 文件地址路径 + */ + private String filePath; +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/resp/target/TargetManagerResp.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/resp/target/TargetManagerResp.java index 9db50746..d4499a57 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/resp/target/TargetManagerResp.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dal/resp/target/TargetManagerResp.java @@ -21,9 +21,9 @@ public class TargetManagerResp{ private String targetName; /** - * 目标图标 + * 目标类型 */ - private String targetIcon; + private String targetType; /** * 组织ID diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/target/TargetManager.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/target/TargetManager.java index 57021d5d..81358cc7 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/target/TargetManager.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/target/TargetManager.java @@ -23,9 +23,9 @@ public class TargetManager extends PipBaseElement { private String targetName; /** - * 目标图标 + * 目标类型 */ - private String targetIcon; + private String targetType; /** * 组织ID diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/target/TargetVersion.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/target/TargetVersion.java index 533b7e65..fa0043bf 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/target/TargetVersion.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/target/TargetVersion.java @@ -22,11 +22,6 @@ public class TargetVersion extends PipBaseElement { */ private String targetId; - /** - * 目标类型 - */ - private String targetType; - /** * 版本号 */ diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/target/TargetManagerService.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/target/TargetManagerService.java index 983403f7..2f6ba133 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/target/TargetManagerService.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/target/TargetManagerService.java @@ -1,13 +1,11 @@ package cd.casic.ci.process.process.service.target; -import cd.casic.ci.process.dal.req.target.TargetManagerCreateReq; -import cd.casic.ci.process.dal.req.target.TargetManagerUpdateReq; -import cd.casic.ci.process.dal.req.target.TargetQueryReq; -import cd.casic.ci.process.dal.req.target.TargetUploadReq; +import cd.casic.ci.process.dal.req.target.*; import cd.casic.ci.process.dal.resp.target.TargetManagerResp; import cd.casic.ci.process.process.dataObject.base.BaseIdReq; import cd.casic.ci.process.process.dataObject.target.TargetManager; +import cd.casic.ci.process.util.SftpUploadUtil; import cd.casic.framework.commons.pojo.PageResult; import com.baomidou.mybatisplus.extension.service.IService; import jakarta.validation.Valid; @@ -32,5 +30,9 @@ public interface TargetManagerService extends IService { List findTargetList(@Valid TargetQueryReq query); - String fileUpload(@Valid TargetUploadReq req); + String fileUpload(TargetUploadReq req) throws SftpUploadUtil.SftpUploadException; + + void createVersion(@Valid TargetVersionCreateReq req); + + void deleteVersion(@Valid BaseIdReq req); } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/target/impl/TargetManagerServiceImpl.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/target/impl/TargetManagerServiceImpl.java index 4b1b7ba3..b0255853 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/target/impl/TargetManagerServiceImpl.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/target/impl/TargetManagerServiceImpl.java @@ -1,10 +1,7 @@ package cd.casic.ci.process.process.service.target.impl; -import cd.casic.ci.process.dal.req.target.TargetManagerCreateReq; -import cd.casic.ci.process.dal.req.target.TargetManagerUpdateReq; -import cd.casic.ci.process.dal.req.target.TargetQueryReq; -import cd.casic.ci.process.dal.req.target.TargetUploadReq; +import cd.casic.ci.process.dal.req.target.*; import cd.casic.ci.process.dal.resp.target.TargetManagerResp; import cd.casic.ci.process.process.converter.TargetConverter; import cd.casic.ci.process.process.dal.pipeline.TargetManagerDao; @@ -13,16 +10,14 @@ import cd.casic.ci.process.process.dataObject.base.BaseIdReq; import cd.casic.ci.process.process.dataObject.target.TargetManager; import cd.casic.ci.process.process.dataObject.target.TargetVersion; import cd.casic.ci.process.process.service.target.TargetManagerService; +import cd.casic.ci.process.util.SftpUploadUtil; import cd.casic.framework.commons.exception.ServiceException; import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants; import cd.casic.framework.commons.pojo.PageResult; import cd.casic.framework.commons.util.object.BeanUtils; import cd.casic.framework.security.dal.user.AdminUserDO; import cd.casic.framework.tenant.core.service.AdminUserServiceImpl; -import cd.casic.module.infra.framework.file.core.client.ftp.FtpFileClient; -import cd.casic.module.infra.framework.file.core.client.ftp.FtpFileClientConfig; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.extra.ftp.FtpMode; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -32,13 +27,11 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; -import org.springframework.util.FileCopyUtils; import org.springframework.util.ObjectUtils; -import java.io.FileInputStream; -import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * @author HopeLi @@ -103,6 +96,7 @@ public class TargetManagerServiceImpl extends ServiceImpl 0) ? remotePort : DEFAULT_SFTP_PORT; + session = jsch.getSession(username, remoteHost, port); + System.out.println("尝试连接 SFTP 服务器: " + username + "@" + remoteHost + ":" + port); + + + // 如果使用密码认证且提供了密码 + if (password != null && !password.trim().isEmpty() && (sshKeyPath == null || sshKeyPath.trim().isEmpty())) { + session.setPassword(password); + System.out.println("使用密码认证."); + } + + // 设置连接不进行主机密钥检查 (生产环境不推荐,应该配置 known_hosts) + // 在实际应用中,应该引导用户信任主机密钥或提前将主机密钥加入 known_hosts + java.util.Properties config = new java.util.Properties(); + config.put("StrictHostKeyChecking", "no"); // !!! 生产环境请谨慎使用或配置正确的主机密钥检查 !!! + session.setConfig(config); + + // 3. 连接 Session + session.connect(); + System.out.println("SFTP Session 连接成功."); + + // 4. 打开 SFTP Channel + channel = session.openChannel("sftp"); + channel.connect(); + System.out.println("SFTP Channel 打开成功."); + + channelSftp = (ChannelSftp) channel; + + // 5. 检查并切换到远程目录 + try { + channelSftp.cd(remoteDir); + System.out.println("已切换到远程目录: " + remoteDir); + } catch (SftpException e) { + // 如果远程目录不存在,尝试创建 + System.err.println("远程目录不存在: " + remoteDir + ",尝试创建..."); + try { + // 尝试递归创建目录 (如果需要) + createRemoteDirRecursive(channelSftp, remoteDir); + channelSftp.cd(remoteDir); // 创建后再次切换 + System.out.println("远程目录创建成功并已切换: " + remoteDir); + } catch (SftpException e2) { + // 创建目录失败 + throw new SftpUploadException("远程目录创建失败: " + remoteDir, e2); + } + } + + // 6. 获取本地文件流 + fis = file.getInputStream(); + System.out.println("本地文件流获取成功: " + file); + + // 7. 确定远程文件名 + String finalRemoteFileName = (remoteFileName != null && !remoteFileName.trim().isEmpty()) ? + remoteFileName : file.getOriginalFilename(); + System.out.println("最终上传到远程的文件名为: " + finalRemoteFileName); + + // 8. 上传文件 + channelSftp.put(fis, finalRemoteFileName); + System.out.println("文件上传成功!"); + + } catch (JSchException e) { + throw new SftpUploadException("SFTP 连接或认证失败: " + e.getMessage(), e); + } catch (SftpException e) { + throw new SftpUploadException("SFTP 操作失败 (如切换目录或上传文件): " + e.getMessage(), e); + } catch (FileNotFoundException e) { + throw new SftpUploadException("本地文件未找到: " + e.getMessage(), e); + } catch (IOException e) { + throw new SftpUploadException("文件流读写异常: " + e.getMessage(), e); + } catch (SftpUploadException e) { + // 重新抛出自定义异常 + throw e; + } catch (Exception e) { + // 捕获其他未知异常 + throw new SftpUploadException("SFTP 上传过程中发生未知异常: " + e.getMessage(), e); + } finally { + // 9. 关闭资源 (确保在任何情况下都关闭) + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + System.err.println("关闭本地文件流失败: " + e.getMessage()); + e.printStackTrace(); // 打印堆栈以便调试 + } + } + if (channelSftp != null) { + channelSftp.disconnect(); + System.out.println("SFTP Channel 已断开."); + } + if (channel != null) { + channel.disconnect(); + System.out.println("SFTP Channel 资源已释放."); + } + if (session != null) { + session.disconnect(); + System.out.println("SFTP Session 已断开."); + } + } + } + /** * 辅助方法:递归创建远程目录 * @param channelSftp ChannelSftp 实例 diff --git a/ops-server/src/test/java/cd/casic/server/TargetTest.java b/ops-server/src/test/java/cd/casic/server/TargetTest.java index 1468ac8b..6215764a 100644 --- a/ops-server/src/test/java/cd/casic/server/TargetTest.java +++ b/ops-server/src/test/java/cd/casic/server/TargetTest.java @@ -2,7 +2,6 @@ package cd.casic.server; import cd.casic.ci.process.dal.req.target.TargetManagerCreateReq; import cd.casic.ci.process.dal.req.target.TargetManagerUpdateReq; -import cd.casic.ci.process.dal.req.target.TargetUploadReq; import cd.casic.ci.process.process.converter.TargetConverter; import cd.casic.ci.process.process.dal.pipeline.TargetManagerDao; import cd.casic.ci.process.process.dal.pipeline.TargetVersionDao; @@ -18,10 +17,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ActiveProfiles; -import java.io.File; -import java.io.IOException; - -import static org.hibernate.validator.internal.util.Contracts.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.times; @@ -81,12 +76,5 @@ public class TargetTest { verify(targetManagerDao, times(1)).deleteById("1"); verify(targetVersionDao, times(1)).deleteByIds(anyList()); } - @Test - void testFileUpload() throws IOException { - TargetUploadReq targetUploadReq = new TargetUploadReq(); - targetUploadReq.setFile(new File("D:\\test\\test.txt")); - String fileUrl = targetManagerService.fileUpload(targetUploadReq); - assertNotNull(fileUrl); - } }